|
@@ -182,6 +183,7 @@ pseudo-softcode plugin aimed at developers wanting to script their game from ins
Evennia 0.9.5 »
Soft Code
+ develop branch
@@ -175,6 +176,7 @@ weather came before it. Expanding it to be more realistic is a useful exercise.<
Tutorials »
Weather Tutorial
+ develop branch
@@ -166,6 +167,7 @@ properly search the inheritance tree.
Tutorials »
Zones
+ develop branch
@@ -432,8 +433,12 @@
BASE_GUEST_TYPECLASS = class_from_module(settings.BASE_GUEST_TYPECLASS)
del class_from_module
- # delayed starts
+ # delayed starts - important so as to not back-access evennia before it has
+ # finished initializing
GLOBAL_SCRIPTS.start()
+ from .prototypes import prototypes
+ prototypes.load_module_prototypes()
+ del prototypes
@@ -93,10 +94,10 @@
# Create throttles for too many account-creations and login attempts
CREATION_THROTTLE = Throttle(
- limit=settings.CREATION_THROTTLE_LIMIT, timeout=settings.CREATION_THROTTLE_TIMEOUT
+ name='creation', limit=settings.CREATION_THROTTLE_LIMIT, timeout=settings.CREATION_THROTTLE_TIMEOUT
)
LOGIN_THROTTLE = Throttle(
- limit=settings.LOGIN_THROTTLE_LIMIT, timeout=settings.LOGIN_THROTTLE_TIMEOUT
+ name='login', limit=settings.LOGIN_THROTTLE_LIMIT, timeout=settings.LOGIN_THROTTLE_TIMEOUT
)
@@ -1761,6 +1762,7 @@
evennia »
evennia.accounts.accounts
+ develop branch
@@ -250,10 +251,15 @@
quality = [mat[4] for mat in matches]
matches = matches[-quality.count(quality[-1]) :]
- if len(matches) > 1 and match_index is not None and 0 < match_index <= len(matches):
+ if len(matches) > 1 and match_index is not None:
# We couldn't separate match by quality, but we have an
# index argument to tell us which match to use.
- matches = [matches[match_index - 1]]
+ if 0 < match_index <= len(matches):
+ matches = [matches[match_index - 1]]
+ else:
+ # we tried to give an index outside of the range - this means
+ # a no-match
+ matches = []
# no matter what we have at this point, we have to return it.
return matches
@@ -302,6 +308,7 @@
evennia »
evennia.commands.cmdparser
+ develop branch
@@ -555,15 +556,16 @@
# cmd is a command set so merge all commands in that set
# to this one. We raise a visible error if we created
# an infinite loop (adding cmdset to itself somehow)
+ cmdset = cmd
try:
- cmd = self._instantiate(cmd)
+ cmdset = self._instantiate(cmdset)
except RuntimeError:
- string = "Adding cmdset %(cmd)s to %(class)s lead to an "
- string += "infinite loop. When adding a cmdset to another, "
- string += "make sure they are not themself cyclically added to "
- string += "the new cmdset somewhere in the chain."
- raise RuntimeError(_(string) % {"cmd": cmd, "class": self.__class__})
- cmds = cmd.commands
+ err = ("Adding cmdset {cmdset} to {cls} lead to an "
+ "infinite loop. When adding a cmdset to another, "
+ "make sure they are not themself cyclically added to "
+ "the new cmdset somewhere in the chain.")
+ raise RuntimeError(_(err.format(cmdset=cmdset, cls=self.__class__)))
+ cmds = cmdset.commands
elif is_iter(cmd):
cmds = [self._instantiate(c) for c in cmd]
else:
@@ -572,7 +574,7 @@
system_commands = self.system_commands
for cmd in cmds:
# add all commands
- if not hasattr(cmd, "obj"):
+ if not hasattr(cmd, "obj") or cmd.obj is None:
cmd.obj = self.cmdsetobj
try:
ic = commands.index(cmd)
@@ -757,6 +759,7 @@
evennia »
evennia.commands.cmdset
+ develop branch
@@ -345,7 +346,7 @@
character_candidates = []
if not self.args:
- character_candidates = [account.db._last_puppet] or []
+ character_candidates = [account.db._last_puppet] if account.db._last_puppet else []
if not character_candidates:
self.msg("Usage: ic <character>")
return
@@ -1138,6 +1139,7 @@
evennia »
evennia.commands.default.account
+ develop branch
@@ -883,21 +884,30 @@
return
if service.name[:7] == "Evennia":
if delmode:
- caller.msg("You cannot remove a core Evennia service (named 'Evennia***').")
+ caller.msg("You cannot remove a core Evennia service (named 'Evennia*').")
return
- string = "You seem to be shutting down a core Evennia service (named 'Evennia***'). Note that"
- string += "stopping some TCP port services will *not* disconnect users *already*"
- string += "connected on those ports, but *may* instead cause spurious errors for them. To "
- string += "safely and permanently remove ports, change settings file and restart the server."
+ string = ("|RYou seem to be shutting down a core Evennia "
+ "service (named 'Evennia*').\nNote that stopping "
+ "some TCP port services will *not* disconnect users "
+ "*already* connected on those ports, but *may* "
+ "instead cause spurious errors for them.\nTo safely "
+ "and permanently remove ports, change settings file "
+ "and restart the server.|n\n")
caller.msg(string)
if delmode:
service.stopService()
service_collection.removeService(service)
- caller.msg("Stopped and removed service '%s'." % self.args)
+ caller.msg("|gStopped and removed service '%s'.|n" % self.args)
else:
- service.stopService()
- caller.msg("Stopped service '%s'." % self.args)
+ caller.msg(f"Stopping service '{self.args}'...")
+ try:
+ service.stopService()
+ except Exception as err:
+ caller.msg(f"|rErrors were reported when stopping this service{err}.\n"
+ "If there are remaining problems, try reloading "
+ "or rebooting the server.")
+ caller.msg("|g... Stopped service '%s'.|n" % self.args)
return
if switches[0] == "start":
@@ -905,8 +915,14 @@
if service.running:
caller.msg("That service is already running.")
return
- caller.msg("Starting service '%s'." % self.args)
- service.startService()
+ caller.msg(f"Starting service '{self.args}' ...")
+ try:
+ service.startService()
+ except Exception as err:
+ caller.msg(f"|rErrors were reported when starting this service{err}.\n"
+ "If there are remaining problems, try reloading the server, changing the "
+ "settings if it's a non-standard service.|n")
+ caller.msg("|gService started.|n")
@@ -430,7 +431,7 @@
(aka MUDs, MUSHes, MUX, MOOs...). It is open-source and |wfree to use|n, also for
commercial projects (BSD license).
- Out of the box, Evennia provides a |wfull, if empty game|n. Whereas you can play
+ Out of the box, Evennia provides a |wworking, if empty game|n. Whereas you can play
via traditional telnet MUD-clients, the server runs your game's website and
offers a |wHTML5 webclient|n so that people can play your game in their browser
without downloading anything extra.
@@ -866,6 +867,7 @@
evennia »
evennia.contrib.tutorial_world.intro_menu
+ develop branch
@@ -507,19 +508,25 @@
# strips the number
match_number, searchdata = match.group("number"), match.group("name")
match_number = int(match_number) - 1
- match_number = match_number if match_number >= 0 else None
if match_number is not None or not exact:
# run search again, with the exactness set by call
matches = _searcher(searchdata, candidates, typeclass, exact=exact)
# deal with result
- if len(matches) > 1 and match_number is not None:
+ if len(matches) == 1 and match_number is not None and match_number != 0:
+ # this indicates trying to get a single match with a match-number
+ # targeting some higher-number match (like 2-box when there is only
+ # one box in the room). This leads to a no-match.
+ matches = []
+ elif len(matches) > 1 and match_number is not None:
# multiple matches, but a number was given to separate them
- try:
+ if 0 <= match_number < len(matches):
+ # limit to one match
matches = [matches[match_number]]
- except IndexError:
- # match number not matching anything
- pass
+ else:
+ # a number was given outside of range. This means a no-match.
+ matches = []
+
# return a list (possibly empty)
return matches
@@ -677,6 +684,7 @@
evennia »
evennia.objects.manager
+ develop branch
@@ -435,7 +436,8 @@
a global search.
- `me,self`: self-reference to this object
- `<num>-<string>` - can be used to differentiate
- between multiple same-named matches
+ between multiple same-named matches. The exact form of this input
+ is given by `settings.SEARCH_MULTIMATCH_REGEX`.
global_search (bool): Search all objects globally. This overrules 'location' data.
use_nicks (bool): Use nickname-replace (nicktype "object") on `searchdata`.
typeclass (str or Typeclass, or list of either): Limit search only
@@ -2791,6 +2793,7 @@
evennia »
evennia.objects.objects
+ develop branch
@@ -185,35 +186,41 @@
# module-based prototypes
- for mod in settings.PROTOTYPE_MODULES:
- # to remove a default prototype, override it with an empty dict.
- # internally we store as (key, desc, locks, tags, prototype_dict)
- prots = []
- for variable_name, prot in all_from_module(mod).items():
- if isinstance(prot, dict):
- if "prototype_key" not in prot:
- prot["prototype_key"] = variable_name.lower()
- prots.append((prot["prototype_key"], homogenize_prototype(prot)))
- # assign module path to each prototype_key for easy reference
- _MODULE_PROTOTYPE_MODULES.update({prototype_key.lower(): mod for prototype_key, _ in prots})
- # make sure the prototype contains all meta info
- for prototype_key, prot in prots:
- actual_prot_key = prot.get("prototype_key", prototype_key).lower()
- prot.update(
- {
- "prototype_key": actual_prot_key,
- "prototype_desc": prot["prototype_desc"] if "prototype_desc" in prot else mod,
- "prototype_locks": (
- prot["prototype_locks"]
- if "prototype_locks" in prot
- else "use:all();edit:false()"
- ),
- "prototype_tags": list(
- set(list(make_iter(prot.get("prototype_tags", []))) + ["module"])
- ),
- }
- )
- _MODULE_PROTOTYPES[actual_prot_key] = prot
+ [docs]def load_module_prototypes():
+ """
+ This is called by `evennia.__init__` as Evennia initializes. It's important
+ to do this late so as to not interfere with evennia initialization.
+
+ """
+ for mod in settings.PROTOTYPE_MODULES:
+ # to remove a default prototype, override it with an empty dict.
+ # internally we store as (key, desc, locks, tags, prototype_dict)
+ prots = []
+ for variable_name, prot in all_from_module(mod).items():
+ if isinstance(prot, dict):
+ if "prototype_key" not in prot:
+ prot["prototype_key"] = variable_name.lower()
+ prots.append((prot["prototype_key"], homogenize_prototype(prot)))
+ # assign module path to each prototype_key for easy reference
+ _MODULE_PROTOTYPE_MODULES.update({prototype_key.lower(): mod for prototype_key, _ in prots})
+ # make sure the prototype contains all meta info
+ for prototype_key, prot in prots:
+ actual_prot_key = prot.get("prototype_key", prototype_key).lower()
+ prot.update(
+ {
+ "prototype_key": actual_prot_key,
+ "prototype_desc": prot["prototype_desc"] if "prototype_desc" in prot else mod,
+ "prototype_locks": (
+ prot["prototype_locks"]
+ if "prototype_locks" in prot
+ else "use:all();edit:false()"
+ ),
+ "prototype_tags": list(
+ set(list(make_iter(prot.get("prototype_tags", []))) + ["module"])
+ ),
+ }
+ )
+ _MODULE_PROTOTYPES[actual_prot_key] = prot
# Db-based prototypes
@@ -970,7 +977,10 @@
value = validator(value[0](*make_iter(args)))
else:
value = validator(value)
- return protfunc_parser(value)
+ result = protfunc_parser(value)
+ if result != value:
+ return validator(result)
+ return result
@@ -134,7 +135,7 @@
[docs] def at_update(self, obj, fieldname):
"""
- Called by the field as it saves.
+ Called by the field/attribute as it saves.
"""
to_delete = []
@@ -289,6 +290,7 @@
evennia »
evennia.scripts.monitorhandler
+ develop branch
@@ -121,9 +122,15 @@
_ERROR_ADD_TICKER = """TickerHandler: Tried to add an invalid ticker:
- {storekey}
+ {store_key}
Ticker was not added."""
+ _ERROR_ADD_TICKER_SUB_SECOND = """You are trying to add a ticker running faster
+ than once per second. This is not supported and also probably not useful:
+ Spamming messages to the user faster than once per second serves no purpose in
+ a text-game, and if you want to update some property, consider doing so
+ on-demand rather than using a ticker.
+ """
[docs]class Ticker(object):
"""
@@ -400,7 +407,8 @@
obj (Object, tuple or None): Subscribing object if any. If a tuple, this is
a packed_obj tuple from dbserialize.
path (str or None): Python-path to callable, if any.
- interval (int): Ticker interval.
+ interval (int): Ticker interval. Floats will be converted to
+ nearest lower integer value.
callfunc (callable or str): This is either the callable function or
the name of the method to call. Note that the callable is never
stored in the key; that is uniquely identified with the python-path.
@@ -419,6 +427,9 @@
`idstring` and `persistent` are integers, strings and bools respectively.
"""
+ if interval < 1:
+ raise RuntimeError(_ERROR_ADD_TICKER_SUB_SECOND)
+
interval = int(interval)
persistent = bool(persistent)
packed_obj = pack_dbobj(obj)
@@ -717,6 +728,7 @@
evennia »
evennia.scripts.tickerhandler
+ develop branch
@@ -562,9 +563,8 @@
session=session,
)
else:
- # kwargs provided: persist them to the account object
- for key, value in kwargs.items():
- clientoptions[key] = value
+ # kwargs provided: persist them to the account object.
+ clientoptions.update(kwargs)
# OOB protocol-specific aliases and wrappers
@@ -702,6 +702,7 @@
evennia »
evennia.server.inputfuncs
+ develop branch
@@ -87,6 +88,14 @@
AMP_MAXLEN = amp.MAX_VALUE_LENGTH # max allowed data length in AMP protocol (cannot be changed)
+# amp internal
+ASK = b'_ask'
+ANSWER = b'_answer'
+ERROR = b'_error'
+ERROR_CODE = b'_error_code'
+ERROR_DESCRIPTION = b'_error_description'
+UNKNOWN_ERROR_CODE = b'UNKNOWN'
+
# buffers
_SENDBATCH = defaultdict(list)
_MSGBUFFER = defaultdict(list)
@@ -342,6 +351,47 @@
# later twisted amp has its own __init__
super(AMPMultiConnectionProtocol, self).__init__(*args, **kwargs)
+ def _commandReceived(self, box):
+ """
+ This overrides the default Twisted AMP error handling which is not
+ passing enough of the traceback through to the other side. Instead we
+ add a specific log of the problem on the erroring side.
+
+ """
+ def formatAnswer(answerBox):
+ answerBox[ANSWER] = box[ASK]
+ return answerBox
+
+ def formatError(error):
+ if error.check(amp.RemoteAmpError):
+ code = error.value.errorCode
+ desc = error.value.description
+
+ # Evennia extra logging
+ desc += " (error logged on other side)"
+ _get_logger().log_err(f"AMP caught exception ({desc}):\n{error.value}")
+
+ if isinstance(desc, str):
+ desc = desc.encode("utf-8", "replace")
+ if error.value.fatal:
+ errorBox = amp.QuitBox()
+ else:
+ errorBox = amp.AmpBox()
+ else:
+ errorBox = amp.QuitBox()
+ _get_logger().log_err(error) # server-side logging if unhandled error
+ code = UNKNOWN_ERROR_CODE
+ desc = b"Unknown Error"
+ errorBox[ERROR] = box[ASK]
+ errorBox[ERROR_DESCRIPTION] = desc
+ errorBox[ERROR_CODE] = code
+ return errorBox
+ deferred = self.dispatchCommand(box)
+ if ASK in box:
+ deferred.addCallbacks(formatAnswer, formatError)
+ deferred.addCallback(self._safeEmit)
+ deferred.addErrback(self.unhandledError)
+
[docs] def dataReceived(self, data):
"""
Handle non-AMP messages, such as HTTP communication.
@@ -426,7 +476,7 @@
"""
e.trap(Exception)
_get_logger().log_err(
- "AMP Error for {info}: {trcbck} {err}".format(
+ "AMP Error from {info}: {trcbck} {err}".format(
info=info, trcbck=e.getTraceback(), err=e.getErrorMessage()
)
)
@@ -575,6 +625,7 @@
evennia »
evennia.server.portal.amp
+ develop branch
@@ -128,7 +129,6 @@
super().dataReceived(data)
except ValueError as err:
from evennia.utils import logger
-
logger.log_err(f"Malformed telnet input: {err}")
@@ -158,6 +159,10 @@
self.sessid = old_session.sessid
self.sessionhandler.disconnect(old_session)
+ self.protocol_flags["CLIENTNAME"] = "Evennia Webclient (websocket)"
+ self.protocol_flags["UTF-8"] = True
+ self.protocol_flags["OOB"] = True
+
# watch for dead links
self.transport.setTcpKeepAlive(1)
# actually do the connection
@@ -387,6 +392,7 @@
evennia »
evennia.server.portal.webclient
+ develop branch
@@ -39,7 +40,8 @@
Source code for evennia.server.throttle
-from collections import defaultdict, deque
+from django.core.cache import caches
+from collections import deque
from evennia.utils import logger
import time
@@ -53,8 +55,8 @@
This version of the throttle is usable by both the terminal server as well
as the web server, imposes limits on memory consumption by using deques
- with length limits instead of open-ended lists, and removes sparse keys when
- no recent failures have been recorded.
+ with length limits instead of open-ended lists, and uses native Django
+ caches for automatic key eviction and persistence configurability.
"""
error_msg = "Too many failed attempts; you must wait a few minutes before trying again."
@@ -64,6 +66,7 @@
Allows setting of throttle parameters.
Keyword Args:
+ name (str): Name of this throttle.
limit (int): Max number of failures before imposing limiter
timeout (int): number of timeout seconds after
max number of tries has been reached.
@@ -71,9 +74,37 @@
rolling window; this is NOT the same as the limit after which
the throttle is imposed!
"""
- self.storage = defaultdict(deque)
- self.cache_size = self.limit = kwargs.get("limit", 5)
+ try:
+ self.storage = caches['throttle']
+ except Exception as e:
+ logger.log_trace("Throttle: Errors encountered; using default cache.")
+ self.storage = caches['default']
+
+ self.name = kwargs.get('name', 'undefined-throttle')
+ self.limit = kwargs.get("limit", 5)
+ self.cache_size = kwargs.get('cache_size', self.limit)
self.timeout = kwargs.get("timeout", 5 * 60)
+
+ [docs] def get_cache_key(self, *args, **kwargs):
+ """
+ Creates a 'prefixed' key containing arbitrary terms to prevent key
+ collisions in the same namespace.
+
+ """
+ return '-'.join((self.name, *args))
+
+ [docs] def touch(self, key, *args, **kwargs):
+ """
+ Refreshes the timeout on a given key and ensures it is recorded in the
+ key register.
+
+ Args:
+ key(str): Key of entry to renew.
+
+ """
+ cache_key = self.get_cache_key(key)
+ if self.storage.touch(cache_key, self.timeout):
+ self.record_key(key)
[docs] def get(self, ip=None):
"""
@@ -91,9 +122,18 @@
"""
if ip:
- return self.storage.get(ip, deque(maxlen=self.cache_size))
+ cache_key = self.get_cache_key(str(ip))
+ return self.storage.get(cache_key, deque(maxlen=self.cache_size))
else:
- return self.storage
+ keys_key = self.get_cache_key('keys')
+ keys = self.storage.get_or_set(keys_key, set(), self.timeout)
+ data = self.storage.get_many((self.get_cache_key(x) for x in keys))
+
+ found_keys = set(data.keys())
+ if len(keys) != len(found_keys):
+ self.storage.set(keys_key, found_keys, self.timeout)
+
+ return data
[docs] def update(self, ip, failmsg="Exceeded threshold."):
"""
@@ -108,24 +148,77 @@
None
"""
+ cache_key = self.get_cache_key(ip)
+
# Get current status
previously_throttled = self.check(ip)
- # Enforce length limits
- if not self.storage[ip].maxlen:
- self.storage[ip] = deque(maxlen=self.cache_size)
-
- self.storage[ip].append(time.time())
+ # Get previous failures, if any
+ entries = self.storage.get(cache_key, [])
+ entries.append(time.time())
+
+ # Store updated record
+ self.storage.set(cache_key, deque(entries, maxlen=self.cache_size), self.timeout)
# See if this update caused a change in status
currently_throttled = self.check(ip)
# If this makes it engage, log a single activation event
if not previously_throttled and currently_throttled:
- logger.log_sec(
- "Throttle Activated: %s (IP: %s, %i hits in %i seconds.)"
- % (failmsg, ip, self.limit, self.timeout)
- )
+ logger.log_sec(f"Throttle Activated: {failmsg} (IP: {ip}, {self.limit} hits in {self.timeout} seconds.)")
+
+ self.record_ip(ip)
+
+[docs] def remove(self, ip, *args, **kwargs):
+ """
+ Clears data stored for an IP from the throttle.
+
+ Args:
+ ip(str): IP to clear.
+
+ """
+ exists = self.get(ip)
+ if not exists: return False
+
+ cache_key = self.get_cache_key(ip)
+ self.storage.delete(cache_key)
+ self.unrecord_ip(ip)
+
+ # Return True if NOT exists
+ return ~bool(self.get(ip))
+
+[docs] def record_ip(self, ip, *args, **kwargs):
+ """
+ Tracks keys as they are added to the cache (since there is no way to
+ get a list of keys after-the-fact).
+
+ Args:
+ ip(str): IP being added to cache. This should be the original
+ IP, not the cache-prefixed key.
+
+ """
+ keys_key = self.get_cache_key('keys')
+ keys = self.storage.get(keys_key, set())
+ keys.add(ip)
+ self.storage.set(keys_key, keys, self.timeout)
+ return True
+
+[docs] def unrecord_ip(self, ip, *args, **kwargs):
+ """
+ Forces removal of a key from the key registry.
+
+ Args:
+ ip(str): IP to remove from list of keys.
+
+ """
+ keys_key = self.get_cache_key('keys')
+ keys = self.storage.get(keys_key, set())
+ try:
+ keys.remove(ip)
+ self.storage.set(keys_key, keys, self.timeout)
+ return True
+ except KeyError:
+ return False
[docs] def check(self, ip):
"""
@@ -143,17 +236,20 @@
"""
now = time.time()
ip = str(ip)
+
+ cache_key = self.get_cache_key(ip)
# checking mode
- latest_fails = self.storage[ip]
+ latest_fails = self.storage.get(cache_key)
if latest_fails and len(latest_fails) >= self.limit:
# too many fails recently
if now - latest_fails[-1] < self.timeout:
# too soon - timeout in play
+ self.touch(cache_key)
return True
else:
# timeout has passed. clear faillist
- del self.storage[ip]
+ self.remove(ip)
return False
else:
return False
@@ -202,6 +298,7 @@
evennia »
evennia.server.throttle
+ develop branch
@@ -479,7 +480,7 @@
"""
key = key.strip().lower() if key else None
- category = category.strip().lower() if category else None
+ category = category.strip().lower() if category is not None else None
if key:
return self._get_cache_key(key, category)
return self._get_cache_category(category)
@@ -1587,6 +1588,7 @@
evennia »
evennia.typeclasses.attributes
+ develop branch
@@ -42,19 +43,64 @@
"""
ANSI - Gives colour to text.
-Use the codes defined in ANSIPARSER in your text
-to apply colour to text according to the ANSI standard.
+Use the codes defined in the *ANSIParser* class to apply colour to text. The
+`parse_ansi` function in this module parses text for markup and `strip_ansi`
+removes it.
-Examples:
+You should usually not need to call `parse_ansi` explicitly; it is run by
+Evennia just before returning data to/from the user. Alternative markup is
+possible by overriding the parser class (see also contrib/ for deprecated
+markup schemes).
+
+
+Supported standards:
+
+- ANSI 8 bright and 8 dark fg (foreground) colors
+- ANSI 8 dark bg (background) colors
+- 'ANSI' 8 bright bg colors 'faked' with xterm256 (bright bg not included in ANSI standard)
+- Xterm256 - 255 fg/bg colors + 26 greyscale fg/bg colors
+
+## Markup
+
+ANSI colors: `r` ed, `g` reen, `y` ellow, `b` lue, `m` agenta, `c` yan, `n` ormal (no color). Capital
+letters indicate the 'dark' variant.
+
+- `|r` fg bright red
+- `|R` fg dark red
+- `|[r` bg bright red
+- `|[R` bg dark red
+- `|[R|g` bg dark red, fg bright green
```python
"This is |rRed text|n and this is normal again."
+
```
-Mostly you should not need to call `parse_ansi()` explicitly;
-it is run by Evennia just before returning data to/from the
-user. Depreciated example forms are available by extending
-the ansi mapping.
+Xterm256 colors are given as RGB (Red-Green-Blue), with values 0-5:
+
+- `|500` fg bright red
+- `|050` fg bright green
+- `|005` fg bright blue
+- `|110` fg dark brown
+- `|425` fg pink
+- `|[431` bg orange
+
+Xterm256 greyscale:
+
+- `|=a` fg black
+- `|=g` fg dark grey
+- `|=o` fg middle grey
+- `|=v` fg bright grey
+- `|=z` fg white
+- `|[=r` bg middle grey
+
+```python
+"This is |500Red text|n and this is normal again."
+"This is |[=jText on dark grey background"
+
+```
+
+----
"""
import functools
@@ -126,8 +172,7 @@
to ANSI command sequences
We also allow to escape colour codes
- by prepending with a \ for xterm256,
- an extra | for Merc-style codes
+ by prepending with an extra `|`.
"""
@@ -138,6 +183,7 @@
(r"|n", ANSI_NORMAL), # reset
(r"|/", ANSI_RETURN), # line break
(r"|-", ANSI_TAB), # tab
+ (r"|>", ANSI_SPACE * 4), # indent (4 spaces)
(r"|_", ANSI_SPACE), # space
(r"|*", ANSI_INVERSE), # invert
(r"|^", ANSI_BLINK), # blinking text (very annoying and not supported by all clients)
@@ -567,6 +613,13 @@
return string.replace("{", "{{").replace("|", "||")
+# ------------------------------------------------------------
+#
+# ANSIString - ANSI-aware string class
+#
+# ------------------------------------------------------------
+
+
def _spacing_preflight(func):
"""
This wrapper function is used to do some preflight checks on
@@ -937,9 +990,23 @@
replayed.
"""
- slice_indexes = self._char_indexes[slc]
+ char_indexes = self._char_indexes
+ slice_indexes = char_indexes[slc]
# If it's the end of the string, we need to append final color codes.
if not slice_indexes:
+ # if we find no characters it may be because we are just outside
+ # of the interval, using an open-ended slice. We must replay all
+ # of the escape characters until/after this point.
+ if char_indexes:
+ if slc.start is None and slc.stop is None:
+ # a [:] slice of only escape characters
+ return ANSIString(self._raw_string[slc])
+ if slc.start is None:
+ # this is a [:x] slice
+ return ANSIString(self._raw_string[:char_indexes[0]])
+ if slc.stop is None:
+ # a [x:] slice
+ return ANSIString(self._raw_string[char_indexes[-1] + 1:])
return ANSIString("")
try:
string = self[slc.start or 0]._raw_string
@@ -959,7 +1026,7 @@
# raw_string not long enough
pass
if i is not None:
- append_tail = self._get_interleving(self._char_indexes.index(i) + 1)
+ append_tail = self._get_interleving(char_indexes.index(i) + 1)
else:
append_tail = ""
return ANSIString(string + append_tail, decoded=True)
@@ -1484,6 +1551,7 @@
evennia »
evennia.utils.ansi
+ develop branch
@@ -341,6 +342,10 @@
def has_key(self, key):
return key in self._data
+ @_save
+ def update(self, *args, **kwargs):
+ self._data.update(*args, **kwargs)
+
class _SaverSet(_SaverMutable, MutableSet):
"""
@@ -836,6 +841,7 @@
evennia »
evennia.utils.dbserialize
+ develop branch
@@ -206,9 +207,12 @@
def _to_ansi(obj, regexable=False):
"convert to ANSIString"
- if isinstance(obj, str):
+ if isinstance(obj, ANSIString):
+ return obj
+ elif isinstance(obj, str):
# since ansi will be parsed twice (here and in the normal ansi send), we have to
- # escape the |-structure twice.
+ # escape the |-structure twice. TODO: This is tied to the default color-tag syntax
+ # which is not ideal for those wanting to replace/extend it ...
obj = _ANSI_ESCAPE.sub(r"||||", obj)
if isinstance(obj, dict):
return dict((key, _to_ansi(value, regexable=regexable)) for key, value in obj.items())
@@ -218,7 +222,7 @@
return ANSIString(obj, regexable=regexable)
-
@@ -586,6 +553,7 @@
evennia »
evennia.utils.evform
+ develop branch
@@ -408,7 +409,7 @@
logfile.LogFile.rotate(self)
return
lines = tail_log_file(self.path, 0, self.num_lines_to_append)
- logfile.LogFile.rotate(self)
+ super().rotate()
for line in lines:
self.write(line)
@@ -618,6 +619,7 @@
evennia »
evennia.utils.logger
+ develop branch
@@ -138,7 +139,7 @@
re_blink = re.compile("(?:%s)(.*?)(?=%s|%s)" % (blink.replace("[", r"\["), fgstop, bgstop))
re_inverse = re.compile("(?:%s)(.*?)(?=%s|%s)" % (inverse.replace("[", r"\["), fgstop, bgstop))
re_string = re.compile(
- r"(?P<htmlchars>[<&>])|(?P<firstspace>(?<=\S) )|(?P<space> [ \t]+)|"
+ r"(?P<htmlchars>[<&>])|(?P<tab>[\t]+)|(?P<space> +)|"
r"(?P<spacestart>^ )|(?P<lineend>\r\n|\r|\n)",
re.S | re.M | re.I,
)
@@ -348,13 +349,12 @@
return html_escape(cdict["htmlchars"])
elif cdict["lineend"]:
return "<br>"
- elif cdict["firstspace"]:
- return " "
- elif cdict["space"] == "\t":
- return " " if self.tabstop == 1 else " " + " " * self.tabstop
+ elif cdict["tab"]:
+ text = cdict["tab"].replace("\t", " " + " " * (self.tabstop - 1))
+ return text
elif cdict["space"] or cdict["spacestart"]:
- text = match.group().replace("\t", " " * self.tabstop)
- text = text.replace(" ", " ")
+ text = cdict["space"]
+ text = " " if len(text) == 1 else " " + text[1:].replace(" ", " ")
return text
return None
@@ -453,6 +453,7 @@
evennia »
evennia.utils.text2html
+ develop branch
@@ -69,7 +70,7 @@ method. Otherwise all text will be returned to all connected sessions.
-
-
aliases = ['l', 'ls']
+aliases = ['ls', 'l']
@@ -100,7 +101,7 @@ method. Otherwise all text will be returned to all connected sessions.
-
-
search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look while out-of-character\n\n Usage:\n look\n\n Look in the ooc state.\n '}
+search_index_entry = {'aliases': 'ls l', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look while out-of-character\n\n Usage:\n look\n\n Look in the ooc state.\n '}
@@ -864,6 +865,7 @@ to all the variables defined therein.
Evennia 0.9.5 »
evennia.commands.default.account
+ develop branch
@@ -74,7 +75,7 @@ skipping, reloading etc.
-
-
aliases = ['batchcommand', 'batchcmd']
+aliases = ['batchcmd', 'batchcommand']
@@ -105,7 +106,7 @@ skipping, reloading etc.
-
-
search_index_entry = {'aliases': 'batchcommand batchcmd', 'category': 'building', 'key': 'batchcommands', 'tags': '', 'text': '\n build from batch-command file\n\n Usage:\n batchcommands[/interactive] <python.path.to.file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n\n Runs batches of commands from a batch-cmd text file (*.ev).\n\n '}
+search_index_entry = {'aliases': 'batchcmd batchcommand', 'category': 'building', 'key': 'batchcommands', 'tags': '', 'text': '\n build from batch-command file\n\n Usage:\n batchcommands[/interactive] <python.path.to.file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n\n Runs batches of commands from a batch-cmd text file (*.ev).\n\n '}
@@ -224,6 +225,7 @@ object copies behind when testing out the script.
Evennia 0.9.5 »
evennia.commands.default.batchprocess
+ develop branch
@@ -528,7 +529,7 @@ You can specify the /force switch to bypass this confirmation.
-
-
aliases = ['del', 'delete']
+aliases = ['delete', 'del']
@@ -569,7 +570,7 @@ You can specify the /force switch to bypass this confirmation.
-
-
search_index_entry = {'aliases': 'del delete', 'category': 'building', 'key': 'destroy', 'tags': '', 'text': '\n permanently delete objects\n\n Usage:\n destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...]\n\n Switches:\n override - The destroy command will usually avoid accidentally\n destroying account objects. This switch overrides this safety.\n force - destroy without confirmation.\n Examples:\n destroy house, roof, door, 44-78\n destroy 5-10, flower, 45\n destroy/force north\n\n Destroys one or many objects. If dbrefs are used, a range to delete can be\n given, e.g. 4-10. Also the end points will be deleted. This command\n displays a confirmation before destroying, to make sure of your choice.\n You can specify the /force switch to bypass this confirmation.\n '}
+search_index_entry = {'aliases': 'delete del', 'category': 'building', 'key': 'destroy', 'tags': '', 'text': '\n permanently delete objects\n\n Usage:\n destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...]\n\n Switches:\n override - The destroy command will usually avoid accidentally\n destroying account objects. This switch overrides this safety.\n force - destroy without confirmation.\n Examples:\n destroy house, roof, door, 44-78\n destroy 5-10, flower, 45\n destroy/force north\n\n Destroys one or many objects. If dbrefs are used, a range to delete can be\n given, e.g. 4-10. Also the end points will be deleted. This command\n displays a confirmation before destroying, to make sure of your choice.\n You can specify the /force switch to bypass this confirmation.\n '}
@@ -1267,7 +1268,7 @@ server settings.
-
-
aliases = ['swap', 'parent', 'update', 'type']
+aliases = ['type', 'parent', 'update', 'swap']
@@ -1298,7 +1299,7 @@ server settings.
-
-
search_index_entry = {'aliases': 'swap parent update type', 'category': 'building', 'key': 'typeclass', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object.\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}
+search_index_entry = {'aliases': 'type parent update swap', 'category': 'building', 'key': 'typeclass', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object.\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}
@@ -1451,7 +1452,7 @@ If object is not specified, the current location is examined.
-
-
aliases = ['exam', 'ex']
+aliases = ['ex', 'exam']
@@ -1548,7 +1549,7 @@ non-persistent data stored on object
-
-
search_index_entry = {'aliases': 'exam ex', 'category': 'building', 'key': 'examine', 'tags': '', 'text': '\n get detailed information about an object\n\n Usage:\n examine [<object>[/attrname]]\n examine [*<account>[/attrname]]\n\n Switch:\n account - examine an Account (same as adding *)\n object - examine an Object (useful when OOC)\n\n The examine command shows detailed game info about an\n object and optionally a specific attribute on it.\n If object is not specified, the current location is examined.\n\n Append a * before the search string to examine an account.\n\n '}
+search_index_entry = {'aliases': 'ex exam', 'category': 'building', 'key': 'examine', 'tags': '', 'text': '\n get detailed information about an object\n\n Usage:\n examine [<object>[/attrname]]\n examine [*<account>[/attrname]]\n\n Switch:\n account - examine an Account (same as adding *)\n object - examine an Object (useful when OOC)\n\n The examine command shows detailed game info about an\n object and optionally a specific attribute on it.\n If object is not specified, the current location is examined.\n\n Append a * before the search string to examine an account.\n\n '}
@@ -1991,6 +1992,7 @@ displays a list of available prototypes.
Evennia 0.9.5 »
evennia.commands.default.building
+ develop branch
@@ -233,7 +234,7 @@ Use addcom/delcom to join and leave channels
-
-
aliases = ['comlist', 'chanlist', 'channellist', 'clist', 'all channels']
+aliases = ['all channels', 'comlist', 'chanlist', 'channellist', 'clist']
@@ -264,7 +265,7 @@ Use addcom/delcom to join and leave channels
-
-
search_index_entry = {'aliases': 'comlist chanlist channellist clist all channels', 'category': 'comms', 'key': 'channels', 'tags': '', 'text': "\n list all channels available to you\n\n Usage:\n channels\n clist\n comlist\n\n Lists all channels available to you, whether you listen to them or not.\n Use 'comlist' to only view your current channel subscriptions.\n Use addcom/delcom to join and leave channels\n "}
+search_index_entry = {'aliases': 'all channels comlist chanlist channellist clist', 'category': 'comms', 'key': 'channels', 'tags': '', 'text': "\n list all channels available to you\n\n Usage:\n channels\n clist\n comlist\n\n Lists all channels available to you, whether you listen to them or not.\n Use 'comlist' to only view your current channel subscriptions.\n Use addcom/delcom to join and leave channels\n "}
@@ -1067,6 +1068,7 @@ must be added to game settings.
Evennia 0.9.5 »
evennia.commands.default.comms
+ develop branch
@@ -111,7 +112,7 @@ look *<account&g
-
-
aliases = ['l', 'ls']
+aliases = ['ls', 'l']
@@ -142,7 +143,7 @@ look *<account&g
-
-
search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look at location or object\n\n Usage:\n look\n look <obj>\n look *<account>\n\n Observes your location or objects in your vicinity.\n '}
+search_index_entry = {'aliases': 'ls l', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look at location or object\n\n Usage:\n look\n look <obj>\n look *<account>\n\n Observes your location or objects in your vicinity.\n '}
@@ -204,7 +205,7 @@ for everyone to use, you need build privileges and the alias command.
-
-
aliases = ['nickname', 'nicks']
+aliases = ['nicks', 'nickname']
@@ -236,7 +237,7 @@ for everyone to use, you need build privileges and the alias command.
-
-
search_index_entry = {'aliases': 'nickname nicks', 'category': 'general', 'key': 'nick', 'tags': '', 'text': '\n define a personal alias/nick by defining a string to\n match and replace it with another on the fly\n\n Usage:\n nick[/switches] <string> [= [replacement_string]]\n nick[/switches] <template> = <replacement_template>\n nick/delete <string> or number\n nicks\n\n Switches:\n inputline - replace on the inputline (default)\n object - replace on object-lookup\n account - replace on account-lookup\n list - show all defined aliases (also "nicks" works)\n delete - remove nick by index in /list\n clearall - clear all nicks\n\n Examples:\n nick hi = say Hello, I\'m Sarah!\n nick/object tom = the tall man\n nick build $1 $2 = create/drop $1;$2\n nick tell $1 $2=page $1=$2\n nick tm?$1=page tallman=$1\n nick tm\\=$1=page tallman=$1\n\n A \'nick\' is a personal string replacement. Use $1, $2, ... to catch arguments.\n Put the last $-marker without an ending space to catch all remaining text. You\n can also use unix-glob matching for the left-hand side <string>:\n\n * - matches everything\n ? - matches 0 or 1 single characters\n [abcd] - matches these chars in any order\n [!abcd] - matches everything not among these chars\n \\= - escape literal \'=\' you want in your <string>\n\n Note that no objects are actually renamed or changed by this command - your nicks\n are only available to you. If you want to permanently add keywords to an object\n for everyone to use, you need build privileges and the alias command.\n\n '}
+search_index_entry = {'aliases': 'nicks nickname', 'category': 'general', 'key': 'nick', 'tags': '', 'text': '\n define a personal alias/nick by defining a string to\n match and replace it with another on the fly\n\n Usage:\n nick[/switches] <string> [= [replacement_string]]\n nick[/switches] <template> = <replacement_template>\n nick/delete <string> or number\n nicks\n\n Switches:\n inputline - replace on the inputline (default)\n object - replace on object-lookup\n account - replace on account-lookup\n list - show all defined aliases (also "nicks" works)\n delete - remove nick by index in /list\n clearall - clear all nicks\n\n Examples:\n nick hi = say Hello, I\'m Sarah!\n nick/object tom = the tall man\n nick build $1 $2 = create/drop $1;$2\n nick tell $1 $2=page $1=$2\n nick tm?$1=page tallman=$1\n nick tm\\=$1=page tallman=$1\n\n A \'nick\' is a personal string replacement. Use $1, $2, ... to catch arguments.\n Put the last $-marker without an ending space to catch all remaining text. You\n can also use unix-glob matching for the left-hand side <string>:\n\n * - matches everything\n ? - matches 0 or 1 single characters\n [abcd] - matches these chars in any order\n [!abcd] - matches everything not among these chars\n \\= - escape literal \'=\' you want in your <string>\n\n Note that no objects are actually renamed or changed by this command - your nicks\n are only available to you. If you want to permanently add keywords to an object\n for everyone to use, you need build privileges and the alias command.\n\n '}
@@ -259,7 +260,7 @@ inv
-
-
aliases = ['i', 'inv']
+aliases = ['inv', 'i']
@@ -290,7 +291,7 @@ inv
-
-
search_index_entry = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
+search_index_entry = {'aliases': 'inv i', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
@@ -640,7 +641,7 @@ automatically begin with your name.
-
-
aliases = [':', 'emote']
+aliases = ['emote', ':']
@@ -676,7 +677,7 @@ space.
-
-
search_index_entry = {'aliases': ': emote', 'category': 'general', 'key': 'pose', 'tags': '', 'text': "\n strike a pose\n\n Usage:\n pose <pose text>\n pose's <pose text>\n\n Example:\n pose is standing by the wall, smiling.\n -> others will see:\n Tom is standing by the wall, smiling.\n\n Describe an action being taken. The pose text will\n automatically begin with your name.\n "}
+search_index_entry = {'aliases': 'emote :', 'category': 'general', 'key': 'pose', 'tags': '', 'text': "\n strike a pose\n\n Usage:\n pose <pose text>\n pose's <pose text>\n\n Example:\n pose is standing by the wall, smiling.\n -> others will see:\n Tom is standing by the wall, smiling.\n\n Describe an action being taken. The pose text will\n automatically begin with your name.\n "}
@@ -699,7 +700,7 @@ which permission groups you are a member of.
-
-
aliases = ['hierarchy', 'groups']
+aliases = ['groups', 'hierarchy']
@@ -730,7 +731,7 @@ which permission groups you are a member of.
-
-
search_index_entry = {'aliases': 'hierarchy groups', 'category': 'general', 'key': 'access', 'tags': '', 'text': '\n show your current game access\n\n Usage:\n access\n\n This command shows you the permission hierarchy and\n which permission groups you are a member of.\n '}
+search_index_entry = {'aliases': 'groups hierarchy', 'category': 'general', 'key': 'access', 'tags': '', 'text': '\n show your current game access\n\n Usage:\n access\n\n This command shows you the permission hierarchy and\n which permission groups you are a member of.\n '}
@@ -786,6 +787,7 @@ which permission groups you are a member of.
Evennia 0.9.5 »
evennia.commands.default.general
+ develop branch
@@ -373,7 +374,7 @@ given, <nr> defaults to 10.
-
-
aliases = ['listobjs', 'listobjects', 'stats', 'db']
+aliases = ['stats', 'db', 'listobjs', 'listobjects']
@@ -399,7 +400,7 @@ given, <nr> defaults to 10.
-
-
search_index_entry = {'aliases': 'listobjs listobjects stats db', 'category': 'system', 'key': 'objects', 'tags': '', 'text': '\n statistics on objects in the database\n\n Usage:\n objects [<nr>]\n\n Gives statictics on objects in database as well as\n a list of <nr> latest objects in database. If not\n given, <nr> defaults to 10.\n '}
+search_index_entry = {'aliases': 'stats db listobjs listobjects', 'category': 'system', 'key': 'objects', 'tags': '', 'text': '\n statistics on objects in the database\n\n Usage:\n objects [<nr>]\n\n Gives statictics on objects in database as well as\n a list of <nr> latest objects in database. If not\n given, <nr> defaults to 10.\n '}
@@ -687,6 +688,7 @@ the released memory will instead be re-used by the program.
Evennia 0.9.5 »
evennia.commands.default.system
+ develop branch
@@ -58,7 +59,7 @@ connect “account name” “pass word”
-
-
aliases = ['conn', 'con', 'co']
+aliases = ['con', 'conn', 'co']
@@ -93,7 +94,7 @@ there is no object yet before the account has logged in)
-
-
search_index_entry = {'aliases': 'conn con co', 'category': 'general', 'key': 'connect', 'tags': '', 'text': '\n connect to the game\n\n Usage (at login screen):\n connect accountname password\n connect "account name" "pass word"\n\n Use the create command to first create an account before logging in.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
+search_index_entry = {'aliases': 'con conn co', 'category': 'general', 'key': 'connect', 'tags': '', 'text': '\n connect to the game\n\n Usage (at login screen):\n connect accountname password\n connect "account name" "pass word"\n\n Use the create command to first create an account before logging in.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
@@ -172,7 +173,7 @@ version is a bit more complicated.
-
-
aliases = ['q', 'qu']
+aliases = ['qu', 'q']
@@ -198,7 +199,7 @@ version is a bit more complicated.
-
-
search_index_entry = {'aliases': 'q qu', 'category': 'general', 'key': 'quit', 'tags': '', 'text': '\n quit when in unlogged-in state\n\n Usage:\n quit\n\n We maintain a different version of the quit command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
+search_index_entry = {'aliases': 'qu q', 'category': 'general', 'key': 'quit', 'tags': '', 'text': '\n quit when in unlogged-in state\n\n Usage:\n quit\n\n We maintain a different version of the quit command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
@@ -222,7 +223,7 @@ All it does is display the connect screen.
-
-
aliases = ['l', 'look']
+aliases = ['look', 'l']
@@ -248,7 +249,7 @@ All it does is display the connect screen.
-
-
search_index_entry = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
+search_index_entry = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
@@ -271,7 +272,7 @@ for simplicity. It shows a pane of info.
-
-
aliases = ['?', 'h']
+aliases = ['h', '?']
@@ -297,7 +298,7 @@ for simplicity. It shows a pane of info.
-
-
search_index_entry = {'aliases': '? h', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n get help when in unconnected-in state\n\n Usage:\n help\n\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
+search_index_entry = {'aliases': 'h ?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n get help when in unconnected-in state\n\n Usage:\n help\n\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
@@ -353,6 +354,7 @@ for simplicity. It shows a pane of info.
Evennia 0.9.5 »
evennia.commands.default.unloggedin
+ develop branch
@@ -680,7 +681,7 @@ try to influence the other part in the deal.
-
-
aliases = ['deal', 'offers']
+aliases = ['offers', 'deal']
@@ -706,7 +707,7 @@ try to influence the other part in the deal.
-
-
search_index_entry = {'aliases': 'deal offers', 'category': 'trading', 'key': 'status', 'tags': '', 'text': "\n show a list of the current deal\n\n Usage:\n status\n deal\n offers\n\n Shows the currently suggested offers on each sides of the deal. To\n accept the current deal, use the 'accept' command. Use 'offer' to\n change your deal. You might also want to use 'say', 'emote' etc to\n try to influence the other part in the deal.\n "}
+search_index_entry = {'aliases': 'offers deal', 'category': 'trading', 'key': 'status', 'tags': '', 'text': "\n show a list of the current deal\n\n Usage:\n status\n deal\n offers\n\n Shows the currently suggested offers on each sides of the deal. To\n accept the current deal, use the 'accept' command. Use 'offer' to\n change your deal. You might also want to use 'say', 'emote' etc to\n try to influence the other part in the deal.\n "}
@@ -890,6 +891,7 @@ info to your choice.
Evennia 0.9.5 »
evennia.contrib.barter
+ develop branch
@@ -76,7 +77,7 @@ at them with this command.
-
-
aliases = ['l', 'ls']
+aliases = ['ls', 'l']
@@ -108,7 +109,7 @@ that is checked by the @ic command directly.
-
-
search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n ooc look\n\n Usage:\n look\n look <character>\n\n This is an OOC version of the look command. Since an Account doesn\'t\n have an in-game existence, there is no concept of location or\n "self".\n\n If any characters are available for you to control, you may look\n at them with this command.\n '}
+search_index_entry = {'aliases': 'ls l', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n ooc look\n\n Usage:\n look\n look <character>\n\n This is an OOC version of the look command. Since an Account doesn\'t\n have an in-game existence, there is no concept of location or\n "self".\n\n If any characters are available for you to control, you may look\n at them with this command.\n '}
@@ -232,6 +233,7 @@ attribute on ourselves to remember it.
Evennia 0.9.5 »
evennia.contrib.chargen
+ develop branch
@@ -627,7 +628,7 @@ inv
-
-
aliases = ['i', 'inv']
+aliases = ['inv', 'i']
@@ -658,7 +659,7 @@ inv
-
-
search_index_entry = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
+search_index_entry = {'aliases': 'inv i', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
@@ -740,6 +741,7 @@ items.
Evennia 0.9.5 »
evennia.contrib.clothing
+ develop branch
@@ -73,7 +74,7 @@ the module given by settings.CONNECTION_SCREEN_MODULE.
-
-
aliases = ['conn', 'con', 'co']
+aliases = ['con', 'conn', 'co']
@@ -103,7 +104,7 @@ there is no object yet before the account has logged in)
-
-
search_index_entry = {'aliases': 'conn con co', 'category': 'general', 'key': 'connect', 'tags': '', 'text': '\n Connect to the game.\n\n Usage (at login screen):\n connect <email> <password>\n\n Use the create command to first create an account before logging in.\n '}
+search_index_entry = {'aliases': 'con conn co', 'category': 'general', 'key': 'connect', 'tags': '', 'text': '\n Connect to the game.\n\n Usage (at login screen):\n connect <email> <password>\n\n Use the create command to first create an account before logging in.\n '}
@@ -180,7 +181,7 @@ version is a bit more complicated.
-
-
aliases = ['q', 'qu']
+aliases = ['qu', 'q']
@@ -206,7 +207,7 @@ version is a bit more complicated.
-
-
search_index_entry = {'aliases': 'q qu', 'category': 'general', 'key': 'quit', 'tags': '', 'text': '\n We maintain a different version of the `quit` command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
+search_index_entry = {'aliases': 'qu q', 'category': 'general', 'key': 'quit', 'tags': '', 'text': '\n We maintain a different version of the `quit` command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
@@ -225,7 +226,7 @@ All it does is display the connect screen.
-
-
aliases = ['l', 'look']
+aliases = ['look', 'l']
@@ -251,7 +252,7 @@ All it does is display the connect screen.
-
-
search_index_entry = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
+search_index_entry = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
@@ -269,7 +270,7 @@ for simplicity. It shows a pane of info.
-
-
aliases = ['?', 'h']
+aliases = ['h', '?']
@@ -295,7 +296,7 @@ for simplicity. It shows a pane of info.
-
-
search_index_entry = {'aliases': '? h', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
+search_index_entry = {'aliases': 'h ?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
@@ -351,6 +352,7 @@ for simplicity. It shows a pane of info.
Evennia 0.9.5 »
evennia.contrib.email_login
+ develop branch
@@ -275,7 +276,7 @@ look *<account&g
-
-
aliases = ['l', 'ls']
+aliases = ['ls', 'l']
@@ -295,7 +296,7 @@ look *<account&g
-
-
search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look\n\n Usage:\n look\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects in your vicinity.\n '}
+search_index_entry = {'aliases': 'ls l', 'category': 'general', 'key': 'look', 'tags': '', 'text': '\n look\n\n Usage:\n look\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects in your vicinity.\n '}
@@ -550,6 +551,7 @@ self.add().
Evennia 0.9.5 »
evennia.contrib.extended_room
+ develop branch
@@ -51,7 +52,7 @@
-
-
aliases = ['@calls', '@callback', '@callbacks']
+aliases = ['@callbacks', '@callback', '@calls']
@@ -132,7 +133,7 @@ on user permission.
-
-
search_index_entry = {'aliases': '@calls @callback @callbacks', 'category': 'building', 'key': '@call', 'tags': '', 'text': '\n Command to edit callbacks.\n '}
+search_index_entry = {'aliases': '@callbacks @callback @calls', 'category': 'building', 'key': '@call', 'tags': '', 'text': '\n Command to edit callbacks.\n '}
@@ -188,6 +189,7 @@ on user permission.
Evennia 0.9.5 »
evennia.contrib.ingame_python.commands
+ develop branch
@@ -800,7 +801,7 @@ Using the command without arguments will list all current recogs.
-
-
aliases = ['forget', 'recognize']
+aliases = ['recognize', 'forget']
@@ -827,7 +828,7 @@ Using the command without arguments will list all current recogs.
-
-
search_index_entry = {'aliases': 'forget recognize', 'category': 'general', 'key': 'recog', 'tags': '', 'text': '\n Recognize another person in the same room.\n\n Usage:\n recog\n recog sdesc as alias\n forget alias\n\n Example:\n recog tall man as Griatch\n forget griatch\n\n This will assign a personal alias for a person, or forget said alias.\n Using the command without arguments will list all current recogs.\n\n '}
+search_index_entry = {'aliases': 'recognize forget', 'category': 'general', 'key': 'recog', 'tags': '', 'text': '\n Recognize another person in the same room.\n\n Usage:\n recog\n recog sdesc as alias\n forget alias\n\n Example:\n recog tall man as Griatch\n forget griatch\n\n This will assign a personal alias for a person, or forget said alias.\n Using the command without arguments will list all current recogs.\n\n '}
@@ -1293,6 +1294,7 @@ the evennia.contrib.rplanguage module.
Evennia 0.9.5 »
evennia.contrib.rpsystem
+ develop branch
@@ -109,7 +110,7 @@ push the lid of the button away.
-
-
aliases = ['press button', 'push', 'press']
+aliases = ['push', 'press', 'press button']
@@ -140,7 +141,7 @@ lid-state respectively.
-
-
search_index_entry = {'aliases': 'press button push press', 'category': 'general', 'key': 'push button', 'tags': '', 'text': '\n Push the red button\n\n Usage:\n push button\n\n '}
+search_index_entry = {'aliases': 'push press press button', 'category': 'general', 'key': 'push button', 'tags': '', 'text': '\n Push the red button\n\n Usage:\n push button\n\n '}
@@ -162,7 +163,7 @@ lid-state respectively.
-
-
aliases = ['smash lid', 'break lid', 'smash']
+aliases = ['smash', 'smash lid', 'break lid']
@@ -189,7 +190,7 @@ of causing the lamp to break.
-
-
search_index_entry = {'aliases': 'smash lid break lid smash', 'category': 'general', 'key': 'smash glass', 'tags': '', 'text': '\n smash glass\n\n Usage:\n smash glass\n\n Try to smash the glass of the button.\n '}
+search_index_entry = {'aliases': 'smash smash lid break lid', 'category': 'general', 'key': 'smash glass', 'tags': '', 'text': '\n smash glass\n\n Usage:\n smash glass\n\n Try to smash the glass of the button.\n '}
@@ -210,7 +211,7 @@ of causing the lamp to break.
-
-
aliases = ['open', 'open button']
+aliases = ['open button', 'open']
@@ -236,7 +237,7 @@ of causing the lamp to break.
-
-
search_index_entry = {'aliases': 'open open button', 'category': 'general', 'key': 'open lid', 'tags': '', 'text': '\n open lid\n\n Usage:\n open lid\n\n '}
+search_index_entry = {'aliases': 'open button open', 'category': 'general', 'key': 'open lid', 'tags': '', 'text': '\n open lid\n\n Usage:\n open lid\n\n '}
@@ -306,7 +307,7 @@ of causing the lamp to break.
-
-
aliases = ['examine', 'l', 'listen', 'get', 'ex', 'feel']
+aliases = ['examine', 'l', 'feel', 'get', 'listen', 'ex']
@@ -332,7 +333,7 @@ of causing the lamp to break.
-
-
search_index_entry = {'aliases': 'examine l listen get ex feel', 'category': 'general', 'key': 'look', 'tags': '', 'text': "\n Looking around in darkness\n\n Usage:\n look <obj>\n\n ... not that there's much to see in the dark.\n\n "}
+search_index_entry = {'aliases': 'examine l feel get listen ex', 'category': 'general', 'key': 'look', 'tags': '', 'text': "\n Looking around in darkness\n\n Usage:\n look <obj>\n\n ... not that there's much to see in the dark.\n\n "}
@@ -567,6 +568,7 @@ the button is pushed.
Evennia 0.9.5 »
evennia.contrib.tutorial_examples.cmdset_red_button
+ develop branch
@@ -491,7 +492,7 @@ shift green root up/down
-
-
aliases = ['move', 'push', 'pull', 'shiftroot']
+aliases = ['push', 'pull', 'shiftroot', 'move']
@@ -527,7 +528,7 @@ yellow/green - horizontal roots
-
-
search_index_entry = {'aliases': 'move push pull shiftroot', 'category': 'tutorialworld', 'key': 'shift', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}
+search_index_entry = {'aliases': 'push pull shiftroot move', 'category': 'tutorialworld', 'key': 'shift', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}
@@ -714,7 +715,7 @@ parry - forgoes your attack but will make you harder to hit on next
-
-
aliases = ['thrust', 'parry', 'defend', 'stab', 'kill', 'slash', 'hit', 'pierce', 'chop', 'bash', 'fight']
+aliases = ['pierce', 'kill', 'slash', 'chop', 'hit', 'fight', 'parry', 'stab', 'defend', 'bash', 'thrust']
@@ -740,7 +741,7 @@ parry - forgoes your attack but will make you harder to hit on next
-
-
search_index_entry = {'aliases': 'thrust parry defend stab kill slash hit pierce chop bash fight', 'category': 'tutorialworld', 'key': 'attack', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}
+search_index_entry = {'aliases': 'pierce kill slash chop hit fight parry stab defend bash thrust', 'category': 'tutorialworld', 'key': 'attack', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}
@@ -995,6 +996,7 @@ pulling weapons from it indefinitely.
Evennia 0.9.5 »
evennia.contrib.tutorial_world.objects
+ develop branch
@@ -183,7 +184,7 @@ code except for adding in the details.
-
-
aliases = ['l', 'ls']
+aliases = ['ls', 'l']
@@ -198,7 +199,7 @@ code except for adding in the details.
-
-
search_index_entry = {'aliases': 'l ls', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n looks at the room and on details\n\n Usage:\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects\n in your vicinity.\n\n Tutorial: This is a child of the default Look command, that also\n allows us to look at "details" in the room. These details are\n things to examine and offers some extra description without\n actually having to be actual database objects. It uses the\n return_detail() hook on TutorialRooms for this.\n '}
+search_index_entry = {'aliases': 'ls l', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n looks at the room and on details\n\n Usage:\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects\n in your vicinity.\n\n Tutorial: This is a child of the default Look command, that also\n allows us to look at "details" in the room. These details are\n things to examine and offers some extra description without\n actually having to be actual database objects. It uses the\n return_detail() hook on TutorialRooms for this.\n '}
@@ -712,7 +713,7 @@ if they fall off the bridge.
-
-
aliases = ['?', 'h']
+aliases = ['h', '?']
@@ -738,7 +739,7 @@ if they fall off the bridge.
-
-
search_index_entry = {'aliases': '? h', 'category': 'tutorial world', 'key': 'help', 'tags': '', 'text': '\n Overwritten help command while on the bridge.\n '}
+search_index_entry = {'aliases': 'h ?', 'category': 'tutorial world', 'key': 'help', 'tags': '', 'text': '\n Overwritten help command while on the bridge.\n '}
@@ -864,7 +865,7 @@ to find something.
-
-
aliases = ['l', 'search', 'fiddle', 'feel around', 'feel']
+aliases = ['l', 'feel', 'search', 'fiddle', 'feel around']
@@ -892,7 +893,7 @@ random chance of eventually finding a light source.
-
-
search_index_entry = {'aliases': 'l search fiddle feel around feel', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}
+search_index_entry = {'aliases': 'l feel search fiddle feel around', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}
@@ -1262,6 +1263,7 @@ overriding the call (unused by default).
Evennia 0.9.5 »
evennia.contrib.tutorial_world.rooms
+ develop branch
@@ -369,7 +370,10 @@ with ‘q’, remove the break line and restart server when finished.
evennia.utils
@@ -101,6 +102,7 @@ also contains the default lock functions used in lock definitions.
Evennia 0.9.5 »
evennia.locks
+ develop branch
@@ -329,7 +330,8 @@ the keyword attribute_name specifies otherwise.
+ develop branch
@@ -76,6 +77,13 @@ the default reserved keys.
+
+-
+
evennia.prototypes.prototypes.load_module_prototypes()[source]
+This is called by evennia.__init__ as Evennia initializes. It’s important
+to do this late so as to not interfere with evennia initialization.
+
+
-
class
evennia.prototypes.prototypes.DbPrototype(*args, **kwargs)[source]
@@ -498,6 +506,7 @@ validator (callable, optional): If given, this will be called with the value to<
Evennia 0.9.5 »
evennia.prototypes.prototypes
+ develop branch
@@ -91,7 +92,7 @@ non-persistent tickers must be killed.
-
at_update(obj, fieldname)[source]
-Called by the field as it saves.
+Called by the field/attribute as it saves.
@@ -205,6 +206,7 @@ all kwargs must be possible to pickle!
Evennia 0.9.5 »
evennia.scripts.monitorhandler
+ develop branch
@@ -47,8 +48,8 @@
particular threshold.
This version of the throttle is usable by both the terminal server as well
as the web server, imposes limits on memory consumption by using deques
-with length limits instead of open-ended lists, and removes sparse keys when
-no recent failures have been recorded.
+with length limits instead of open-ended lists, and uses native Django
+caches for automatic key eviction and persistence configurability.
-
error_msg = 'Too many failed attempts; you must wait a few minutes before trying again.'
@@ -61,6 +62,7 @@ no recent failures have been recorded.
- Keyword Arguments
+name (str) – Name of this throttle.
limit (int) – Max number of failures before imposing limiter
timeout (int) – number of timeout seconds after
max number of tries has been reached.
@@ -72,6 +74,25 @@ the throttle is imposed!
+
+-
+
get_cache_key(*args, **kwargs)[source]
+Creates a ‘prefixed’ key containing arbitrary terms to prevent key
+collisions in the same namespace.
+
+
+
+-
+
touch(key, *args, **kwargs)[source]
+Refreshes the timeout on a given key and ensures it is recorded in the
+key register.
+
+- Parameters
+key (str) – Key of entry to renew.
+
+
+
+
-
get(ip=None)[source]
@@ -112,6 +133,41 @@ of throttle.
+
+-
+
remove(ip, *args, **kwargs)[source]
+Clears data stored for an IP from the throttle.
+
+- Parameters
+ip (str) – IP to clear.
+
+
+
+
+
+-
+
record_ip(ip, *args, **kwargs)[source]
+Tracks keys as they are added to the cache (since there is no way to
+get a list of keys after-the-fact).
+
+- Parameters
+ip (str) – IP being added to cache. This should be the original
+IP, not the cache-prefixed key.
+
+
+
+
+
+-
+
unrecord_ip(ip, *args, **kwargs)[source]
+Forces removal of a key from the key registry.
+
+- Parameters
+ip (str) – IP to remove from list of keys.
+
+
+
+
-
check(ip)[source]
@@ -186,6 +242,7 @@ fails recently.
Evennia 0.9.5 »
evennia.server.throttle
+ develop branch
@@ -39,16 +40,57 @@
evennia.utils.ansi
ANSI - Gives colour to text.
- Use the codes defined in ANSIPARSER in your text
-to apply colour to text according to the ANSI standard.
- Examples:
+ Use the codes defined in the ANSIParser class to apply colour to text. The
+parse_ansi function in this module parses text for markup and strip_ansi
+removes it.
+ You should usually not need to call parse_ansi explicitly; it is run by
+Evennia just before returning data to/from the user. Alternative markup is
+possible by overriding the parser class (see also contrib/ for deprecated
+markup schemes).
+ Supported standards:
+
+ANSI 8 bright and 8 dark fg (foreground) colors
+ANSI 8 dark bg (background) colors
+‘ANSI’ 8 bright bg colors ‘faked’ with xterm256 (bright bg not included in ANSI standard)
+Xterm256 - 255 fg/bg colors + 26 greyscale fg/bg colors
+
+
+ Markup
+ ANSI colors: r ed, g reen, y ellow, b lue, m agenta, c yan, n ormal (no color). Capital
+letters indicate the ‘dark’ variant.
+
"This is |rRed text|n and this is normal again."
- Mostly you should not need to call parse_ansi() explicitly;
-it is run by Evennia just before returning data to/from the
-user. Depreciated example forms are available by extending
-the ansi mapping.
+ Xterm256 colors are given as RGB (Red-Green-Blue), with values 0-5:
+
+|500 fg bright red
+|050 fg bright green
+|005 fg bright blue
+|110 fg dark brown
+|425 fg pink
+|[431 bg orange
+
+ Xterm256 greyscale:
+
+|=a fg black
+|=g fg dark grey
+|=o fg middle grey
+|=v fg bright grey
+|=z fg white
+|[=r bg middle grey
+
+ "This is |500Red text|n and this is normal again."
+"This is |[=jText on dark grey background"
+
+
+
-
class
evennia.utils.ansi.ANSIParser[source]
@@ -56,11 +98,10 @@ the ansi mapping.
A class that parses ANSI markup
to ANSI command sequences
We also allow to escape colour codes
-by prepending with a for xterm256,
-an extra | for Merc-style codes
+by prepending with an extra |.
-
-
ansi_map = [('|n', '\x1b[0m'), ('|/', '\r\n'), ('|-', '\t'), ('|_', ' '), ('|*', '\x1b[7m'), ('|^', '\x1b[5m'), ('|u', '\x1b[4m'), ('|r', '\x1b[1m\x1b[31m'), ('|g', '\x1b[1m\x1b[32m'), ('|y', '\x1b[1m\x1b[33m'), ('|b', '\x1b[1m\x1b[34m'), ('|m', '\x1b[1m\x1b[35m'), ('|c', '\x1b[1m\x1b[36m'), ('|w', '\x1b[1m\x1b[37m'), ('|x', '\x1b[1m\x1b[30m'), ('|R', '\x1b[22m\x1b[31m'), ('|G', '\x1b[22m\x1b[32m'), ('|Y', '\x1b[22m\x1b[33m'), ('|B', '\x1b[22m\x1b[34m'), ('|M', '\x1b[22m\x1b[35m'), ('|C', '\x1b[22m\x1b[36m'), ('|W', '\x1b[22m\x1b[37m'), ('|X', '\x1b[22m\x1b[30m'), ('|h', '\x1b[1m'), ('|H', '\x1b[22m'), ('|!R', '\x1b[31m'), ('|!G', '\x1b[32m'), ('|!Y', '\x1b[33m'), ('|!B', '\x1b[34m'), ('|!M', '\x1b[35m'), ('|!C', '\x1b[36m'), ('|!W', '\x1b[37m'), ('|!X', '\x1b[30m'), ('|[R', '\x1b[41m'), ('|[G', '\x1b[42m'), ('|[Y', '\x1b[43m'), ('|[B', '\x1b[44m'), ('|[M', '\x1b[45m'), ('|[C', '\x1b[46m'), ('|[W', '\x1b[47m'), ('|[X', '\x1b[40m')]
+ansi_map = [('|n', '\x1b[0m'), ('|/', '\r\n'), ('|-', '\t'), ('|>', ' '), ('|_', ' '), ('|*', '\x1b[7m'), ('|^', '\x1b[5m'), ('|u', '\x1b[4m'), ('|r', '\x1b[1m\x1b[31m'), ('|g', '\x1b[1m\x1b[32m'), ('|y', '\x1b[1m\x1b[33m'), ('|b', '\x1b[1m\x1b[34m'), ('|m', '\x1b[1m\x1b[35m'), ('|c', '\x1b[1m\x1b[36m'), ('|w', '\x1b[1m\x1b[37m'), ('|x', '\x1b[1m\x1b[30m'), ('|R', '\x1b[22m\x1b[31m'), ('|G', '\x1b[22m\x1b[32m'), ('|Y', '\x1b[22m\x1b[33m'), ('|B', '\x1b[22m\x1b[34m'), ('|M', '\x1b[22m\x1b[35m'), ('|C', '\x1b[22m\x1b[36m'), ('|W', '\x1b[22m\x1b[37m'), ('|X', '\x1b[22m\x1b[30m'), ('|h', '\x1b[1m'), ('|H', '\x1b[22m'), ('|!R', '\x1b[31m'), ('|!G', '\x1b[32m'), ('|!Y', '\x1b[33m'), ('|!B', '\x1b[34m'), ('|!M', '\x1b[35m'), ('|!C', '\x1b[36m'), ('|!W', '\x1b[37m'), ('|!X', '\x1b[30m'), ('|[R', '\x1b[41m'), ('|[G', '\x1b[42m'), ('|[Y', '\x1b[43m'), ('|[B', '\x1b[44m'), ('|[M', '\x1b[45m'), ('|[C', '\x1b[46m'), ('|[W', '\x1b[47m'), ('|[X', '\x1b[40m')]
@@ -120,7 +161,7 @@ an extra | for Merc-style codes
-
-
ansi_sub = re.compile('\\|n|\\|/|\\|\\-|\\|_|\\|\\*|\\|\\^|\\|u|\\|r|\\|g|\\|y|\\|b|\\|m|\\|c|\\|w|\\|x|\\|R|\\|G|\\|Y|\\|B|\\|M|\\|C|\\|W|\\|X|\\|h|\\|H|\\|!R|\\|!G|\\|!Y|\\|!B|\\|!M|\\|!C|\\|!W|\\|!X|\\|\\[R|\\|\\[G|\\|\, re.DOTALL)
+ansi_sub = re.compile('\\|n|\\|/|\\|\\-|\\|>|\\|_|\\|\\*|\\|\\^|\\|u|\\|r|\\|g|\\|y|\\|b|\\|m|\\|c|\\|w|\\|x|\\|R|\\|G|\\|Y|\\|B|\\|M|\\|C|\\|W|\\|X|\\|h|\\|H|\\|!R|\\|!G|\\|!Y|\\|!B|\\|!M|\\|!C|\\|!W|\\|!X|\\|\\[R|\\|\\[G, re.DOTALL)
@@ -130,7 +171,7 @@ an extra | for Merc-style codes
-
-
ansi_map_dict = {'|!B': '\x1b[34m', '|!C': '\x1b[36m', '|!G': '\x1b[32m', '|!M': '\x1b[35m', '|!R': '\x1b[31m', '|!W': '\x1b[37m', '|!X': '\x1b[30m', '|!Y': '\x1b[33m', '|*': '\x1b[7m', '|-': '\t', '|/': '\r\n', '|B': '\x1b[22m\x1b[34m', '|C': '\x1b[22m\x1b[36m', '|G': '\x1b[22m\x1b[32m', '|H': '\x1b[22m', '|M': '\x1b[22m\x1b[35m', '|R': '\x1b[22m\x1b[31m', '|W': '\x1b[22m\x1b[37m', '|X': '\x1b[22m\x1b[30m', '|Y': '\x1b[22m\x1b[33m', '|[B': '\x1b[44m', '|[C': '\x1b[46m', '|[G': '\x1b[42m', '|[M': '\x1b[45m', '|[R': '\x1b[41m', '|[W': '\x1b[47m', '|[X': '\x1b[40m', '|[Y': '\x1b[43m', '|^': '\x1b[5m', '|_': ' ', '|b': '\x1b[1m\x1b[34m', '|c': '\x1b[1m\x1b[36m', '|g': '\x1b[1m\x1b[32m', '|h': '\x1b[1m', '|m': '\x1b[1m\x1b[35m', '|n': '\x1b[0m', '|r': '\x1b[1m\x1b[31m', '|u': '\x1b[4m', '|w': '\x1b[1m\x1b[37m', '|x': '\x1b[1m\x1b[30m', '|y': '\x1b[1m\x1b[33m'}
+ansi_map_dict = {'|!B': '\x1b[34m', '|!C': '\x1b[36m', '|!G': '\x1b[32m', '|!M': '\x1b[35m', '|!R': '\x1b[31m', '|!W': '\x1b[37m', '|!X': '\x1b[30m', '|!Y': '\x1b[33m', '|*': '\x1b[7m', '|-': '\t', '|/': '\r\n', '|>': ' ', '|B': '\x1b[22m\x1b[34m', '|C': '\x1b[22m\x1b[36m', '|G': '\x1b[22m\x1b[32m', '|H': '\x1b[22m', '|M': '\x1b[22m\x1b[35m', '|R': '\x1b[22m\x1b[31m', '|W': '\x1b[22m\x1b[37m', '|X': '\x1b[22m\x1b[30m', '|Y': '\x1b[22m\x1b[33m', '|[B': '\x1b[44m', '|[C': '\x1b[46m', '|[G': '\x1b[42m', '|[M': '\x1b[45m', '|[R': '\x1b[41m', '|[W': '\x1b[47m', '|[X': '\x1b[40m', '|[Y': '\x1b[43m', '|^': '\x1b[5m', '|_': ' ', '|b': '\x1b[1m\x1b[34m', '|c': '\x1b[1m\x1b[36m', '|g': '\x1b[1m\x1b[32m', '|h': '\x1b[1m', '|m': '\x1b[1m\x1b[35m', '|n': '\x1b[0m', '|r': '\x1b[1m\x1b[31m', '|u': '\x1b[4m', '|w': '\x1b[1m\x1b[37m', '|x': '\x1b[1m\x1b[30m', '|y': '\x1b[1m\x1b[33m'}
@@ -845,6 +886,7 @@ with.
+
@@ -867,6 +909,14 @@ with.
+
+
+
@@ -273,7 +274,7 @@ indentation.
-
-
aliases = [':>', ':x', ':UU', ':', ':!', ':w', ':=', ':dd', ':S', ':DD', ':p', ':::', ':wq', ':u', ':I', ':A', ':uu', ':h', ':y', ':echo', ':r', ':fi', ':q!', ':s', ':dw', '::', ':j', ':fd', ':i', ':<', ':q', ':f']
+aliases = [':', ':j', ':fi', ':r', ':::', ':fd', ':h', ':y', ':p', ':DD', ':I', ':>', ':<', ':s', ':echo', ':i', ':=', ':dd', ':S', ':q!', ':q', ':A', ':f', ':w', ':uu', ':!', ':UU', ':u', ':dw', ':wq', '::', ':x']
@@ -301,7 +302,7 @@ efficient presentation.
-
-
search_index_entry = {'aliases': ':> :x :UU : :! :w := :dd :S :DD :p ::: :wq :u :I :A :uu :h :y :echo :r :fi :q! :s :dw :: :j :fd :i :< :q :f', 'category': 'general', 'key': ':editor_command_group', 'tags': '', 'text': '\n Commands for the editor\n '}
+search_index_entry = {'aliases': ': :j :fi :r ::: :fd :h :y :p :DD :I :> :< :s :echo :i := :dd :S :q! :q :A :f :w :uu :! :UU :u :dw :wq :: :x', 'category': 'general', 'key': ':editor_command_group', 'tags': '', 'text': '\n Commands for the editor\n '}
@@ -538,6 +539,7 @@ formatting information.
Evennia 0.9.5 »
evennia.utils.eveditor
+ develop branch
@@ -74,7 +75,7 @@ the caller.msg() construct every time the page is updated.
-
-
aliases = ['e', 'a', 'q', 'abort', 'next', 'quit', 'b', 'top', 'end', 't', 'n', 'back']
+aliases = ['e', 'n', 'q', 'next', 't', 'quit', 'back', 'top', 'b', 'end', 'a', 'abort']
@@ -100,7 +101,7 @@ the caller.msg() construct every time the page is updated.
-
-
search_index_entry = {'aliases': 'e a q abort next quit b top end t n back', 'category': 'general', 'key': '__noinput_command', 'tags': '', 'text': '\n Manipulate the text paging\n '}
+search_index_entry = {'aliases': 'e n q next t quit back top b end a abort', 'category': 'general', 'key': '__noinput_command', 'tags': '', 'text': '\n Manipulate the text paging\n '}
@@ -547,6 +548,7 @@ the evmore commands will be available when this is run).
Evennia 0.9.5 »
evennia.utils.evmore
+ develop branch
@@ -43,7 +44,10 @@ modules in Evennia. It also holds the idmapper in-memory caching
functionality.
|
+ load_module_prototypes() (in module evennia.prototypes.prototypes)
+
load_sync_data() (evennia.server.session.Session method)
loads() (in module evennia.server.portal.amp)
@@ -11736,6 +11741,8 @@
(evennia.server.portal.irc.IRCBotFactory method)
+ record_ip() (evennia.server.throttle.Throttle method)
+
RedButton (class in evennia.contrib.tutorial_examples.red_button)
RedButton.DoesNotExist
@@ -11842,6 +11849,8 @@
(evennia.scripts.tickerhandler.TickerHandler method)
(evennia.scripts.tickerhandler.TickerPool method)
+
+ (evennia.server.throttle.Throttle method)
(evennia.typeclasses.attributes.AttributeHandler method)
@@ -14057,6 +14066,8 @@
toint() (in module evennia.prototypes.protfuncs)
toString() (evennia.server.portal.amp.Compressed method)
+
+ touch() (evennia.server.throttle.Throttle method)
TradeHandler (class in evennia.contrib.barter)
@@ -14387,6 +14398,8 @@
unpuppet_all() (evennia.accounts.accounts.DefaultAccount method)
unpuppet_object() (evennia.accounts.accounts.DefaultAccount method)
+
+ unrecord_ip() (evennia.server.throttle.Throttle method)
unrepeat() (in module evennia.server.inputfuncs)
@@ -14408,10 +14421,10 @@
(evennia.utils.utils.LimitedSizeOrderedDict method)
- update_attribute() (evennia.typeclasses.attributes.IAttributeBackend method)
-
|
+ develop branch
@@ -40,7 +41,6 @@
Toc
@@ -218,6 +219,7 @@ course hard to actually mimic human user behavior. For this, actual real-game te
Evennia 1.0-dev »
Profiling
+ develop branch
@@ -213,6 +214,7 @@ instructions, use the following command to fix it:
Evennia 1.0-dev »
Quirks
+ develop branch
@@ -503,6 +504,7 @@ commands having any combination of the keys and/or aliases “kick”, “punch
Evennia 1.0-dev »
Command Sets
+ develop branch
@@ -214,6 +215,7 @@ for channel communication (since the default ChannelCommand instead logs to a fi
Evennia 1.0-dev »
Communications
+ develop branch
@@ -337,6 +338,7 @@ editor can be useful if you want to test the code you have typed but add new lin
Evennia 1.0-dev »
EvEditor
+ develop branch
@@ -290,6 +291,7 @@ add more. By default the following fields/attributes can be monitored:
Evennia 1.0-dev »
Inputfuncs
+ develop branch
@@ -640,6 +641,7 @@ interface. It’s stand-alone from the permissions described above.
Evennia 1.0-dev »
Locks
+ develop branch
@@ -226,6 +227,7 @@ basically the unchanged strings you enter to the Evennia 1.0-dev »
Nicks
+ develop branch
@@ -295,6 +296,7 @@ and display this as an error message. If this is not found, the Exit will instea
Evennia 1.0-dev »
Objects
+ develop branch
@@ -182,6 +183,7 @@ pseudo-softcode plugin aimed at developers wanting to script their game from ins
Evennia 1.0-dev »
Soft Code
+ develop branch
@@ -235,6 +236,7 @@ implementation, the relevant django “applications” in default Evennia are Evennia 1.0-dev »
Web Features
+ develop branch
@@ -213,6 +214,7 @@ UBBFWIuVDEZxC0M_2pM6ywO&dispatch=5885d80a13c0db1f8e263663d3faee8d66f31424b43
Evennia 1.0-dev »
Contributing
+ develop branch
@@ -278,6 +279,7 @@ directly the easiest way is to just wrap those with a multiple inheritance to yo
Evennia 1.0-dev »
Command Prompt
+ develop branch
@@ -581,6 +582,7 @@ square (E, G, M and O) are not in this circle. So we remove them.
Evennia 1.0-dev »
Coordinates
+ develop branch
@@ -109,6 +110,7 @@ as Evennia itself, unless the individual contributor has specifically defined ot
Evennia 1.0-dev »
Licensing
+ develop branch
@@ -306,6 +307,7 @@ programming curriculum for different skill levels
Evennia 1.0-dev »
Links
+ develop branch
@@ -286,6 +287,7 @@ port but this should be applicable also to other types of proxies (like nginx).<
Evennia 1.0-dev »
Apache Config
+ develop branch
@@ -176,6 +177,7 @@ name of the IRC channel you used (#evennia here).
Evennia 1.0-dev »
IRC
+ develop branch
@@ -432,8 +433,12 @@
BASE_GUEST_TYPECLASS = class_from_module(settings.BASE_GUEST_TYPECLASS)
del class_from_module
- # delayed starts
+ # delayed starts - important so as to not back-access evennia before it has
+ # finished initializing
GLOBAL_SCRIPTS.start()
+ from .prototypes import prototypes
+ prototypes.load_module_prototypes()
+ del prototypes
@@ -93,10 +94,10 @@
# Create throttles for too many account-creations and login attempts
CREATION_THROTTLE = Throttle(
- limit=settings.CREATION_THROTTLE_LIMIT, timeout=settings.CREATION_THROTTLE_TIMEOUT
+ name='creation', limit=settings.CREATION_THROTTLE_LIMIT, timeout=settings.CREATION_THROTTLE_TIMEOUT
)
LOGIN_THROTTLE = Throttle(
- limit=settings.LOGIN_THROTTLE_LIMIT, timeout=settings.LOGIN_THROTTLE_TIMEOUT
+ name='login', limit=settings.LOGIN_THROTTLE_LIMIT, timeout=settings.LOGIN_THROTTLE_TIMEOUT
)
@@ -1761,6 +1762,7 @@
evennia »
evennia.accounts.accounts
+ develop branch
@@ -250,10 +251,15 @@
quality = [mat[4] for mat in matches]
matches = matches[-quality.count(quality[-1]) :]
- if len(matches) > 1 and match_index is not None and 0 < match_index <= len(matches):
+ if len(matches) > 1 and match_index is not None:
# We couldn't separate match by quality, but we have an
# index argument to tell us which match to use.
- matches = [matches[match_index - 1]]
+ if 0 < match_index <= len(matches):
+ matches = [matches[match_index - 1]]
+ else:
+ # we tried to give an index outside of the range - this means
+ # a no-match
+ matches = []
# no matter what we have at this point, we have to return it.
return matches
@@ -302,6 +308,7 @@
evennia »
evennia.commands.cmdparser
+ develop branch
@@ -555,15 +556,16 @@
# cmd is a command set so merge all commands in that set
# to this one. We raise a visible error if we created
# an infinite loop (adding cmdset to itself somehow)
+ cmdset = cmd
try:
- cmd = self._instantiate(cmd)
+ cmdset = self._instantiate(cmdset)
except RuntimeError:
- string = "Adding cmdset %(cmd)s to %(class)s lead to an "
- string += "infinite loop. When adding a cmdset to another, "
- string += "make sure they are not themself cyclically added to "
- string += "the new cmdset somewhere in the chain."
- raise RuntimeError(_(string) % {"cmd": cmd, "class": self.__class__})
- cmds = cmd.commands
+ err = ("Adding cmdset {cmdset} to {cls} lead to an "
+ "infinite loop. When adding a cmdset to another, "
+ "make sure they are not themself cyclically added to "
+ "the new cmdset somewhere in the chain.")
+ raise RuntimeError(_(err.format(cmdset=cmdset, cls=self.__class__)))
+ cmds = cmdset.commands
elif is_iter(cmd):
cmds = [self._instantiate(c) for c in cmd]
else:
@@ -572,7 +574,7 @@
system_commands = self.system_commands
for cmd in cmds:
# add all commands
- if not hasattr(cmd, "obj"):
+ if not hasattr(cmd, "obj") or cmd.obj is None:
cmd.obj = self.cmdsetobj
try:
ic = commands.index(cmd)
@@ -757,6 +759,7 @@
evennia »
evennia.commands.cmdset
+ develop branch
@@ -345,7 +346,7 @@
character_candidates = []
if not self.args:
- character_candidates = [account.db._last_puppet] or []
+ character_candidates = [account.db._last_puppet] if account.db._last_puppet else []
if not character_candidates:
self.msg("Usage: ic <character>")
return
@@ -1138,6 +1139,7 @@
evennia »
evennia.commands.default.account
+ develop branch
@@ -883,21 +884,30 @@
return
if service.name[:7] == "Evennia":
if delmode:
- caller.msg("You cannot remove a core Evennia service (named 'Evennia***').")
+ caller.msg("You cannot remove a core Evennia service (named 'Evennia*').")
return
- string = "You seem to be shutting down a core Evennia service (named 'Evennia***'). Note that"
- string += "stopping some TCP port services will *not* disconnect users *already*"
- string += "connected on those ports, but *may* instead cause spurious errors for them. To "
- string += "safely and permanently remove ports, change settings file and restart the server."
+ string = ("|RYou seem to be shutting down a core Evennia "
+ "service (named 'Evennia*').\nNote that stopping "
+ "some TCP port services will *not* disconnect users "
+ "*already* connected on those ports, but *may* "
+ "instead cause spurious errors for them.\nTo safely "
+ "and permanently remove ports, change settings file "
+ "and restart the server.|n\n")
caller.msg(string)
if delmode:
service.stopService()
service_collection.removeService(service)
- caller.msg("Stopped and removed service '%s'." % self.args)
+ caller.msg("|gStopped and removed service '%s'.|n" % self.args)
else:
- service.stopService()
- caller.msg("Stopped service '%s'." % self.args)
+ caller.msg(f"Stopping service '{self.args}'...")
+ try:
+ service.stopService()
+ except Exception as err:
+ caller.msg(f"|rErrors were reported when stopping this service{err}.\n"
+ "If there are remaining problems, try reloading "
+ "or rebooting the server.")
+ caller.msg("|g... Stopped service '%s'.|n" % self.args)
return
if switches[0] == "start":
@@ -905,8 +915,14 @@
if service.running:
caller.msg("That service is already running.")
return
- caller.msg("Starting service '%s'." % self.args)
- service.startService()
+ caller.msg(f"Starting service '{self.args}' ...")
+ try:
+ service.startService()
+ except Exception as err:
+ caller.msg(f"|rErrors were reported when starting this service{err}.\n"
+ "If there are remaining problems, try reloading the server, changing the "
+ "settings if it's a non-standard service.|n")
+ caller.msg("|gService started.|n")
@@ -430,7 +431,7 @@
(aka MUDs, MUSHes, MUX, MOOs...). It is open-source and |wfree to use|n, also for
commercial projects (BSD license).
- Out of the box, Evennia provides a |wfull, if empty game|n. Whereas you can play
+ Out of the box, Evennia provides a |wworking, if empty game|n. Whereas you can play
via traditional telnet MUD-clients, the server runs your game's website and
offers a |wHTML5 webclient|n so that people can play your game in their browser
without downloading anything extra.
@@ -866,6 +867,7 @@
evennia »
evennia.contrib.tutorial_world.intro_menu
+ develop branch
@@ -507,19 +508,25 @@
# strips the number
match_number, searchdata = match.group("number"), match.group("name")
match_number = int(match_number) - 1
- match_number = match_number if match_number >= 0 else None
if match_number is not None or not exact:
# run search again, with the exactness set by call
matches = _searcher(searchdata, candidates, typeclass, exact=exact)
# deal with result
- if len(matches) > 1 and match_number is not None:
+ if len(matches) == 1 and match_number is not None and match_number != 0:
+ # this indicates trying to get a single match with a match-number
+ # targeting some higher-number match (like 2-box when there is only
+ # one box in the room). This leads to a no-match.
+ matches = []
+ elif len(matches) > 1 and match_number is not None:
# multiple matches, but a number was given to separate them
- try:
+ if 0 <= match_number < len(matches):
+ # limit to one match
matches = [matches[match_number]]
- except IndexError:
- # match number not matching anything
- pass
+ else:
+ # a number was given outside of range. This means a no-match.
+ matches = []
+
# return a list (possibly empty)
return matches
@@ -677,6 +684,7 @@
evennia »
evennia.objects.manager
+ develop branch
@@ -435,7 +436,8 @@
a global search.
- `me,self`: self-reference to this object
- `<num>-<string>` - can be used to differentiate
- between multiple same-named matches
+ between multiple same-named matches. The exact form of this input
+ is given by `settings.SEARCH_MULTIMATCH_REGEX`.
global_search (bool): Search all objects globally. This overrules 'location' data.
use_nicks (bool): Use nickname-replace (nicktype "object") on `searchdata`.
typeclass (str or Typeclass, or list of either): Limit search only
@@ -2791,6 +2793,7 @@
evennia »
evennia.objects.objects
+ develop branch
@@ -185,35 +186,41 @@
# module-based prototypes
- for mod in settings.PROTOTYPE_MODULES:
- # to remove a default prototype, override it with an empty dict.
- # internally we store as (key, desc, locks, tags, prototype_dict)
- prots = []
- for variable_name, prot in all_from_module(mod).items():
- if isinstance(prot, dict):
- if "prototype_key" not in prot:
- prot["prototype_key"] = variable_name.lower()
- prots.append((prot["prototype_key"], homogenize_prototype(prot)))
- # assign module path to each prototype_key for easy reference
- _MODULE_PROTOTYPE_MODULES.update({prototype_key.lower(): mod for prototype_key, _ in prots})
- # make sure the prototype contains all meta info
- for prototype_key, prot in prots:
- actual_prot_key = prot.get("prototype_key", prototype_key).lower()
- prot.update(
- {
- "prototype_key": actual_prot_key,
- "prototype_desc": prot["prototype_desc"] if "prototype_desc" in prot else mod,
- "prototype_locks": (
- prot["prototype_locks"]
- if "prototype_locks" in prot
- else "use:all();edit:false()"
- ),
- "prototype_tags": list(
- set(list(make_iter(prot.get("prototype_tags", []))) + ["module"])
- ),
- }
- )
- _MODULE_PROTOTYPES[actual_prot_key] = prot
+ [docs]def load_module_prototypes():
+ """
+ This is called by `evennia.__init__` as Evennia initializes. It's important
+ to do this late so as to not interfere with evennia initialization.
+
+ """
+ for mod in settings.PROTOTYPE_MODULES:
+ # to remove a default prototype, override it with an empty dict.
+ # internally we store as (key, desc, locks, tags, prototype_dict)
+ prots = []
+ for variable_name, prot in all_from_module(mod).items():
+ if isinstance(prot, dict):
+ if "prototype_key" not in prot:
+ prot["prototype_key"] = variable_name.lower()
+ prots.append((prot["prototype_key"], homogenize_prototype(prot)))
+ # assign module path to each prototype_key for easy reference
+ _MODULE_PROTOTYPE_MODULES.update({prototype_key.lower(): mod for prototype_key, _ in prots})
+ # make sure the prototype contains all meta info
+ for prototype_key, prot in prots:
+ actual_prot_key = prot.get("prototype_key", prototype_key).lower()
+ prot.update(
+ {
+ "prototype_key": actual_prot_key,
+ "prototype_desc": prot["prototype_desc"] if "prototype_desc" in prot else mod,
+ "prototype_locks": (
+ prot["prototype_locks"]
+ if "prototype_locks" in prot
+ else "use:all();edit:false()"
+ ),
+ "prototype_tags": list(
+ set(list(make_iter(prot.get("prototype_tags", []))) + ["module"])
+ ),
+ }
+ )
+ _MODULE_PROTOTYPES[actual_prot_key] = prot
# Db-based prototypes
@@ -970,7 +977,10 @@
value = validator(value[0](*make_iter(args)))
else:
value = validator(value)
- return protfunc_parser(value)
+ result = protfunc_parser(value)
+ if result != value:
+ return validator(result)
+ return result
@@ -134,7 +135,7 @@
[docs] def at_update(self, obj, fieldname):
"""
- Called by the field as it saves.
+ Called by the field/attribute as it saves.
"""
to_delete = []
@@ -289,6 +290,7 @@
evennia »
evennia.scripts.monitorhandler
+ develop branch
@@ -121,9 +122,15 @@
_ERROR_ADD_TICKER = """TickerHandler: Tried to add an invalid ticker:
- {storekey}
+ {store_key}
Ticker was not added."""
+ _ERROR_ADD_TICKER_SUB_SECOND = """You are trying to add a ticker running faster
+ than once per second. This is not supported and also probably not useful:
+ Spamming messages to the user faster than once per second serves no purpose in
+ a text-game, and if you want to update some property, consider doing so
+ on-demand rather than using a ticker.
+ """
[docs]class Ticker(object):
"""
@@ -400,7 +407,8 @@
obj (Object, tuple or None): Subscribing object if any. If a tuple, this is
a packed_obj tuple from dbserialize.
path (str or None): Python-path to callable, if any.
- interval (int): Ticker interval.
+ interval (int): Ticker interval. Floats will be converted to
+ nearest lower integer value.
callfunc (callable or str): This is either the callable function or
the name of the method to call. Note that the callable is never
stored in the key; that is uniquely identified with the python-path.
@@ -419,6 +427,9 @@
`idstring` and `persistent` are integers, strings and bools respectively.
"""
+ if interval < 1:
+ raise RuntimeError(_ERROR_ADD_TICKER_SUB_SECOND)
+
interval = int(interval)
persistent = bool(persistent)
packed_obj = pack_dbobj(obj)
@@ -717,6 +728,7 @@
evennia »
evennia.scripts.tickerhandler
+ develop branch
@@ -562,9 +563,8 @@
session=session,
)
else:
- # kwargs provided: persist them to the account object
- for key, value in kwargs.items():
- clientoptions[key] = value
+ # kwargs provided: persist them to the account object.
+ clientoptions.update(kwargs)
# OOB protocol-specific aliases and wrappers
@@ -702,6 +702,7 @@
evennia »
evennia.server.inputfuncs
+ develop branch
@@ -87,6 +88,14 @@
AMP_MAXLEN = amp.MAX_VALUE_LENGTH # max allowed data length in AMP protocol (cannot be changed)
+# amp internal
+ASK = b'_ask'
+ANSWER = b'_answer'
+ERROR = b'_error'
+ERROR_CODE = b'_error_code'
+ERROR_DESCRIPTION = b'_error_description'
+UNKNOWN_ERROR_CODE = b'UNKNOWN'
+
# buffers
_SENDBATCH = defaultdict(list)
_MSGBUFFER = defaultdict(list)
@@ -342,6 +351,47 @@
# later twisted amp has its own __init__
super(AMPMultiConnectionProtocol, self).__init__(*args, **kwargs)
+ def _commandReceived(self, box):
+ """
+ This overrides the default Twisted AMP error handling which is not
+ passing enough of the traceback through to the other side. Instead we
+ add a specific log of the problem on the erroring side.
+
+ """
+ def formatAnswer(answerBox):
+ answerBox[ANSWER] = box[ASK]
+ return answerBox
+
+ def formatError(error):
+ if error.check(amp.RemoteAmpError):
+ code = error.value.errorCode
+ desc = error.value.description
+
+ # Evennia extra logging
+ desc += " (error logged on other side)"
+ _get_logger().log_err(f"AMP caught exception ({desc}):\n{error.value}")
+
+ if isinstance(desc, str):
+ desc = desc.encode("utf-8", "replace")
+ if error.value.fatal:
+ errorBox = amp.QuitBox()
+ else:
+ errorBox = amp.AmpBox()
+ else:
+ errorBox = amp.QuitBox()
+ _get_logger().log_err(error) # server-side logging if unhandled error
+ code = UNKNOWN_ERROR_CODE
+ desc = b"Unknown Error"
+ errorBox[ERROR] = box[ASK]
+ errorBox[ERROR_DESCRIPTION] = desc
+ errorBox[ERROR_CODE] = code
+ return errorBox
+ deferred = self.dispatchCommand(box)
+ if ASK in box:
+ deferred.addCallbacks(formatAnswer, formatError)
+ deferred.addCallback(self._safeEmit)
+ deferred.addErrback(self.unhandledError)
+
[docs] def dataReceived(self, data):
"""
Handle non-AMP messages, such as HTTP communication.
@@ -426,7 +476,7 @@
"""
e.trap(Exception)
_get_logger().log_err(
- "AMP Error for {info}: {trcbck} {err}".format(
+ "AMP Error from {info}: {trcbck} {err}".format(
info=info, trcbck=e.getTraceback(), err=e.getErrorMessage()
)
)
@@ -575,6 +625,7 @@
evennia »
evennia.server.portal.amp
+ develop branch
@@ -128,7 +129,6 @@
super().dataReceived(data)
except ValueError as err:
from evennia.utils import logger
-
logger.log_err(f"Malformed telnet input: {err}")
@@ -158,6 +159,10 @@
self.sessid = old_session.sessid
self.sessionhandler.disconnect(old_session)
+ self.protocol_flags["CLIENTNAME"] = "Evennia Webclient (websocket)"
+ self.protocol_flags["UTF-8"] = True
+ self.protocol_flags["OOB"] = True
+
# watch for dead links
self.transport.setTcpKeepAlive(1)
# actually do the connection
@@ -387,6 +392,7 @@
evennia »
evennia.server.portal.webclient
+ develop branch
@@ -39,7 +40,8 @@
Source code for evennia.server.throttle
-from collections import defaultdict, deque
+from django.core.cache import caches
+from collections import deque
from evennia.utils import logger
import time
@@ -53,8 +55,8 @@
This version of the throttle is usable by both the terminal server as well
as the web server, imposes limits on memory consumption by using deques
- with length limits instead of open-ended lists, and removes sparse keys when
- no recent failures have been recorded.
+ with length limits instead of open-ended lists, and uses native Django
+ caches for automatic key eviction and persistence configurability.
"""
error_msg = "Too many failed attempts; you must wait a few minutes before trying again."
@@ -64,6 +66,7 @@
Allows setting of throttle parameters.
Keyword Args:
+ name (str): Name of this throttle.
limit (int): Max number of failures before imposing limiter
timeout (int): number of timeout seconds after
max number of tries has been reached.
@@ -71,9 +74,37 @@
rolling window; this is NOT the same as the limit after which
the throttle is imposed!
"""
- self.storage = defaultdict(deque)
- self.cache_size = self.limit = kwargs.get("limit", 5)
+ try:
+ self.storage = caches['throttle']
+ except Exception as e:
+ logger.log_trace("Throttle: Errors encountered; using default cache.")
+ self.storage = caches['default']
+
+ self.name = kwargs.get('name', 'undefined-throttle')
+ self.limit = kwargs.get("limit", 5)
+ self.cache_size = kwargs.get('cache_size', self.limit)
self.timeout = kwargs.get("timeout", 5 * 60)
+
+ [docs] def get_cache_key(self, *args, **kwargs):
+ """
+ Creates a 'prefixed' key containing arbitrary terms to prevent key
+ collisions in the same namespace.
+
+ """
+ return '-'.join((self.name, *args))
+
+ [docs] def touch(self, key, *args, **kwargs):
+ """
+ Refreshes the timeout on a given key and ensures it is recorded in the
+ key register.
+
+ Args:
+ key(str): Key of entry to renew.
+
+ """
+ cache_key = self.get_cache_key(key)
+ if self.storage.touch(cache_key, self.timeout):
+ self.record_key(key)
[docs] def get(self, ip=None):
"""
@@ -91,9 +122,18 @@
"""
if ip:
- return self.storage.get(ip, deque(maxlen=self.cache_size))
+ cache_key = self.get_cache_key(str(ip))
+ return self.storage.get(cache_key, deque(maxlen=self.cache_size))
else:
- return self.storage
+ keys_key = self.get_cache_key('keys')
+ keys = self.storage.get_or_set(keys_key, set(), self.timeout)
+ data = self.storage.get_many((self.get_cache_key(x) for x in keys))
+
+ found_keys = set(data.keys())
+ if len(keys) != len(found_keys):
+ self.storage.set(keys_key, found_keys, self.timeout)
+
+ return data
[docs] def update(self, ip, failmsg="Exceeded threshold."):
"""
@@ -108,24 +148,77 @@
None
"""
+ cache_key = self.get_cache_key(ip)
+
# Get current status
previously_throttled = self.check(ip)
- # Enforce length limits
- if not self.storage[ip].maxlen:
- self.storage[ip] = deque(maxlen=self.cache_size)
-
- self.storage[ip].append(time.time())
+ # Get previous failures, if any
+ entries = self.storage.get(cache_key, [])
+ entries.append(time.time())
+
+ # Store updated record
+ self.storage.set(cache_key, deque(entries, maxlen=self.cache_size), self.timeout)
# See if this update caused a change in status
currently_throttled = self.check(ip)
# If this makes it engage, log a single activation event
if not previously_throttled and currently_throttled:
- logger.log_sec(
- "Throttle Activated: %s (IP: %s, %i hits in %i seconds.)"
- % (failmsg, ip, self.limit, self.timeout)
- )
+ logger.log_sec(f"Throttle Activated: {failmsg} (IP: {ip}, {self.limit} hits in {self.timeout} seconds.)")
+
+ self.record_ip(ip)
+
+[docs] def remove(self, ip, *args, **kwargs):
+ """
+ Clears data stored for an IP from the throttle.
+
+ Args:
+ ip(str): IP to clear.
+
+ """
+ exists = self.get(ip)
+ if not exists: return False
+
+ cache_key = self.get_cache_key(ip)
+ self.storage.delete(cache_key)
+ self.unrecord_ip(ip)
+
+ # Return True if NOT exists
+ return ~bool(self.get(ip))
+
+[docs] def record_ip(self, ip, *args, **kwargs):
+ """
+ Tracks keys as they are added to the cache (since there is no way to
+ get a list of keys after-the-fact).
+
+ Args:
+ ip(str): IP being added to cache. This should be the original
+ IP, not the cache-prefixed key.
+
+ """
+ keys_key = self.get_cache_key('keys')
+ keys = self.storage.get(keys_key, set())
+ keys.add(ip)
+ self.storage.set(keys_key, keys, self.timeout)
+ return True
+
+[docs] def unrecord_ip(self, ip, *args, **kwargs):
+ """
+ Forces removal of a key from the key registry.
+
+ Args:
+ ip(str): IP to remove from list of keys.
+
+ """
+ keys_key = self.get_cache_key('keys')
+ keys = self.storage.get(keys_key, set())
+ try:
+ keys.remove(ip)
+ self.storage.set(keys_key, keys, self.timeout)
+ return True
+ except KeyError:
+ return False
[docs] def check(self, ip):
"""
@@ -143,17 +236,20 @@
"""
now = time.time()
ip = str(ip)
+
+ cache_key = self.get_cache_key(ip)
# checking mode
- latest_fails = self.storage[ip]
+ latest_fails = self.storage.get(cache_key)
if latest_fails and len(latest_fails) >= self.limit:
# too many fails recently
if now - latest_fails[-1] < self.timeout:
# too soon - timeout in play
+ self.touch(cache_key)
return True
else:
# timeout has passed. clear faillist
- del self.storage[ip]
+ self.remove(ip)
return False
else:
return False
@@ -202,6 +298,7 @@
evennia »
evennia.server.throttle
+ develop branch
@@ -479,7 +480,7 @@
"""
key = key.strip().lower() if key else None
- category = category.strip().lower() if category else None
+ category = category.strip().lower() if category is not None else None
if key:
return self._get_cache_key(key, category)
return self._get_cache_category(category)
@@ -1587,6 +1588,7 @@
evennia »
evennia.typeclasses.attributes
+ develop branch
@@ -42,19 +43,64 @@
"""
ANSI - Gives colour to text.
-Use the codes defined in ANSIPARSER in your text
-to apply colour to text according to the ANSI standard.
+Use the codes defined in the *ANSIParser* class to apply colour to text. The
+`parse_ansi` function in this module parses text for markup and `strip_ansi`
+removes it.
-Examples:
+You should usually not need to call `parse_ansi` explicitly; it is run by
+Evennia just before returning data to/from the user. Alternative markup is
+possible by overriding the parser class (see also contrib/ for deprecated
+markup schemes).
+
+
+Supported standards:
+
+- ANSI 8 bright and 8 dark fg (foreground) colors
+- ANSI 8 dark bg (background) colors
+- 'ANSI' 8 bright bg colors 'faked' with xterm256 (bright bg not included in ANSI standard)
+- Xterm256 - 255 fg/bg colors + 26 greyscale fg/bg colors
+
+## Markup
+
+ANSI colors: `r` ed, `g` reen, `y` ellow, `b` lue, `m` agenta, `c` yan, `n` ormal (no color). Capital
+letters indicate the 'dark' variant.
+
+- `|r` fg bright red
+- `|R` fg dark red
+- `|[r` bg bright red
+- `|[R` bg dark red
+- `|[R|g` bg dark red, fg bright green
```python
"This is |rRed text|n and this is normal again."
+
```
-Mostly you should not need to call `parse_ansi()` explicitly;
-it is run by Evennia just before returning data to/from the
-user. Depreciated example forms are available by extending
-the ansi mapping.
+Xterm256 colors are given as RGB (Red-Green-Blue), with values 0-5:
+
+- `|500` fg bright red
+- `|050` fg bright green
+- `|005` fg bright blue
+- `|110` fg dark brown
+- `|425` fg pink
+- `|[431` bg orange
+
+Xterm256 greyscale:
+
+- `|=a` fg black
+- `|=g` fg dark grey
+- `|=o` fg middle grey
+- `|=v` fg bright grey
+- `|=z` fg white
+- `|[=r` bg middle grey
+
+```python
+"This is |500Red text|n and this is normal again."
+"This is |[=jText on dark grey background"
+
+```
+
+----
"""
import functools
@@ -126,8 +172,7 @@
to ANSI command sequences
We also allow to escape colour codes
- by prepending with a \ for xterm256,
- an extra | for Merc-style codes
+ by prepending with an extra `|`.
"""
@@ -138,6 +183,7 @@
(r"|n", ANSI_NORMAL), # reset
(r"|/", ANSI_RETURN), # line break
(r"|-", ANSI_TAB), # tab
+ (r"|>", ANSI_SPACE * 4), # indent (4 spaces)
(r"|_", ANSI_SPACE), # space
(r"|*", ANSI_INVERSE), # invert
(r"|^", ANSI_BLINK), # blinking text (very annoying and not supported by all clients)
@@ -567,6 +613,13 @@
return string.replace("{", "{{").replace("|", "||")
+# ------------------------------------------------------------
+#
+# ANSIString - ANSI-aware string class
+#
+# ------------------------------------------------------------
+
+
def _spacing_preflight(func):
"""
This wrapper function is used to do some preflight checks on
@@ -937,9 +990,23 @@
replayed.
"""
- slice_indexes = self._char_indexes[slc]
+ char_indexes = self._char_indexes
+ slice_indexes = char_indexes[slc]
# If it's the end of the string, we need to append final color codes.
if not slice_indexes:
+ # if we find no characters it may be because we are just outside
+ # of the interval, using an open-ended slice. We must replay all
+ # of the escape characters until/after this point.
+ if char_indexes:
+ if slc.start is None and slc.stop is None:
+ # a [:] slice of only escape characters
+ return ANSIString(self._raw_string[slc])
+ if slc.start is None:
+ # this is a [:x] slice
+ return ANSIString(self._raw_string[:char_indexes[0]])
+ if slc.stop is None:
+ # a [x:] slice
+ return ANSIString(self._raw_string[char_indexes[-1] + 1:])
return ANSIString("")
try:
string = self[slc.start or 0]._raw_string
@@ -959,7 +1026,7 @@
# raw_string not long enough
pass
if i is not None:
- append_tail = self._get_interleving(self._char_indexes.index(i) + 1)
+ append_tail = self._get_interleving(char_indexes.index(i) + 1)
else:
append_tail = ""
return ANSIString(string + append_tail, decoded=True)
@@ -1484,6 +1551,7 @@
evennia »
evennia.utils.ansi
+ develop branch
@@ -341,6 +342,10 @@
def has_key(self, key):
return key in self._data
+ @_save
+ def update(self, *args, **kwargs):
+ self._data.update(*args, **kwargs)
+
class _SaverSet(_SaverMutable, MutableSet):
"""
@@ -836,6 +841,7 @@
evennia »
evennia.utils.dbserialize
+ develop branch
@@ -206,9 +207,12 @@
def _to_ansi(obj, regexable=False):
"convert to ANSIString"
- if isinstance(obj, str):
+ if isinstance(obj, ANSIString):
+ return obj
+ elif isinstance(obj, str):
# since ansi will be parsed twice (here and in the normal ansi send), we have to
- # escape the |-structure twice.
+ # escape the |-structure twice. TODO: This is tied to the default color-tag syntax
+ # which is not ideal for those wanting to replace/extend it ...
obj = _ANSI_ESCAPE.sub(r"||||", obj)
if isinstance(obj, dict):
return dict((key, _to_ansi(value, regexable=regexable)) for key, value in obj.items())
@@ -218,7 +222,7 @@
return ANSIString(obj, regexable=regexable)
-
@@ -586,6 +553,7 @@
evennia »
evennia.utils.evform
+ develop branch
@@ -408,7 +409,7 @@
logfile.LogFile.rotate(self)
return
lines = tail_log_file(self.path, 0, self.num_lines_to_append)
- logfile.LogFile.rotate(self)
+ super().rotate()
for line in lines:
self.write(line)
@@ -618,6 +619,7 @@
evennia »
evennia.utils.logger
+ develop branch
@@ -138,7 +139,7 @@
re_blink = re.compile("(?:%s)(.*?)(?=%s|%s)" % (blink.replace("[", r"\["), fgstop, bgstop))
re_inverse = re.compile("(?:%s)(.*?)(?=%s|%s)" % (inverse.replace("[", r"\["), fgstop, bgstop))
re_string = re.compile(
- r"(?P<htmlchars>[<&>])|(?P<firstspace>(?<=\S) )|(?P<space> [ \t]+)|"
+ r"(?P<htmlchars>[<&>])|(?P<tab>[\t]+)|(?P<space> +)|"
r"(?P<spacestart>^ )|(?P<lineend>\r\n|\r|\n)",
re.S | re.M | re.I,
)
@@ -348,13 +349,12 @@
return html_escape(cdict["htmlchars"])
elif cdict["lineend"]:
return "<br>"
- elif cdict["firstspace"]:
- return " "
- elif cdict["space"] == "\t":
- return " " if self.tabstop == 1 else " " + " " * self.tabstop
+ elif cdict["tab"]:
+ text = cdict["tab"].replace("\t", " " + " " * (self.tabstop - 1))
+ return text
elif cdict["space"] or cdict["spacestart"]:
- text = match.group().replace("\t", " " * self.tabstop)
- text = text.replace(" ", " ")
+ text = cdict["space"]
+ text = " " if len(text) == 1 else " " + text[1:].replace(" ", " ")
return text
return None
@@ -453,6 +453,7 @@
evennia »
evennia.utils.text2html
+ develop branch
@@ -528,7 +529,7 @@ You can specify the /force switch to bypass this confirmation.
-
-
aliases = ['del', 'delete']
+aliases = ['delete', 'del']
@@ -569,7 +570,7 @@ You can specify the /force switch to bypass this confirmation.
-
-
search_index_entry = {'aliases': 'del delete', 'category': 'building', 'key': 'destroy', 'tags': '', 'text': '\n permanently delete objects\n\n Usage:\n destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...]\n\n Switches:\n override - The destroy command will usually avoid accidentally\n destroying account objects. This switch overrides this safety.\n force - destroy without confirmation.\n Examples:\n destroy house, roof, door, 44-78\n destroy 5-10, flower, 45\n destroy/force north\n\n Destroys one or many objects. If dbrefs are used, a range to delete can be\n given, e.g. 4-10. Also the end points will be deleted. This command\n displays a confirmation before destroying, to make sure of your choice.\n You can specify the /force switch to bypass this confirmation.\n '}
+search_index_entry = {'aliases': 'delete del', 'category': 'building', 'key': 'destroy', 'tags': '', 'text': '\n permanently delete objects\n\n Usage:\n destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...]\n\n Switches:\n override - The destroy command will usually avoid accidentally\n destroying account objects. This switch overrides this safety.\n force - destroy without confirmation.\n Examples:\n destroy house, roof, door, 44-78\n destroy 5-10, flower, 45\n destroy/force north\n\n Destroys one or many objects. If dbrefs are used, a range to delete can be\n given, e.g. 4-10. Also the end points will be deleted. This command\n displays a confirmation before destroying, to make sure of your choice.\n You can specify the /force switch to bypass this confirmation.\n '}
@@ -1267,7 +1268,7 @@ server settings.
-
-
aliases = ['swap', 'update', 'parent', 'type']
+aliases = ['type', 'swap', 'update', 'parent']
@@ -1298,7 +1299,7 @@ server settings.
-
-
search_index_entry = {'aliases': 'swap update parent type', 'category': 'building', 'key': 'typeclass', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object.\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}
+search_index_entry = {'aliases': 'type swap update parent', 'category': 'building', 'key': 'typeclass', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object.\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}
@@ -1582,7 +1583,7 @@ one is given.
-
-
aliases = ['locate', 'search']
+aliases = ['search', 'locate']
@@ -1613,7 +1614,7 @@ one is given.
-
-
search_index_entry = {'aliases': 'locate search', 'category': 'building', 'key': 'find', 'tags': '', 'text': '\n search the database for objects\n\n Usage:\n find[/switches] <name or dbref or *account> [= dbrefmin[-dbrefmax]]\n locate - this is a shorthand for using the /loc switch.\n\n Switches:\n room - only look for rooms (location=None)\n exit - only look for exits (destination!=None)\n char - only look for characters (BASE_CHARACTER_TYPECLASS)\n exact - only exact matches are returned.\n loc - display object location if exists and match has one result\n startswith - search for names starting with the string, rather than containing\n\n Searches the database for an object of a particular name or exact #dbref.\n Use *accountname to search for an account. The switches allows for\n limiting object matches to certain game entities. Dbrefmin and dbrefmax\n limits matches to within the given dbrefs range, or above/below if only\n one is given.\n '}
+search_index_entry = {'aliases': 'search locate', 'category': 'building', 'key': 'find', 'tags': '', 'text': '\n search the database for objects\n\n Usage:\n find[/switches] <name or dbref or *account> [= dbrefmin[-dbrefmax]]\n locate - this is a shorthand for using the /loc switch.\n\n Switches:\n room - only look for rooms (location=None)\n exit - only look for exits (destination!=None)\n char - only look for characters (BASE_CHARACTER_TYPECLASS)\n exact - only exact matches are returned.\n loc - display object location if exists and match has one result\n startswith - search for names starting with the string, rather than containing\n\n Searches the database for an object of a particular name or exact #dbref.\n Use *accountname to search for an account. The switches allows for\n limiting object matches to certain game entities. Dbrefmin and dbrefmax\n limits matches to within the given dbrefs range, or above/below if only\n one is given.\n '}
@@ -1991,6 +1992,7 @@ displays a list of available prototypes.
Evennia 1.0-dev »
evennia.commands.default.building
+ develop branch
@@ -233,7 +234,7 @@ Use addcom/delcom to join and leave channels
-
-
aliases = ['all channels', 'comlist', 'chanlist', 'clist', 'channellist']
+aliases = ['all channels', 'channellist', 'chanlist', 'clist', 'comlist']
@@ -264,7 +265,7 @@ Use addcom/delcom to join and leave channels
-
-
search_index_entry = {'aliases': 'all channels comlist chanlist clist channellist', 'category': 'comms', 'key': 'channels', 'tags': '', 'text': "\n list all channels available to you\n\n Usage:\n channels\n clist\n comlist\n\n Lists all channels available to you, whether you listen to them or not.\n Use 'comlist' to only view your current channel subscriptions.\n Use addcom/delcom to join and leave channels\n "}
+search_index_entry = {'aliases': 'all channels channellist chanlist clist comlist', 'category': 'comms', 'key': 'channels', 'tags': '', 'text': "\n list all channels available to you\n\n Usage:\n channels\n clist\n comlist\n\n Lists all channels available to you, whether you listen to them or not.\n Use 'comlist' to only view your current channel subscriptions.\n Use addcom/delcom to join and leave channels\n "}
@@ -1067,6 +1068,7 @@ must be added to game settings.
Evennia 1.0-dev »
evennia.commands.default.comms
+ develop branch
@@ -204,7 +205,7 @@ for everyone to use, you need build privileges and the alias command.
-
-
aliases = ['nickname', 'nicks']
+aliases = ['nicks', 'nickname']
@@ -236,7 +237,7 @@ for everyone to use, you need build privileges and the alias command.
-
-
search_index_entry = {'aliases': 'nickname nicks', 'category': 'general', 'key': 'nick', 'tags': '', 'text': '\n define a personal alias/nick by defining a string to\n match and replace it with another on the fly\n\n Usage:\n nick[/switches] <string> [= [replacement_string]]\n nick[/switches] <template> = <replacement_template>\n nick/delete <string> or number\n nicks\n\n Switches:\n inputline - replace on the inputline (default)\n object - replace on object-lookup\n account - replace on account-lookup\n list - show all defined aliases (also "nicks" works)\n delete - remove nick by index in /list\n clearall - clear all nicks\n\n Examples:\n nick hi = say Hello, I\'m Sarah!\n nick/object tom = the tall man\n nick build $1 $2 = create/drop $1;$2\n nick tell $1 $2=page $1=$2\n nick tm?$1=page tallman=$1\n nick tm\\=$1=page tallman=$1\n\n A \'nick\' is a personal string replacement. Use $1, $2, ... to catch arguments.\n Put the last $-marker without an ending space to catch all remaining text. You\n can also use unix-glob matching for the left-hand side <string>:\n\n * - matches everything\n ? - matches 0 or 1 single characters\n [abcd] - matches these chars in any order\n [!abcd] - matches everything not among these chars\n \\= - escape literal \'=\' you want in your <string>\n\n Note that no objects are actually renamed or changed by this command - your nicks\n are only available to you. If you want to permanently add keywords to an object\n for everyone to use, you need build privileges and the alias command.\n\n '}
+search_index_entry = {'aliases': 'nicks nickname', 'category': 'general', 'key': 'nick', 'tags': '', 'text': '\n define a personal alias/nick by defining a string to\n match and replace it with another on the fly\n\n Usage:\n nick[/switches] <string> [= [replacement_string]]\n nick[/switches] <template> = <replacement_template>\n nick/delete <string> or number\n nicks\n\n Switches:\n inputline - replace on the inputline (default)\n object - replace on object-lookup\n account - replace on account-lookup\n list - show all defined aliases (also "nicks" works)\n delete - remove nick by index in /list\n clearall - clear all nicks\n\n Examples:\n nick hi = say Hello, I\'m Sarah!\n nick/object tom = the tall man\n nick build $1 $2 = create/drop $1;$2\n nick tell $1 $2=page $1=$2\n nick tm?$1=page tallman=$1\n nick tm\\=$1=page tallman=$1\n\n A \'nick\' is a personal string replacement. Use $1, $2, ... to catch arguments.\n Put the last $-marker without an ending space to catch all remaining text. You\n can also use unix-glob matching for the left-hand side <string>:\n\n * - matches everything\n ? - matches 0 or 1 single characters\n [abcd] - matches these chars in any order\n [!abcd] - matches everything not among these chars\n \\= - escape literal \'=\' you want in your <string>\n\n Note that no objects are actually renamed or changed by this command - your nicks\n are only available to you. If you want to permanently add keywords to an object\n for everyone to use, you need build privileges and the alias command.\n\n '}
@@ -259,7 +260,7 @@ inv
-
-
aliases = ['inv', 'i']
+aliases = ['i', 'inv']
@@ -290,7 +291,7 @@ inv
-
-
search_index_entry = {'aliases': 'inv i', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
+search_index_entry = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
@@ -640,7 +641,7 @@ automatically begin with your name.
-
-
aliases = ['emote', ':']
+aliases = [':', 'emote']
@@ -676,7 +677,7 @@ space.
-
-
search_index_entry = {'aliases': 'emote :', 'category': 'general', 'key': 'pose', 'tags': '', 'text': "\n strike a pose\n\n Usage:\n pose <pose text>\n pose's <pose text>\n\n Example:\n pose is standing by the wall, smiling.\n -> others will see:\n Tom is standing by the wall, smiling.\n\n Describe an action being taken. The pose text will\n automatically begin with your name.\n "}
+search_index_entry = {'aliases': ': emote', 'category': 'general', 'key': 'pose', 'tags': '', 'text': "\n strike a pose\n\n Usage:\n pose <pose text>\n pose's <pose text>\n\n Example:\n pose is standing by the wall, smiling.\n -> others will see:\n Tom is standing by the wall, smiling.\n\n Describe an action being taken. The pose text will\n automatically begin with your name.\n "}
@@ -699,7 +700,7 @@ which permission groups you are a member of.
-
-
aliases = ['groups', 'hierarchy']
+aliases = ['hierarchy', 'groups']
@@ -730,7 +731,7 @@ which permission groups you are a member of.
-
-
search_index_entry = {'aliases': 'groups hierarchy', 'category': 'general', 'key': 'access', 'tags': '', 'text': '\n show your current game access\n\n Usage:\n access\n\n This command shows you the permission hierarchy and\n which permission groups you are a member of.\n '}
+search_index_entry = {'aliases': 'hierarchy groups', 'category': 'general', 'key': 'access', 'tags': '', 'text': '\n show your current game access\n\n Usage:\n access\n\n This command shows you the permission hierarchy and\n which permission groups you are a member of.\n '}
@@ -786,6 +787,7 @@ which permission groups you are a member of.
Evennia 1.0-dev »
evennia.commands.default.general
+ develop branch
@@ -373,7 +374,7 @@ given, <nr> defaults to 10.
-
-
aliases = ['listobjects', 'db', 'stats', 'listobjs']
+aliases = ['db', 'listobjs', 'stats', 'listobjects']
@@ -399,7 +400,7 @@ given, <nr> defaults to 10.
-
-
search_index_entry = {'aliases': 'listobjects db stats listobjs', 'category': 'system', 'key': 'objects', 'tags': '', 'text': '\n statistics on objects in the database\n\n Usage:\n objects [<nr>]\n\n Gives statictics on objects in database as well as\n a list of <nr> latest objects in database. If not\n given, <nr> defaults to 10.\n '}
+search_index_entry = {'aliases': 'db listobjs stats listobjects', 'category': 'system', 'key': 'objects', 'tags': '', 'text': '\n statistics on objects in the database\n\n Usage:\n objects [<nr>]\n\n Gives statictics on objects in database as well as\n a list of <nr> latest objects in database. If not\n given, <nr> defaults to 10.\n '}
@@ -687,6 +688,7 @@ the released memory will instead be re-used by the program.
Evennia 1.0-dev »
evennia.commands.default.system
+ develop branch
@@ -117,7 +118,7 @@ create “account name” “pass word”
-
-
aliases = ['cr', 'cre']
+aliases = ['cre', 'cr']
@@ -148,7 +149,7 @@ create “account name” “pass word”
-
-
search_index_entry = {'aliases': 'cr cre', 'category': 'general', 'key': 'create', 'tags': '', 'text': '\n create a new account account\n\n Usage (at login screen):\n create <accountname> <password>\n create "account name" "pass word"\n\n This creates a new account account.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
+search_index_entry = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'tags': '', 'text': '\n create a new account account\n\n Usage (at login screen):\n create <accountname> <password>\n create "account name" "pass word"\n\n This creates a new account account.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
@@ -271,7 +272,7 @@ for simplicity. It shows a pane of info.
-
-
aliases = ['?', 'h']
+aliases = ['h', '?']
@@ -297,7 +298,7 @@ for simplicity. It shows a pane of info.
-
-
search_index_entry = {'aliases': '? h', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n get help when in unconnected-in state\n\n Usage:\n help\n\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
+search_index_entry = {'aliases': 'h ?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n get help when in unconnected-in state\n\n Usage:\n help\n\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
@@ -353,6 +354,7 @@ for simplicity. It shows a pane of info.
Evennia 1.0-dev »
evennia.commands.default.unloggedin
+ develop branch
@@ -680,7 +681,7 @@ try to influence the other part in the deal.
-
-
aliases = ['deal', 'offers']
+aliases = ['offers', 'deal']
@@ -706,7 +707,7 @@ try to influence the other part in the deal.
-
-
search_index_entry = {'aliases': 'deal offers', 'category': 'trading', 'key': 'status', 'tags': '', 'text': "\n show a list of the current deal\n\n Usage:\n status\n deal\n offers\n\n Shows the currently suggested offers on each sides of the deal. To\n accept the current deal, use the 'accept' command. Use 'offer' to\n change your deal. You might also want to use 'say', 'emote' etc to\n try to influence the other part in the deal.\n "}
+search_index_entry = {'aliases': 'offers deal', 'category': 'trading', 'key': 'status', 'tags': '', 'text': "\n show a list of the current deal\n\n Usage:\n status\n deal\n offers\n\n Shows the currently suggested offers on each sides of the deal. To\n accept the current deal, use the 'accept' command. Use 'offer' to\n change your deal. You might also want to use 'say', 'emote' etc to\n try to influence the other part in the deal.\n "}
@@ -890,6 +891,7 @@ info to your choice.
Evennia 1.0-dev »
evennia.contrib.barter
+ develop branch
@@ -627,7 +628,7 @@ inv
-
-
aliases = ['inv', 'i']
+aliases = ['i', 'inv']
@@ -658,7 +659,7 @@ inv
-
-
search_index_entry = {'aliases': 'inv i', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
+search_index_entry = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
@@ -740,6 +741,7 @@ items.
Evennia 1.0-dev »
evennia.contrib.clothing
+ develop branch
@@ -148,7 +149,7 @@ everyone but the person rolling.
-
-
aliases = ['@dice', 'roll']
+aliases = ['roll', '@dice']
@@ -174,7 +175,7 @@ everyone but the person rolling.
-
-
search_index_entry = {'aliases': '@dice roll', 'category': 'general', 'key': 'dice', 'tags': '', 'text': "\n roll dice\n\n Usage:\n dice[/switch] <nr>d<sides> [modifier] [success condition]\n\n Switch:\n hidden - tell the room the roll is being done, but don't show the result\n secret - don't inform the room about neither roll nor result\n\n Examples:\n dice 3d6 + 4\n dice 1d100 - 2 < 50\n\n This will roll the given number of dice with given sides and modifiers.\n So e.g. 2d6 + 3 means to 'roll a 6-sided die 2 times and add the result,\n then add 3 to the total'.\n Accepted modifiers are +, -, * and /.\n A success condition is given as normal Python conditionals\n (<,>,<=,>=,==,!=). So e.g. 2d6 + 3 > 10 means that the roll will succeed\n only if the final result is above 8. If a success condition is given, the\n outcome (pass/fail) will be echoed along with how much it succeeded/failed\n with. The hidden/secret switches will hide all or parts of the roll from\n everyone but the person rolling.\n "}
+search_index_entry = {'aliases': 'roll @dice', 'category': 'general', 'key': 'dice', 'tags': '', 'text': "\n roll dice\n\n Usage:\n dice[/switch] <nr>d<sides> [modifier] [success condition]\n\n Switch:\n hidden - tell the room the roll is being done, but don't show the result\n secret - don't inform the room about neither roll nor result\n\n Examples:\n dice 3d6 + 4\n dice 1d100 - 2 < 50\n\n This will roll the given number of dice with given sides and modifiers.\n So e.g. 2d6 + 3 means to 'roll a 6-sided die 2 times and add the result,\n then add 3 to the total'.\n Accepted modifiers are +, -, * and /.\n A success condition is given as normal Python conditionals\n (<,>,<=,>=,==,!=). So e.g. 2d6 + 3 > 10 means that the roll will succeed\n only if the final result is above 8. If a success condition is given, the\n outcome (pass/fail) will be echoed along with how much it succeeded/failed\n with. The hidden/secret switches will hide all or parts of the roll from\n everyone but the person rolling.\n "}
@@ -249,6 +250,7 @@ Add with @py self.cmdset.add(“contrib.dice.DiceCmdSet”)
Evennia 1.0-dev »
evennia.contrib.dice
+ develop branch
@@ -125,7 +126,7 @@ there is no object yet before the account has logged in)
-
-
aliases = ['cr', 'cre']
+aliases = ['cre', 'cr']
@@ -161,7 +162,7 @@ name enclosed in quotes:
-
-
search_index_entry = {'aliases': 'cr cre', 'category': 'general', 'key': 'create', 'tags': '', 'text': '\n Create a new account.\n\n Usage (at login screen):\n create "accountname" <email> <password>\n\n This creates a new account account.\n\n '}
+search_index_entry = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'tags': '', 'text': '\n Create a new account.\n\n Usage (at login screen):\n create "accountname" <email> <password>\n\n This creates a new account account.\n\n '}
@@ -269,7 +270,7 @@ for simplicity. It shows a pane of info.
-
-
aliases = ['?', 'h']
+aliases = ['h', '?']
@@ -295,7 +296,7 @@ for simplicity. It shows a pane of info.
-
-
search_index_entry = {'aliases': '? h', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
+search_index_entry = {'aliases': 'h ?', 'category': 'general', 'key': 'help', 'tags': '', 'text': '\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
@@ -351,6 +352,7 @@ for simplicity. It shows a pane of info.
Evennia 1.0-dev »
evennia.contrib.email_login
+ develop branch
@@ -51,7 +52,7 @@
-
-
aliases = ['@calls', '@callbacks', '@callback']
+aliases = ['@callbacks', '@callback', '@calls']
@@ -132,7 +133,7 @@ on user permission.
-
-
search_index_entry = {'aliases': '@calls @callbacks @callback', 'category': 'building', 'key': '@call', 'tags': '', 'text': '\n Command to edit callbacks.\n '}
+search_index_entry = {'aliases': '@callbacks @callback @calls', 'category': 'building', 'key': '@call', 'tags': '', 'text': '\n Command to edit callbacks.\n '}
@@ -188,6 +189,7 @@ on user permission.
Evennia 1.0-dev »
evennia.contrib.ingame_python.commands
+ develop branch
@@ -109,7 +110,7 @@ push the lid of the button away.
-
-
aliases = ['push', 'press button', 'press']
+aliases = ['press button', 'press', 'push']
@@ -140,7 +141,7 @@ lid-state respectively.
-
-
search_index_entry = {'aliases': 'push press button press', 'category': 'general', 'key': 'push button', 'tags': '', 'text': '\n Push the red button\n\n Usage:\n push button\n\n '}
+search_index_entry = {'aliases': 'press button press push', 'category': 'general', 'key': 'push button', 'tags': '', 'text': '\n Push the red button\n\n Usage:\n push button\n\n '}
@@ -162,7 +163,7 @@ lid-state respectively.
-
-
aliases = ['smash', 'smash lid', 'break lid']
+aliases = ['smash lid', 'break lid', 'smash']
@@ -189,7 +190,7 @@ of causing the lamp to break.
-
-
search_index_entry = {'aliases': 'smash smash lid break lid', 'category': 'general', 'key': 'smash glass', 'tags': '', 'text': '\n smash glass\n\n Usage:\n smash glass\n\n Try to smash the glass of the button.\n '}
+search_index_entry = {'aliases': 'smash lid break lid smash', 'category': 'general', 'key': 'smash glass', 'tags': '', 'text': '\n smash glass\n\n Usage:\n smash glass\n\n Try to smash the glass of the button.\n '}
@@ -210,7 +211,7 @@ of causing the lamp to break.
-
-
aliases = ['open', 'open button']
+aliases = ['open button', 'open']
@@ -236,7 +237,7 @@ of causing the lamp to break.
-
-
search_index_entry = {'aliases': 'open open button', 'category': 'general', 'key': 'open lid', 'tags': '', 'text': '\n open lid\n\n Usage:\n open lid\n\n '}
+search_index_entry = {'aliases': 'open button open', 'category': 'general', 'key': 'open lid', 'tags': '', 'text': '\n open lid\n\n Usage:\n open lid\n\n '}
@@ -306,7 +307,7 @@ of causing the lamp to break.
-
-
aliases = ['examine', 'get', 'feel', 'l', 'ex', 'listen']
+aliases = ['get', 'ex', 'feel', 'listen', 'examine', 'l']
@@ -332,7 +333,7 @@ of causing the lamp to break.
-
-
search_index_entry = {'aliases': 'examine get feel l ex listen', 'category': 'general', 'key': 'look', 'tags': '', 'text': "\n Looking around in darkness\n\n Usage:\n look <obj>\n\n ... not that there's much to see in the dark.\n\n "}
+search_index_entry = {'aliases': 'get ex feel listen examine l', 'category': 'general', 'key': 'look', 'tags': '', 'text': "\n Looking around in darkness\n\n Usage:\n look <obj>\n\n ... not that there's much to see in the dark.\n\n "}
@@ -567,6 +568,7 @@ the button is pushed.
Evennia 1.0-dev »
evennia.contrib.tutorial_examples.cmdset_red_button
+ develop branch
@@ -360,7 +361,7 @@ of the object. We overload it with our own version.
-
-
aliases = ['burn', 'light']
+aliases = ['light', 'burn']
@@ -387,7 +388,7 @@ to sit on a “lightable” object, we operate only on self.obj.
-
-
search_index_entry = {'aliases': 'burn light', 'category': 'tutorialworld', 'key': 'on', 'tags': '', 'text': '\n Creates light where there was none. Something to burn.\n '}
+search_index_entry = {'aliases': 'light burn', 'category': 'tutorialworld', 'key': 'on', 'tags': '', 'text': '\n Creates light where there was none. Something to burn.\n '}
@@ -491,7 +492,7 @@ shift green root up/down
-
-
aliases = ['push', 'shiftroot', 'pull', 'move']
+aliases = ['move', 'push', 'pull', 'shiftroot']
@@ -527,7 +528,7 @@ yellow/green - horizontal roots
-
-
search_index_entry = {'aliases': 'push shiftroot pull move', 'category': 'tutorialworld', 'key': 'shift', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}
+search_index_entry = {'aliases': 'move push pull shiftroot', 'category': 'tutorialworld', 'key': 'shift', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}
@@ -544,7 +545,7 @@ yellow/green - horizontal roots
-
-
aliases = ['push button', 'press button', 'button']
+aliases = ['press button', 'push button', 'button']
@@ -570,7 +571,7 @@ yellow/green - horizontal roots
-
-
search_index_entry = {'aliases': 'push button press button button', 'category': 'tutorialworld', 'key': 'press', 'tags': '', 'text': '\n Presses a button.\n '}
+search_index_entry = {'aliases': 'press button push button button', 'category': 'tutorialworld', 'key': 'press', 'tags': '', 'text': '\n Presses a button.\n '}
@@ -714,7 +715,7 @@ parry - forgoes your attack but will make you harder to hit on next
-
-
aliases = ['kill', 'thrust', 'chop', 'hit', 'fight', 'bash', 'pierce', 'stab', 'slash', 'parry', 'defend']
+aliases = ['chop', 'bash', 'slash', 'fight', 'defend', 'kill', 'thrust', 'pierce', 'parry', 'stab', 'hit']
@@ -740,7 +741,7 @@ parry - forgoes your attack but will make you harder to hit on next
-
-
search_index_entry = {'aliases': 'kill thrust chop hit fight bash pierce stab slash parry defend', 'category': 'tutorialworld', 'key': 'attack', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}
+search_index_entry = {'aliases': 'chop bash slash fight defend kill thrust pierce parry stab hit', 'category': 'tutorialworld', 'key': 'attack', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}
@@ -995,6 +996,7 @@ pulling weapons from it indefinitely.
Evennia 1.0-dev »
evennia.contrib.tutorial_world.objects
+ develop branch
@@ -712,7 +713,7 @@ if they fall off the bridge.
-
-
aliases = ['?', 'h']
+aliases = ['h', '?']
@@ -738,7 +739,7 @@ if they fall off the bridge.
-
-
search_index_entry = {'aliases': '? h', 'category': 'tutorial world', 'key': 'help', 'tags': '', 'text': '\n Overwritten help command while on the bridge.\n '}
+search_index_entry = {'aliases': 'h ?', 'category': 'tutorial world', 'key': 'help', 'tags': '', 'text': '\n Overwritten help command while on the bridge.\n '}
@@ -864,7 +865,7 @@ to find something.
-
-
aliases = ['search', 'feel around', 'feel', 'l', 'fiddle']
+aliases = ['feel', 'fiddle', 'feel around', 'l', 'search']
@@ -892,7 +893,7 @@ random chance of eventually finding a light source.
-
-
search_index_entry = {'aliases': 'search feel around feel l fiddle', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}
+search_index_entry = {'aliases': 'feel fiddle feel around l search', 'category': 'tutorialworld', 'key': 'look', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}
@@ -1262,6 +1263,7 @@ overriding the call (unused by default).
Evennia 1.0-dev »
evennia.contrib.tutorial_world.rooms
+ develop branch
@@ -393,7 +394,10 @@ with ‘q’, remove the break line and restart server when finished.
evennia.utils
@@ -329,7 +330,8 @@ the keyword attribute_name specifies otherwise.
+ develop branch
@@ -76,6 +77,13 @@ the default reserved keys.
+
+-
+
evennia.prototypes.prototypes.load_module_prototypes()[source]
+This is called by evennia.__init__ as Evennia initializes. It’s important
+to do this late so as to not interfere with evennia initialization.
+
+
-
class
evennia.prototypes.prototypes.DbPrototype(*args, **kwargs)[source]
@@ -498,6 +506,7 @@ validator (callable, optional): If given, this will be called with the value to<
Evennia 1.0-dev »
evennia.prototypes.prototypes
+ develop branch
@@ -91,7 +92,7 @@ non-persistent tickers must be killed.
-
at_update(obj, fieldname)[source]
-Called by the field as it saves.
+Called by the field/attribute as it saves.
@@ -205,6 +206,7 @@ all kwargs must be possible to pickle!
Evennia 1.0-dev »
evennia.scripts.monitorhandler
+ develop branch
@@ -47,8 +48,8 @@
particular threshold.
This version of the throttle is usable by both the terminal server as well
as the web server, imposes limits on memory consumption by using deques
-with length limits instead of open-ended lists, and removes sparse keys when
-no recent failures have been recorded.
+with length limits instead of open-ended lists, and uses native Django
+caches for automatic key eviction and persistence configurability.
-
error_msg = 'Too many failed attempts; you must wait a few minutes before trying again.'
@@ -61,6 +62,7 @@ no recent failures have been recorded.
- Keyword Arguments
+name (str) – Name of this throttle.
limit (int) – Max number of failures before imposing limiter
timeout (int) – number of timeout seconds after
max number of tries has been reached.
@@ -72,6 +74,25 @@ the throttle is imposed!
+
+-
+
get_cache_key(*args, **kwargs)[source]
+Creates a ‘prefixed’ key containing arbitrary terms to prevent key
+collisions in the same namespace.
+
+
+
+-
+
touch(key, *args, **kwargs)[source]
+Refreshes the timeout on a given key and ensures it is recorded in the
+key register.
+
+- Parameters
+key (str) – Key of entry to renew.
+
+
+
+
-
get(ip=None)[source]
@@ -112,6 +133,41 @@ of throttle.
+
+-
+
remove(ip, *args, **kwargs)[source]
+Clears data stored for an IP from the throttle.
+
+- Parameters
+ip (str) – IP to clear.
+
+
+
+
+
+-
+
record_ip(ip, *args, **kwargs)[source]
+Tracks keys as they are added to the cache (since there is no way to
+get a list of keys after-the-fact).
+
+- Parameters
+ip (str) – IP being added to cache. This should be the original
+IP, not the cache-prefixed key.
+
+
+
+
+
+-
+
unrecord_ip(ip, *args, **kwargs)[source]
+Forces removal of a key from the key registry.
+
+- Parameters
+ip (str) – IP to remove from list of keys.
+
+
+
+
-
check(ip)[source]
@@ -186,6 +242,7 @@ fails recently.
Evennia 1.0-dev »
evennia.server.throttle
+ develop branch
@@ -39,16 +40,57 @@
evennia.utils.ansi
ANSI - Gives colour to text.
- Use the codes defined in ANSIPARSER in your text
-to apply colour to text according to the ANSI standard.
- Examples:
+ Use the codes defined in the ANSIParser class to apply colour to text. The
+parse_ansi function in this module parses text for markup and strip_ansi
+removes it.
+ You should usually not need to call parse_ansi explicitly; it is run by
+Evennia just before returning data to/from the user. Alternative markup is
+possible by overriding the parser class (see also contrib/ for deprecated
+markup schemes).
+ Supported standards:
+
+ANSI 8 bright and 8 dark fg (foreground) colors
+ANSI 8 dark bg (background) colors
+‘ANSI’ 8 bright bg colors ‘faked’ with xterm256 (bright bg not included in ANSI standard)
+Xterm256 - 255 fg/bg colors + 26 greyscale fg/bg colors
+
+
+ Markup
+ ANSI colors: r ed, g reen, y ellow, b lue, m agenta, c yan, n ormal (no color). Capital
+letters indicate the ‘dark’ variant.
+
"This is |rRed text|n and this is normal again."
- Mostly you should not need to call parse_ansi() explicitly;
-it is run by Evennia just before returning data to/from the
-user. Depreciated example forms are available by extending
-the ansi mapping.
+ Xterm256 colors are given as RGB (Red-Green-Blue), with values 0-5:
+
+|500 fg bright red
+|050 fg bright green
+|005 fg bright blue
+|110 fg dark brown
+|425 fg pink
+|[431 bg orange
+
+ Xterm256 greyscale:
+
+|=a fg black
+|=g fg dark grey
+|=o fg middle grey
+|=v fg bright grey
+|=z fg white
+|[=r bg middle grey
+
+ "This is |500Red text|n and this is normal again."
+"This is |[=jText on dark grey background"
+
+
+
-
class
evennia.utils.ansi.ANSIParser[source]
@@ -56,11 +98,10 @@ the ansi mapping.
A class that parses ANSI markup
to ANSI command sequences
We also allow to escape colour codes
-by prepending with a for xterm256,
-an extra | for Merc-style codes
+by prepending with an extra |.
-
-
ansi_map = [('|n', '\x1b[0m'), ('|/', '\r\n'), ('|-', '\t'), ('|_', ' '), ('|*', '\x1b[7m'), ('|^', '\x1b[5m'), ('|u', '\x1b[4m'), ('|r', '\x1b[1m\x1b[31m'), ('|g', '\x1b[1m\x1b[32m'), ('|y', '\x1b[1m\x1b[33m'), ('|b', '\x1b[1m\x1b[34m'), ('|m', '\x1b[1m\x1b[35m'), ('|c', '\x1b[1m\x1b[36m'), ('|w', '\x1b[1m\x1b[37m'), ('|x', '\x1b[1m\x1b[30m'), ('|R', '\x1b[22m\x1b[31m'), ('|G', '\x1b[22m\x1b[32m'), ('|Y', '\x1b[22m\x1b[33m'), ('|B', '\x1b[22m\x1b[34m'), ('|M', '\x1b[22m\x1b[35m'), ('|C', '\x1b[22m\x1b[36m'), ('|W', '\x1b[22m\x1b[37m'), ('|X', '\x1b[22m\x1b[30m'), ('|h', '\x1b[1m'), ('|H', '\x1b[22m'), ('|!R', '\x1b[31m'), ('|!G', '\x1b[32m'), ('|!Y', '\x1b[33m'), ('|!B', '\x1b[34m'), ('|!M', '\x1b[35m'), ('|!C', '\x1b[36m'), ('|!W', '\x1b[37m'), ('|!X', '\x1b[30m'), ('|[R', '\x1b[41m'), ('|[G', '\x1b[42m'), ('|[Y', '\x1b[43m'), ('|[B', '\x1b[44m'), ('|[M', '\x1b[45m'), ('|[C', '\x1b[46m'), ('|[W', '\x1b[47m'), ('|[X', '\x1b[40m')]
+ansi_map = [('|n', '\x1b[0m'), ('|/', '\r\n'), ('|-', '\t'), ('|>', ' '), ('|_', ' '), ('|*', '\x1b[7m'), ('|^', '\x1b[5m'), ('|u', '\x1b[4m'), ('|r', '\x1b[1m\x1b[31m'), ('|g', '\x1b[1m\x1b[32m'), ('|y', '\x1b[1m\x1b[33m'), ('|b', '\x1b[1m\x1b[34m'), ('|m', '\x1b[1m\x1b[35m'), ('|c', '\x1b[1m\x1b[36m'), ('|w', '\x1b[1m\x1b[37m'), ('|x', '\x1b[1m\x1b[30m'), ('|R', '\x1b[22m\x1b[31m'), ('|G', '\x1b[22m\x1b[32m'), ('|Y', '\x1b[22m\x1b[33m'), ('|B', '\x1b[22m\x1b[34m'), ('|M', '\x1b[22m\x1b[35m'), ('|C', '\x1b[22m\x1b[36m'), ('|W', '\x1b[22m\x1b[37m'), ('|X', '\x1b[22m\x1b[30m'), ('|h', '\x1b[1m'), ('|H', '\x1b[22m'), ('|!R', '\x1b[31m'), ('|!G', '\x1b[32m'), ('|!Y', '\x1b[33m'), ('|!B', '\x1b[34m'), ('|!M', '\x1b[35m'), ('|!C', '\x1b[36m'), ('|!W', '\x1b[37m'), ('|!X', '\x1b[30m'), ('|[R', '\x1b[41m'), ('|[G', '\x1b[42m'), ('|[Y', '\x1b[43m'), ('|[B', '\x1b[44m'), ('|[M', '\x1b[45m'), ('|[C', '\x1b[46m'), ('|[W', '\x1b[47m'), ('|[X', '\x1b[40m')]
@@ -120,7 +161,7 @@ an extra | for Merc-style codes
-
-
ansi_sub = re.compile('\\|n|\\|/|\\|\\-|\\|_|\\|\\*|\\|\\^|\\|u|\\|r|\\|g|\\|y|\\|b|\\|m|\\|c|\\|w|\\|x|\\|R|\\|G|\\|Y|\\|B|\\|M|\\|C|\\|W|\\|X|\\|h|\\|H|\\|!R|\\|!G|\\|!Y|\\|!B|\\|!M|\\|!C|\\|!W|\\|!X|\\|\\[R|\\|\\[G|\\|\, re.DOTALL)
+ansi_sub = re.compile('\\|n|\\|/|\\|\\-|\\|>|\\|_|\\|\\*|\\|\\^|\\|u|\\|r|\\|g|\\|y|\\|b|\\|m|\\|c|\\|w|\\|x|\\|R|\\|G|\\|Y|\\|B|\\|M|\\|C|\\|W|\\|X|\\|h|\\|H|\\|!R|\\|!G|\\|!Y|\\|!B|\\|!M|\\|!C|\\|!W|\\|!X|\\|\\[R|\\|\\[G, re.DOTALL)
@@ -130,7 +171,7 @@ an extra | for Merc-style codes
-
-
ansi_map_dict = {'|!B': '\x1b[34m', '|!C': '\x1b[36m', '|!G': '\x1b[32m', '|!M': '\x1b[35m', '|!R': '\x1b[31m', '|!W': '\x1b[37m', '|!X': '\x1b[30m', '|!Y': '\x1b[33m', '|*': '\x1b[7m', '|-': '\t', '|/': '\r\n', '|B': '\x1b[22m\x1b[34m', '|C': '\x1b[22m\x1b[36m', '|G': '\x1b[22m\x1b[32m', '|H': '\x1b[22m', '|M': '\x1b[22m\x1b[35m', '|R': '\x1b[22m\x1b[31m', '|W': '\x1b[22m\x1b[37m', '|X': '\x1b[22m\x1b[30m', '|Y': '\x1b[22m\x1b[33m', '|[B': '\x1b[44m', '|[C': '\x1b[46m', '|[G': '\x1b[42m', '|[M': '\x1b[45m', '|[R': '\x1b[41m', '|[W': '\x1b[47m', '|[X': '\x1b[40m', '|[Y': '\x1b[43m', '|^': '\x1b[5m', '|_': ' ', '|b': '\x1b[1m\x1b[34m', '|c': '\x1b[1m\x1b[36m', '|g': '\x1b[1m\x1b[32m', '|h': '\x1b[1m', '|m': '\x1b[1m\x1b[35m', '|n': '\x1b[0m', '|r': '\x1b[1m\x1b[31m', '|u': '\x1b[4m', '|w': '\x1b[1m\x1b[37m', '|x': '\x1b[1m\x1b[30m', '|y': '\x1b[1m\x1b[33m'}
+ansi_map_dict = {'|!B': '\x1b[34m', '|!C': '\x1b[36m', '|!G': '\x1b[32m', '|!M': '\x1b[35m', '|!R': '\x1b[31m', '|!W': '\x1b[37m', '|!X': '\x1b[30m', '|!Y': '\x1b[33m', '|*': '\x1b[7m', '|-': '\t', '|/': '\r\n', '|>': ' ', '|B': '\x1b[22m\x1b[34m', '|C': '\x1b[22m\x1b[36m', '|G': '\x1b[22m\x1b[32m', '|H': '\x1b[22m', '|M': '\x1b[22m\x1b[35m', '|R': '\x1b[22m\x1b[31m', '|W': '\x1b[22m\x1b[37m', '|X': '\x1b[22m\x1b[30m', '|Y': '\x1b[22m\x1b[33m', '|[B': '\x1b[44m', '|[C': '\x1b[46m', '|[G': '\x1b[42m', '|[M': '\x1b[45m', '|[R': '\x1b[41m', '|[W': '\x1b[47m', '|[X': '\x1b[40m', '|[Y': '\x1b[43m', '|^': '\x1b[5m', '|_': ' ', '|b': '\x1b[1m\x1b[34m', '|c': '\x1b[1m\x1b[36m', '|g': '\x1b[1m\x1b[32m', '|h': '\x1b[1m', '|m': '\x1b[1m\x1b[35m', '|n': '\x1b[0m', '|r': '\x1b[1m\x1b[31m', '|u': '\x1b[4m', '|w': '\x1b[1m\x1b[37m', '|x': '\x1b[1m\x1b[30m', '|y': '\x1b[1m\x1b[33m'}
@@ -845,6 +886,7 @@ with.
+
@@ -867,6 +909,14 @@ with.
+
+
+
@@ -273,7 +274,7 @@ indentation.
-
-
aliases = [':dw', ':::', ':UU', ':r', ':<', ':w', ':x', ':u', ':p', ':fd', ':wq', ':y', ':>', ':A', ':DD', ':', ':i', ':h', ':dd', ':j', ':=', ':I', ':q!', ':q', ':s', ':echo', ':uu', ':S', ':fi', ':f', ':!', '::']
+aliases = [':dw', ':p', ':r', ':q!', ':DD', ':i', ':echo', ':<', ':>', ':fd', ':wq', ':j', '::', ':!', ':A', ':S', ':fi', ':UU', ':f', ':q', ':s', ':uu', ':y', ':I', ':::', ':u', ':x', ':h', ':=', ':dd', ':w', ':']
@@ -301,7 +302,7 @@ efficient presentation.
-
-
search_index_entry = {'aliases': ':dw ::: :UU :r :< :w :x :u :p :fd :wq :y :> :A :DD : :i :h :dd :j := :I :q! :q :s :echo :uu :S :fi :f :! ::', 'category': 'general', 'key': ':editor_command_group', 'tags': '', 'text': '\n Commands for the editor\n '}
+search_index_entry = {'aliases': ':dw :p :r :q! :DD :i :echo :< :> :fd :wq :j :: :! :A :S :fi :UU :f :q :s :uu :y :I ::: :u :x :h := :dd :w :', 'category': 'general', 'key': ':editor_command_group', 'tags': '', 'text': '\n Commands for the editor\n '}
@@ -538,6 +539,7 @@ formatting information.
Evennia 1.0-dev »
evennia.utils.eveditor
+ develop branch
@@ -74,7 +75,7 @@ the caller.msg() construct every time the page is updated.
-
-
aliases = ['n', 'next', 'back', 'abort', 'end', 'q', 'a', 't', 'quit', 'top', 'b', 'e']
+aliases = ['q', 'end', 'abort', 'e', 'back', 'next', 't', 'top', 'b', 'a', 'quit', 'n']
@@ -100,7 +101,7 @@ the caller.msg() construct every time the page is updated.
-
-
search_index_entry = {'aliases': 'n next back abort end q a t quit top b e', 'category': 'general', 'key': '__noinput_command', 'tags': '', 'text': '\n Manipulate the text paging\n '}
+search_index_entry = {'aliases': 'q end abort e back next t top b a quit n', 'category': 'general', 'key': '__noinput_command', 'tags': '', 'text': '\n Manipulate the text paging\n '}
@@ -547,6 +548,7 @@ the evmore commands will be available when this is run).
Evennia 1.0-dev »
evennia.utils.evmore
+ develop branch
@@ -43,7 +44,10 @@ modules in Evennia. It also holds the idmapper in-memory caching
functionality.
@@ -7003,6 +7004,8 @@
get_by_permission() (evennia.typeclasses.managers.TypedObjectManager method)
get_by_tag() (evennia.typeclasses.managers.TypedObjectManager method)
+
+ get_cache_key() (evennia.server.throttle.Throttle method)
get_cached_instance() (evennia.utils.idmapper.models.SharedMemoryModel class method)
@@ -9086,6 +9089,8 @@
(evennia.utils.containers.GlobalScriptContainer method)
+ load_module_prototypes() (in module evennia.prototypes.prototypes)
+
load_sync_data() (evennia.server.session.Session method)
loads() (in module evennia.server.portal.amp)
@@ -12255,6 +12260,8 @@
(evennia.server.portal.irc.IRCBotFactory method)
+ record_ip() (evennia.server.throttle.Throttle method)
+
RedButton (class in evennia.contrib.tutorial_examples.red_button)
RedButton.DoesNotExist
@@ -12367,6 +12374,8 @@
(evennia.scripts.tickerhandler.TickerHandler method)
(evennia.scripts.tickerhandler.TickerPool method)
+
+ (evennia.server.throttle.Throttle method)
(evennia.typeclasses.attributes.AttributeHandler method)
@@ -14657,10 +14666,10 @@
test_sessions() (evennia.commands.default.tests.TestAccount method)
- |
- |
+ |
+ develop branch
@@ -42,13 +43,13 @@
Warning
- This is the experimental and unstable documentation for the
-development branch of Evennia (v1.0-dev). It’s based on converted docs
-from the Evennia wiki (https://github.com/evennia/evennia/wiki/) at
-2020-06-12 22:36:53. There are known conversion issues and missing links.
-This will slowly be ironed out as this is developed.
- For now you are best off using the original wiki, or the less changing v0.9.5
-of these docs. You have been warned.
+ This is the WIP documentation for the
+development branch of Evennia (v1.0-dev). The text is based on the
+original Evennia wiki
+but it’s being refactored heavily. There are known conversion issues
+and missing links. This will slowly be ironed out as this is developed.
+ New things will be added to this version only, but for now you are best
+off using v0.9.5 of the docs, or the original wiki. You have been warned.
|