"""
Evennia MUD/MUX/MU* creation system
This is the main top-level API for Evennia. You can explore the evennia library
by accessing evennia.<subpackage> directly. From inside the game you can read
docs of all object by viewing its `__doc__` string, such as through
py evennia.ObjectDB.__doc__
For full functionality you should explore this module via a django-
aware shell. Go to your game directory and use the command
evennia shell
to launch such a shell (using python or ipython depending on your install).
See www.evennia.com for full documentation.
"""
import evennia
# docstring header
DOCSTRING = """
Evennia MU* creation system.
Online manual and API docs are found at http://www.evennia.com.
Flat-API shortcut names:
{}
"""
# Delayed loading of properties
# Typeclasses
DefaultAccount = None
DefaultGuest = None
DefaultObject = None
DefaultCharacter = None
DefaultRoom = None
DefaultExit = None
DefaultChannel = None
DefaultScript = None
# Database models
ObjectDB = None
AccountDB = None
ScriptDB = None
ChannelDB = None
Msg = None
ServerConfig = None
# Properties
AttributeProperty = None
TagProperty = None
TagCategoryProperty = None
# commands
Command = None
CmdSet = None
default_cmds = None
syscmdkeys = None
InterruptCommand = None
# search functions
search_object = None
search_script = None
search_account = None
search_channel = None
search_message = None
search_help = None
search_tag = None
# create functions
create_object = None
create_script = None
create_account = None
create_channel = None
create_message = None
create_help_entry = None
# utilities
settings = None
lockfuncs = None
inputhandler = None
logger = None
gametime = None
ansi = None
spawn = None
managers = None
contrib = None
EvMenu = None
EvTable = None
EvForm = None
EvEditor = None
EvMore = None
ANSIString = None
signals = None
FuncParser = None
# Handlers
SESSION_HANDLER = None
PORTAL_SESSION_HANDLER = None
SERVER_SESSION_HANDLER = None
TASK_HANDLER = None
TICKER_HANDLER = None
MONITOR_HANDLER = None
# Containers
GLOBAL_SCRIPTS = None
OPTION_CLASSES = None
PROCESS_ID = None
TWISTED_APPLICATION = None
EVENNIA_PORTAL_SERVICE = None
EVENNIA_SERVER_SERVICE = None
def _create_version():
"""
Helper function for building the version string
"""
import os
from subprocess import STDOUT, CalledProcessError, check_output
version = "Unknown"
root = os.path.dirname(os.path.abspath(__file__))
try:
with open(os.path.join(root, "VERSION.txt"), "r") as f:
version = f.read().strip()
except IOError as err:
print(err)
try:
rev = (
check_output("git rev-parse --short HEAD", shell=True, cwd=root, stderr=STDOUT)
.strip()
.decode()
)
version = "%s (rev %s)" % (version, rev)
except (IOError, CalledProcessError, OSError):
# ignore if we cannot get to git
pass
return version
__version__ = _create_version()
del _create_version
_LOADED = False
PORTAL_MODE = False
def _init(portal_mode=False):
"""
This function is called automatically by the launcher only after
Evennia has fully initialized all its models. It sets up the API
in a safe environment where all models are available already.
"""
global _LOADED
if _LOADED:
return
_LOADED = True
global DefaultAccount, DefaultObject, DefaultGuest, DefaultCharacter
global DefaultRoom, DefaultExit, DefaultChannel, DefaultScript
global ObjectDB, AccountDB, ScriptDB, ChannelDB, Msg
global Command, CmdSet, default_cmds, syscmdkeys, InterruptCommand
global search_object, search_script, search_account, search_channel
global search_help, search_tag, search_message
global create_object, create_script, create_account, create_channel
global create_message, create_help_entry
global signals
global settings, lockfuncs, logger, utils, gametime, ansi, spawn, managers
global contrib, TICKER_HANDLER, MONITOR_HANDLER, SESSION_HANDLER, PROCESS_ID
global TASK_HANDLER, PORTAL_SESSION_HANDLER, SERVER_SESSION_HANDLER
global GLOBAL_SCRIPTS, OPTION_CLASSES, EVENNIA_PORTAL_SERVICE, EVENNIA_SERVER_SERVICE, TWISTED_APPLICATION
global EvMenu, EvTable, EvForm, EvMore, EvEditor
global ANSIString, FuncParser
global AttributeProperty, TagProperty, TagCategoryProperty, ServerConfig
global PORTAL_MODE
PORTAL_MODE = portal_mode
# Parent typeclasses
# utilities
import os
from django.conf import settings
from . import contrib
from .accounts.accounts import DefaultAccount, DefaultGuest
from .accounts.models import AccountDB
from .commands.cmdset import CmdSet
from .commands.command import Command, InterruptCommand
from .comms.comms import DefaultChannel
from .comms.models import ChannelDB, Msg
from .locks import lockfuncs
from .objects.models import ObjectDB
from .objects.objects import (
DefaultCharacter,
DefaultExit,
DefaultObject,
DefaultRoom,
)
from .prototypes.spawner import spawn
from .scripts.models import ScriptDB
from .scripts.monitorhandler import MONITOR_HANDLER
from .scripts.scripts import DefaultScript
from .scripts.taskhandler import TASK_HANDLER
from .scripts.tickerhandler import TICKER_HANDLER
from .server import signals
from .server.models import ServerConfig
from .typeclasses.attributes import AttributeProperty
from .typeclasses.tags import TagCategoryProperty, TagProperty
from .utils import ansi, class_from_module, gametime, logger
from .utils.ansi import ANSIString
if not PORTAL_MODE:
# containers
from .utils.containers import GLOBAL_SCRIPTS, OPTION_CLASSES
# create functions
from .utils.create import (
create_account,
create_channel,
create_help_entry,
create_message,
create_object,
create_script,
)
from .utils.eveditor import EvEditor
from .utils.evform import EvForm
from .utils.evmenu import EvMenu
from .utils.evmore import EvMore
from .utils.evtable import EvTable
from .utils.funcparser import FuncParser
# search functions
from .utils.search import (
search_account,
search_channel,
search_help,
search_message,
search_object,
search_script,
search_tag,
)
from .utils.utils import class_from_module
PROCESS_ID = os.getpid()
from twisted.application.service import Application
TWISTED_APPLICATION = Application("Evennia")
_evennia_service_class = None
if portal_mode:
# Set up the PortalSessionHandler
from evennia.server.portal import portalsessionhandler
portal_sess_handler_class = class_from_module(settings.PORTAL_SESSION_HANDLER_CLASS)
portalsessionhandler.PORTAL_SESSIONS = portal_sess_handler_class()
SESSION_HANDLER = portalsessionhandler.PORTAL_SESSIONS
evennia.PORTAL_SESSION_HANDLER = evennia.SESSION_HANDLER
_evennia_service_class = class_from_module(settings.EVENNIA_PORTAL_SERVICE_CLASS)
EVENNIA_PORTAL_SERVICE = _evennia_service_class()
EVENNIA_PORTAL_SERVICE.setServiceParent(TWISTED_APPLICATION)
from django.db import connection
# we don't need a connection to the database so close it right away
try:
connection.close()
except Exception:
pass
else:
# Create the ServerSesssionHandler
from evennia.server import sessionhandler
sess_handler_class = class_from_module(settings.SERVER_SESSION_HANDLER_CLASS)
sessionhandler.SESSIONS = sess_handler_class()
sessionhandler.SESSION_HANDLER = sessionhandler.SESSIONS
SESSION_HANDLER = sessionhandler.SESSIONS
SERVER_SESSION_HANDLER = SESSION_HANDLER
_evennia_service_class = class_from_module(settings.EVENNIA_SERVER_SERVICE_CLASS)
EVENNIA_SERVER_SERVICE = _evennia_service_class()
EVENNIA_SERVER_SERVICE.setServiceParent(TWISTED_APPLICATION)
# API containers
class _EvContainer(object):
"""
Parent for other containers
"""
def _help(self):
"Returns list of contents"
names = [name for name in self.__class__.__dict__ if not name.startswith("_")]
names += [name for name in self.__dict__ if not name.startswith("_")]
print(self.__doc__ + "-" * 60 + "\n" + ", ".join(names))
help = property(_help)
class DBmanagers(_EvContainer):
"""
Links to instantiated Django database managers. These are used
to perform more advanced custom database queries than the standard
search functions allow.
helpentries - HelpEntry.objects
accounts - AccountDB.objects
scripts - ScriptDB.objects
msgs - Msg.objects
channels - Channel.objects
objects - ObjectDB.objects
serverconfigs - ServerConfig.objects
tags - Tags.objects
attributes - Attributes.objects
"""
from .accounts.models import AccountDB
from .comms.models import ChannelDB, Msg
from .help.models import HelpEntry
from .objects.models import ObjectDB
from .scripts.models import ScriptDB
from .server.models import ServerConfig
from .typeclasses.attributes import Attribute
from .typeclasses.tags import Tag
# create container's properties
helpentries = HelpEntry.objects
accounts = AccountDB.objects
scripts = ScriptDB.objects
msgs = Msg.objects
channels = ChannelDB.objects
objects = ObjectDB.objects
serverconfigs = ServerConfig.objects
attributes = Attribute.objects
tags = Tag.objects
# remove these so they are not visible as properties
del HelpEntry, AccountDB, ScriptDB, Msg, ChannelDB
# del ExternalChannelConnection
del ObjectDB, ServerConfig, Tag, Attribute
managers = DBmanagers()
del DBmanagers
class DefaultCmds(_EvContainer):
"""
This container holds direct shortcuts to all default commands in Evennia.
To access in code, do 'from evennia import default_cmds' then
access the properties on the imported default_cmds object.
"""
from .commands.default.cmdset_account import AccountCmdSet
from .commands.default.cmdset_character import CharacterCmdSet
from .commands.default.cmdset_session import SessionCmdSet
from .commands.default.cmdset_unloggedin import UnloggedinCmdSet
from .commands.default.muxcommand import MuxAccountCommand, MuxCommand
def __init__(self):
"populate the object with commands"
def add_cmds(module):
"helper method for populating this object with cmds"
from evennia.utils import utils
cmdlist = utils.variable_from_module(module, module.__all__)
self.__dict__.update(dict([(c.__name__, c) for c in cmdlist]))
from .commands.default import (
account,
admin,
batchprocess,
building,
comms,
general,
help,
system,
unloggedin,
)
add_cmds(admin)
add_cmds(building)
add_cmds(batchprocess)
add_cmds(building)
add_cmds(comms)
add_cmds(general)
add_cmds(account)
add_cmds(help)
add_cmds(system)
add_cmds(unloggedin)
default_cmds = DefaultCmds()
del DefaultCmds
class SystemCmds(_EvContainer):
"""
Creating commands with keys set to these constants will make
them system commands called as a replacement by the parser when
special situations occur. If not defined, the hard-coded
responses in the server are used.
CMD_NOINPUT - no input was given on command line
CMD_NOMATCH - no valid command key was found
CMD_MULTIMATCH - multiple command matches were found
CMD_LOGINSTART - this command will be called as the very
first command when an account connects to
the server.
To access in code, do 'from evennia import syscmdkeys' then
access the properties on the imported syscmdkeys object.
"""
from .commands import cmdhandler
CMD_NOINPUT = cmdhandler.CMD_NOINPUT
CMD_NOMATCH = cmdhandler.CMD_NOMATCH
CMD_MULTIMATCH = cmdhandler.CMD_MULTIMATCH
CMD_LOGINSTART = cmdhandler.CMD_LOGINSTART
del cmdhandler
syscmdkeys = SystemCmds()
del SystemCmds
del _EvContainer
[docs]def set_trace(term_size=(140, 80), debugger="auto"):
"""
Helper function for running a debugger inside the Evennia event loop.
Args:
term_size (tuple, optional): Only used for Pudb and defines the size of the terminal
(width, height) in number of characters.
debugger (str, optional): One of 'auto', 'pdb' or 'pudb'. Pdb is the standard debugger. Pudb
is an external package with a different, more 'graphical', ncurses-based UI. With
'auto', will use pudb if possible, otherwise fall back to pdb. Pudb is available through
`pip install pudb`.
Notes:
To use:
1) add this to a line to act as a breakpoint for entering the debugger:
from evennia import set_trace; set_trace()
2) restart evennia in interactive mode
evennia istart
3) debugger will appear in the interactive terminal when breakpoint is reached. Exit
with 'q', remove the break line and restart server when finished.
"""
import sys
dbg = None
if debugger in ("auto", "pudb"):
try:
from pudb import debugger
dbg = debugger.Debugger(stdout=sys.__stdout__, term_size=term_size)
except ImportError:
if debugger == "pudb":
raise
pass
if not dbg:
import pdb
dbg = pdb.Pdb(stdout=sys.__stdout__)
try:
# Start debugger, forcing it up one stack frame (otherwise `set_trace`
# will start debugger this point, not the actual code location)
dbg.set_trace(sys._getframe().f_back)
except Exception:
# Stopped at breakpoint. Press 'n' to continue into the code.
dbg.set_trace()
# initialize the doc string
global __doc__
__doc__ = DOCSTRING.format(
"\n- "
+ "\n- ".join(
f"evennia.{key}"
for key in sorted(globals())
if not key.startswith("_") and key not in ("DOCSTRING",)
)
)