2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
This module gathers all the essential database-creation
|
2012-03-25 14:01:51 +02:00
|
|
|
functions for the game engine's various object types.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-03-25 14:01:51 +02:00
|
|
|
Only objects created 'stand-alone' are in here, e.g. object Attributes
|
|
|
|
|
are always created directly through their respective objects.
|
|
|
|
|
|
|
|
|
|
Each creation_* function also has an alias named for the entity being
|
|
|
|
|
created, such as create_object() and object(). This is for
|
|
|
|
|
consistency with the utils.search module and allows you to do the
|
|
|
|
|
shorter "create.object()".
|
|
|
|
|
|
|
|
|
|
The respective object managers hold more methods for manipulating and
|
|
|
|
|
searching objects already existing in the database.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-04-21 16:15:37 +02:00
|
|
|
Models covered:
|
2010-08-29 18:46:58 +00:00
|
|
|
Objects
|
|
|
|
|
Scripts
|
|
|
|
|
Help
|
|
|
|
|
Message
|
2012-04-21 16:15:37 +02:00
|
|
|
Channel
|
2010-08-29 18:46:58 +00:00
|
|
|
Players
|
|
|
|
|
"""
|
|
|
|
|
from django.conf import settings
|
|
|
|
|
from django.db import IntegrityError
|
2011-08-06 18:15:04 +00:00
|
|
|
from src.utils.idmapper.models import SharedMemoryModel
|
2012-04-21 16:15:37 +02:00
|
|
|
from src.utils import utils, logger
|
2012-08-30 00:05:00 +02:00
|
|
|
from src.utils.utils import make_iter
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-05-01 22:51:18 +02:00
|
|
|
# delayed imports
|
|
|
|
|
_User = None
|
|
|
|
|
_Object = None
|
|
|
|
|
_ObjectDB = None
|
|
|
|
|
_Script = None
|
|
|
|
|
_ScriptDB = None
|
|
|
|
|
_HelpEntry = None
|
|
|
|
|
_Msg = None
|
|
|
|
|
_Player = None
|
|
|
|
|
_PlayerDB = None
|
|
|
|
|
_to_object = None
|
|
|
|
|
_Channel = None
|
|
|
|
|
_channelhandler = None
|
|
|
|
|
|
|
|
|
|
|
2012-03-25 14:01:51 +02:00
|
|
|
# limit symbol import from API
|
2012-03-25 17:01:27 +02:00
|
|
|
__all__ = ("create_object", "create_script", "create_help_entry", "create_message", "create_channel", "create_player")
|
2012-03-25 14:01:51 +02:00
|
|
|
|
2012-05-01 22:51:18 +02:00
|
|
|
_GA = object.__getattribute__
|
2012-03-25 16:35:22 +02:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
2012-04-21 16:15:37 +02:00
|
|
|
# Game Object creation
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
|
|
|
|
|
|
|
|
|
def create_object(typeclass, key=None, location=None,
|
2013-02-03 20:04:40 +01:00
|
|
|
home=None, permissions=None, locks=None,
|
2013-09-23 22:08:14 +02:00
|
|
|
aliases=None, destination=None, report_to=None, testmode=False):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
Create a new in-game object. Any game object is a combination
|
|
|
|
|
of a database object that stores data persistently to
|
|
|
|
|
the database, and a typeclass, which on-the-fly 'decorates'
|
|
|
|
|
the database object into whataver different type of object
|
2012-04-21 16:15:37 +02:00
|
|
|
it is supposed to be in the game.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
See src.objects.managers for methods to manipulate existing objects
|
|
|
|
|
in the database. src.objects.objects holds the base typeclasses
|
2012-04-21 16:15:37 +02:00
|
|
|
and src.objects.models hold the database model.
|
|
|
|
|
|
|
|
|
|
report_to is an optional object for reporting errors to in string form.
|
|
|
|
|
If report_to is not set, errors will be raised as en Exception
|
|
|
|
|
containing the error message. If set, this method will return
|
|
|
|
|
None upon errors.
|
2013-09-23 22:08:14 +02:00
|
|
|
testmode is only intended for Evennia unittest system
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-05-01 22:51:18 +02:00
|
|
|
global _Object, _ObjectDB
|
|
|
|
|
if not _Object:
|
|
|
|
|
from src.objects.objects import Object as _Object
|
|
|
|
|
if not _ObjectDB:
|
|
|
|
|
from src.objects.models import ObjectDB as _ObjectDB
|
2011-08-06 18:15:04 +00:00
|
|
|
|
2011-10-01 22:00:22 +02:00
|
|
|
if not typeclass:
|
|
|
|
|
typeclass = settings.BASE_OBJECT_TYPECLASS
|
2012-05-01 22:51:18 +02:00
|
|
|
elif isinstance(typeclass, _ObjectDB):
|
2011-08-06 18:15:04 +00:00
|
|
|
# this is already an objectdb instance, extract its typeclass
|
2011-10-01 22:00:22 +02:00
|
|
|
typeclass = typeclass.typeclass.path
|
2012-05-01 22:51:18 +02:00
|
|
|
elif isinstance(typeclass, _Object) or utils.inherits_from(typeclass, _Object):
|
2011-08-06 18:15:04 +00:00
|
|
|
# this is already an object typeclass, extract its path
|
2012-04-21 16:15:37 +02:00
|
|
|
typeclass = typeclass.path
|
2011-08-06 18:15:04 +00:00
|
|
|
|
2012-04-21 16:15:37 +02:00
|
|
|
# create new database object
|
2012-05-01 22:51:18 +02:00
|
|
|
new_db_object = _ObjectDB()
|
2012-04-21 16:15:37 +02:00
|
|
|
|
|
|
|
|
# assign the typeclass
|
2011-08-06 18:15:04 +00:00
|
|
|
typeclass = utils.to_unicode(typeclass)
|
|
|
|
|
new_db_object.typeclass_path = typeclass
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
# the name/key is often set later in the typeclass. This
|
2012-04-21 16:15:37 +02:00
|
|
|
# is set here as a failsafe.
|
2010-08-29 18:46:58 +00:00
|
|
|
if key:
|
2012-04-21 16:15:37 +02:00
|
|
|
new_db_object.key = key
|
2010-08-29 18:46:58 +00:00
|
|
|
else:
|
2012-05-01 22:51:18 +02:00
|
|
|
new_db_object.key = "#%i" % new_db_object.dbid
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2011-10-01 22:00:22 +02:00
|
|
|
# this will either load the typeclass or the default one
|
|
|
|
|
new_object = new_db_object.typeclass
|
|
|
|
|
|
2012-05-01 22:51:18 +02:00
|
|
|
if not _GA(new_object, "is_typeclass")(typeclass, exact=True):
|
2011-10-01 22:00:22 +02:00
|
|
|
# this will fail if we gave a typeclass as input and it still gave us a default
|
|
|
|
|
SharedMemoryModel.delete(new_db_object)
|
2012-04-21 16:15:37 +02:00
|
|
|
if report_to:
|
2012-05-01 22:51:18 +02:00
|
|
|
_GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_object.key, typeclass,
|
|
|
|
|
_GA(new_db_object, "typeclass_last_errmsg")))
|
2012-04-21 16:15:37 +02:00
|
|
|
return None
|
|
|
|
|
else:
|
2012-05-01 22:51:18 +02:00
|
|
|
raise Exception(_GA(new_db_object, "typeclass_last_errmsg"))
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-04-21 16:15:37 +02:00
|
|
|
# from now on we can use the typeclass object
|
2010-08-29 18:46:58 +00:00
|
|
|
# as if it was the database object.
|
|
|
|
|
|
2012-04-21 16:15:37 +02:00
|
|
|
new_object.destination = destination
|
2011-08-11 21:16:35 +00:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
# call the hook method. This is where all at_creation
|
|
|
|
|
# customization happens as the typeclass stores custom
|
2012-04-21 16:15:37 +02:00
|
|
|
# things on its database object.
|
2011-03-17 21:43:18 +00:00
|
|
|
new_object.basetype_setup() # setup the basics of Exits, Characters etc.
|
2010-08-29 18:46:58 +00:00
|
|
|
new_object.at_object_creation()
|
2012-04-21 16:15:37 +02:00
|
|
|
|
2011-08-11 21:16:35 +00:00
|
|
|
# custom-given perms/locks overwrite hooks
|
2011-03-15 16:08:32 +00:00
|
|
|
if permissions:
|
2013-08-24 23:57:44 +02:00
|
|
|
new_object.permissions.add(permissions)
|
2011-03-15 16:08:32 +00:00
|
|
|
if locks:
|
2012-05-01 22:51:18 +02:00
|
|
|
new_object.locks.add(locks)
|
2011-08-11 21:16:35 +00:00
|
|
|
if aliases:
|
2013-07-12 15:34:54 +02:00
|
|
|
new_object.aliases.add(aliases)
|
2011-03-15 16:08:32 +00:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
# perform a move_to in order to display eventual messages.
|
|
|
|
|
if home:
|
|
|
|
|
new_object.home = home
|
2013-09-23 22:08:14 +02:00
|
|
|
elif testmode:
|
|
|
|
|
# this is required by unittest
|
|
|
|
|
pass
|
2011-11-06 23:55:24 +01:00
|
|
|
else:
|
2012-05-01 22:51:18 +02:00
|
|
|
new_object.home = settings.CHARACTER_DEFAULT_HOME
|
2011-11-06 23:55:24 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
if location:
|
2013-07-13 15:39:16 +02:00
|
|
|
new_object.move_to(location, quiet=True)
|
2010-08-29 18:46:58 +00:00
|
|
|
else:
|
|
|
|
|
# rooms would have location=None.
|
2012-04-21 16:15:37 +02:00
|
|
|
new_object.location = None
|
2011-08-11 21:16:35 +00:00
|
|
|
|
|
|
|
|
# post-hook setup (mainly used by Exits)
|
2012-04-21 16:15:37 +02:00
|
|
|
new_object.basetype_posthook_setup()
|
2011-08-11 21:16:35 +00:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
new_object.save()
|
|
|
|
|
return new_object
|
|
|
|
|
|
2012-03-25 14:01:51 +02:00
|
|
|
#alias for create_object
|
|
|
|
|
object = create_object
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
2012-04-21 16:15:37 +02:00
|
|
|
# Script creation
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
|
|
|
|
|
2012-04-21 16:15:37 +02:00
|
|
|
def create_script(typeclass, key=None, obj=None, locks=None,
|
|
|
|
|
interval=None, start_delay=None, repeats=None,
|
|
|
|
|
persistent=None, autostart=True, report_to=None):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
Create a new script. All scripts are a combination
|
|
|
|
|
of a database object that communicates with the
|
|
|
|
|
database, and an typeclass that 'decorates' the
|
|
|
|
|
database object into being different types of scripts.
|
|
|
|
|
It's behaviour is similar to the game objects except
|
|
|
|
|
scripts has a time component and are more limited in
|
2012-04-21 16:15:37 +02:00
|
|
|
scope.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
Argument 'typeclass' can be either an actual
|
|
|
|
|
typeclass object or a python path to such an object.
|
|
|
|
|
Only set key here if you want a unique name for this
|
|
|
|
|
particular script (set it in config to give
|
|
|
|
|
same key to all scripts of the same type). Set obj
|
2012-04-21 16:15:37 +02:00
|
|
|
to tie this script to a particular object.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
See src.scripts.manager for methods to manipulate existing
|
|
|
|
|
scripts in the database.
|
2012-04-21 16:15:37 +02:00
|
|
|
|
|
|
|
|
report_to is an obtional object to receive error messages.
|
|
|
|
|
If report_to is not set, an Exception with the
|
|
|
|
|
error will be raised. If set, this method will
|
|
|
|
|
return None upon errors.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-05-01 22:51:18 +02:00
|
|
|
global _Script, _ScriptDB
|
|
|
|
|
if not _Script:
|
|
|
|
|
from src.scripts.scripts import Script as _Script
|
|
|
|
|
if not _ScriptDB:
|
|
|
|
|
from src.scripts.models import ScriptDB as _ScriptDB
|
2011-08-06 18:15:04 +00:00
|
|
|
|
2011-10-01 22:00:22 +02:00
|
|
|
if not typeclass:
|
|
|
|
|
typeclass = settings.BASE_SCRIPT_TYPECLASS
|
2012-05-01 22:51:18 +02:00
|
|
|
elif isinstance(typeclass, _ScriptDB):
|
2011-10-01 22:00:22 +02:00
|
|
|
# this is already an scriptdb instance, extract its typeclass
|
2012-04-21 16:15:37 +02:00
|
|
|
typeclass = typeclass.typeclass.path
|
2012-05-01 22:51:18 +02:00
|
|
|
elif isinstance(typeclass, _Script) or utils.inherits_from(typeclass, _Script):
|
2011-08-06 18:15:04 +00:00
|
|
|
# this is already an object typeclass, extract its path
|
2012-04-21 16:15:37 +02:00
|
|
|
typeclass = typeclass.path
|
2011-10-01 22:00:22 +02:00
|
|
|
|
|
|
|
|
# create new database script
|
2012-05-01 22:51:18 +02:00
|
|
|
new_db_script = _ScriptDB()
|
2011-10-01 22:00:22 +02:00
|
|
|
|
2012-04-21 16:15:37 +02:00
|
|
|
# assign the typeclass
|
2011-08-06 18:15:04 +00:00
|
|
|
typeclass = utils.to_unicode(typeclass)
|
2011-10-01 22:00:22 +02:00
|
|
|
new_db_script.typeclass_path = typeclass
|
2012-04-21 16:15:37 +02:00
|
|
|
|
2011-10-01 22:00:22 +02:00
|
|
|
# the name/key is often set later in the typeclass. This
|
2012-04-21 16:15:37 +02:00
|
|
|
# is set here as a failsafe.
|
2011-10-01 22:00:22 +02:00
|
|
|
if key:
|
|
|
|
|
new_db_script.key = key
|
|
|
|
|
else:
|
|
|
|
|
new_db_script.key = "#%i" % new_db_script.id
|
|
|
|
|
|
2011-08-06 18:15:04 +00:00
|
|
|
# this will either load the typeclass or the default one
|
2011-10-01 22:00:22 +02:00
|
|
|
new_script = new_db_script.typeclass
|
2011-08-06 18:15:04 +00:00
|
|
|
|
2012-05-01 22:51:18 +02:00
|
|
|
if not _GA(new_db_script, "is_typeclass")(typeclass, exact=True):
|
2011-10-01 22:00:22 +02:00
|
|
|
# this will fail if we gave a typeclass as input and it still gave us a default
|
|
|
|
|
SharedMemoryModel.delete(new_db_script)
|
2012-04-21 16:15:37 +02:00
|
|
|
if report_to:
|
2012-05-01 22:51:18 +02:00
|
|
|
_GA(report_to, "msg")("Error creating %s (%s): %s" % (new_db_script.key, typeclass,
|
|
|
|
|
_GA(new_db_script, "typeclass_last_errmsg")))
|
2012-04-21 16:15:37 +02:00
|
|
|
return None
|
|
|
|
|
else:
|
2012-05-01 22:51:18 +02:00
|
|
|
raise Exception(_GA(new_db_script, "typeclass_last_errmsg"))
|
2011-03-15 16:08:32 +00:00
|
|
|
|
2011-04-08 20:06:04 +00:00
|
|
|
if obj:
|
|
|
|
|
try:
|
|
|
|
|
new_script.obj = obj
|
|
|
|
|
except ValueError:
|
2012-04-21 16:15:37 +02:00
|
|
|
new_script.obj = obj.dbobj
|
2011-04-08 20:06:04 +00:00
|
|
|
|
2011-03-15 16:08:32 +00:00
|
|
|
# call the hook method. This is where all at_creation
|
|
|
|
|
# customization happens as the typeclass stores custom
|
|
|
|
|
# things on its database object.
|
|
|
|
|
new_script.at_script_creation()
|
|
|
|
|
|
|
|
|
|
# custom-given variables override the hook
|
2011-03-20 19:45:56 +00:00
|
|
|
if key:
|
2012-04-21 16:15:37 +02:00
|
|
|
new_script.key = key
|
2011-03-15 16:08:32 +00:00
|
|
|
if locks:
|
|
|
|
|
new_script.locks.add(locks)
|
2012-04-21 16:15:37 +02:00
|
|
|
if interval != None:
|
2012-02-15 22:12:50 +01:00
|
|
|
new_script.interval = interval
|
|
|
|
|
if start_delay != None:
|
|
|
|
|
new_script.start_delay = start_delay
|
|
|
|
|
if repeats != None:
|
|
|
|
|
new_script.repeats = repeats
|
|
|
|
|
if persistent != None:
|
|
|
|
|
new_script.persistent = persistent
|
2012-04-21 16:15:37 +02:00
|
|
|
|
2011-03-20 19:45:56 +00:00
|
|
|
# a new created script should usually be started.
|
2010-08-29 18:46:58 +00:00
|
|
|
if autostart:
|
|
|
|
|
new_script.start()
|
2012-04-21 16:15:37 +02:00
|
|
|
|
2011-10-01 22:00:22 +02:00
|
|
|
new_db_script.save()
|
2012-04-21 16:15:37 +02:00
|
|
|
return new_script
|
2012-03-25 14:01:51 +02:00
|
|
|
#alias
|
|
|
|
|
script = create_script
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Help entry creation
|
|
|
|
|
#
|
|
|
|
|
|
2011-03-15 16:08:32 +00:00
|
|
|
def create_help_entry(key, entrytext, category="General", locks=None):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
Create a static help entry in the help database. Note that Command
|
|
|
|
|
help entries are dynamic and directly taken from the __doc__ entries
|
|
|
|
|
of the command. The database-stored help entries are intended for more
|
|
|
|
|
general help on the game, more extensive info, in-game setting information
|
2012-04-21 16:15:37 +02:00
|
|
|
and so on.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-05-01 22:51:18 +02:00
|
|
|
global _HelpEntry
|
|
|
|
|
if not _HelpEntry:
|
|
|
|
|
from src.help.models import HelpEntry as _HelpEntry
|
2010-12-07 02:34:59 +00:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
try:
|
2012-05-01 22:51:18 +02:00
|
|
|
new_help = _HelpEntry()
|
2010-08-29 18:46:58 +00:00
|
|
|
new_help.key = key
|
|
|
|
|
new_help.entrytext = entrytext
|
|
|
|
|
new_help.help_category = category
|
2011-03-15 16:08:32 +00:00
|
|
|
if locks:
|
|
|
|
|
new_help.locks.add(locks)
|
2010-08-29 18:46:58 +00:00
|
|
|
new_help.save()
|
2012-04-21 16:15:37 +02:00
|
|
|
return new_help
|
2010-08-29 18:46:58 +00:00
|
|
|
except IntegrityError:
|
|
|
|
|
string = "Could not add help entry: key '%s' already exists." % key
|
|
|
|
|
logger.log_errmsg(string)
|
|
|
|
|
return None
|
|
|
|
|
except Exception:
|
|
|
|
|
logger.log_trace()
|
2012-04-21 16:15:37 +02:00
|
|
|
return None
|
2012-03-25 14:01:51 +02:00
|
|
|
# alias
|
|
|
|
|
help_entry = create_help_entry
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
#
|
2012-04-21 16:15:37 +02:00
|
|
|
# Comm system methods
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
|
|
|
|
|
|
|
|
|
def create_message(senderobj, message, channels=None,
|
2012-11-04 17:39:06 +01:00
|
|
|
receivers=None, locks=None, header=None):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
Create a new communication message. Msgs are used for all
|
|
|
|
|
player-to-player communication, both between individual players
|
|
|
|
|
and over channels.
|
|
|
|
|
senderobj - the player sending the message. This must be the actual object.
|
|
|
|
|
message - text with the message. Eventual headers, titles etc
|
|
|
|
|
should all be included in this text string. Formatting
|
2012-04-21 16:15:37 +02:00
|
|
|
will be retained.
|
2010-08-29 18:46:58 +00:00
|
|
|
channels - a channel or a list of channels to send to. The channels
|
|
|
|
|
may be actual channel objects or their unique key strings.
|
|
|
|
|
receivers - a player to send to, or a list of them. May be Player objects
|
|
|
|
|
or playernames.
|
2011-03-15 16:08:32 +00:00
|
|
|
locks - lock definition string
|
2012-11-04 17:39:06 +01:00
|
|
|
header - mime-type or other optional information for the message
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
The Comm system is created very open-ended, so it's fully possible
|
|
|
|
|
to let a message both go to several channels and to several receivers
|
|
|
|
|
at the same time, it's up to the command definitions to limit this as
|
2012-04-21 16:15:37 +02:00
|
|
|
desired.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-08-30 00:05:00 +02:00
|
|
|
global _Msg
|
2012-05-01 22:51:18 +02:00
|
|
|
if not _Msg:
|
|
|
|
|
from src.comms.models import Msg as _Msg
|
2010-08-29 18:46:58 +00:00
|
|
|
if not message:
|
2012-04-21 16:15:37 +02:00
|
|
|
# we don't allow empty messages.
|
2010-08-29 18:46:58 +00:00
|
|
|
return
|
2012-08-30 00:05:00 +02:00
|
|
|
new_message = _Msg(db_message=message)
|
2010-08-29 18:46:58 +00:00
|
|
|
new_message.save()
|
2012-08-30 00:05:00 +02:00
|
|
|
for sender in make_iter(senderobj):
|
|
|
|
|
new_message.senders = sender
|
2012-11-04 17:39:06 +01:00
|
|
|
new_message.header = header
|
2012-08-30 00:05:00 +02:00
|
|
|
for channel in make_iter(channels):
|
|
|
|
|
new_message.channels = channel
|
|
|
|
|
for receiver in make_iter(receivers):
|
|
|
|
|
new_message.receivers = receiver
|
2011-03-15 16:08:32 +00:00
|
|
|
if locks:
|
|
|
|
|
new_message.locks.add(locks)
|
2010-08-29 18:46:58 +00:00
|
|
|
new_message.save()
|
|
|
|
|
return new_message
|
2012-03-25 14:01:51 +02:00
|
|
|
message = create_message
|
|
|
|
|
|
2011-02-27 22:27:56 +00:00
|
|
|
def create_channel(key, aliases=None, desc=None,
|
2011-03-15 16:08:32 +00:00
|
|
|
locks=None, keep_log=True):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
Create A communication Channel. A Channel serves as a central
|
|
|
|
|
hub for distributing Msgs to groups of people without
|
|
|
|
|
specifying the receivers explicitly. Instead players may
|
|
|
|
|
'connect' to the channel and follow the flow of messages. By
|
|
|
|
|
default the channel allows access to all old messages, but
|
2012-04-21 16:15:37 +02:00
|
|
|
this can be turned off with the keep_log switch.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-04-21 16:15:37 +02:00
|
|
|
key - this must be unique.
|
2010-08-29 18:46:58 +00:00
|
|
|
aliases - list of alternative (likely shorter) keynames.
|
2011-03-15 16:08:32 +00:00
|
|
|
locks - lock string definitions
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-05-01 22:51:18 +02:00
|
|
|
global _Channel, _channelhandler
|
|
|
|
|
if not _Channel:
|
|
|
|
|
from src.comms.models import Channel as _Channel
|
|
|
|
|
if not _channelhandler:
|
|
|
|
|
from src.comms import channelhandler as _channelhandler
|
2010-08-29 18:46:58 +00:00
|
|
|
try:
|
2012-05-01 22:51:18 +02:00
|
|
|
new_channel = _Channel()
|
2012-04-21 16:15:37 +02:00
|
|
|
new_channel.key = key
|
2010-08-29 18:46:58 +00:00
|
|
|
if aliases:
|
2012-04-21 16:15:37 +02:00
|
|
|
if not utils.is_iter(aliases):
|
2010-08-29 18:46:58 +00:00
|
|
|
aliases = [aliases]
|
2011-04-21 16:45:18 +00:00
|
|
|
new_channel.aliases = ",".join([alias for alias in aliases])
|
2011-02-27 22:27:56 +00:00
|
|
|
new_channel.desc = desc
|
2010-08-29 18:46:58 +00:00
|
|
|
new_channel.keep_log = keep_log
|
|
|
|
|
except IntegrityError:
|
|
|
|
|
string = "Could not add channel: key '%s' already exists." % key
|
|
|
|
|
logger.log_errmsg(string)
|
|
|
|
|
return None
|
2011-03-15 16:08:32 +00:00
|
|
|
if locks:
|
|
|
|
|
new_channel.locks.add(locks)
|
2010-08-29 18:46:58 +00:00
|
|
|
new_channel.save()
|
2012-05-01 22:51:18 +02:00
|
|
|
_channelhandler.CHANNELHANDLER.add_channel(new_channel)
|
2012-04-21 16:15:37 +02:00
|
|
|
return new_channel
|
|
|
|
|
|
|
|
|
|
channel = create_channel
|
2012-03-25 14:01:51 +02:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
2012-04-21 16:15:37 +02:00
|
|
|
# Player creation methods
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
|
|
|
|
|
2013-07-11 18:03:07 +02:00
|
|
|
def create_player(key, email, password,
|
2011-10-01 22:00:22 +02:00
|
|
|
typeclass=None,
|
2012-04-21 16:15:37 +02:00
|
|
|
is_superuser=False,
|
2011-10-01 22:00:22 +02:00
|
|
|
locks=None, permissions=None,
|
2013-07-11 18:03:07 +02:00
|
|
|
report_to=None):
|
2012-04-21 16:15:37 +02:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2013-07-11 18:03:07 +02:00
|
|
|
This creates a new player.
|
2011-11-13 18:46:14 +01:00
|
|
|
|
2013-07-11 18:03:07 +02:00
|
|
|
key - the player's name. This should be unique.
|
|
|
|
|
email - email on valid addr@addr.domain form.
|
|
|
|
|
password - password in cleartext
|
|
|
|
|
is_superuser - wether or not this player is to be a superuser
|
|
|
|
|
locks - lockstring
|
|
|
|
|
permission - list of permissions
|
|
|
|
|
report_to - an object with a msg() method to report errors to. If
|
|
|
|
|
not given, errors will be logged.
|
2012-04-21 16:15:37 +02:00
|
|
|
|
2013-07-11 18:03:07 +02:00
|
|
|
Will return the Player-typeclass or None/raise Exception if the
|
|
|
|
|
Typeclass given failed to load.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
Concerning is_superuser:
|
2011-10-01 22:00:22 +02:00
|
|
|
Usually only the server admin should need to be superuser, all
|
|
|
|
|
other access levels can be handled with more fine-grained
|
2013-07-11 18:03:07 +02:00
|
|
|
permissions or groups. A superuser bypasses all lock checking
|
|
|
|
|
operations and is thus not suitable for play-testing the game.
|
2012-04-21 16:15:37 +02:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-05-01 22:51:18 +02:00
|
|
|
global _PlayerDB, _Player
|
|
|
|
|
if not _PlayerDB:
|
|
|
|
|
from src.players.models import PlayerDB as _PlayerDB
|
|
|
|
|
if not _Player:
|
|
|
|
|
from src.players.player import Player as _Player
|
2012-04-21 16:15:37 +02:00
|
|
|
|
2011-11-06 17:38:29 +01:00
|
|
|
if not email:
|
|
|
|
|
email = "dummy@dummy.com"
|
2013-07-11 18:03:07 +02:00
|
|
|
if _PlayerDB.objects.filter(username__iexact=key):
|
|
|
|
|
raise ValueError("A Player with this name already exists.")
|
|
|
|
|
try:
|
2013-05-13 12:30:00 -05:00
|
|
|
|
2013-07-11 18:03:07 +02:00
|
|
|
# create the correct Player object
|
2010-08-29 18:46:58 +00:00
|
|
|
if is_superuser:
|
2013-07-11 18:03:07 +02:00
|
|
|
new_db_player = _PlayerDB.objects.create_superuser(key, email, password)
|
2010-08-29 18:46:58 +00:00
|
|
|
else:
|
2013-07-11 18:03:07 +02:00
|
|
|
new_db_player = _PlayerDB.objects.create_user(key, email, password)
|
|
|
|
|
|
2011-10-09 16:32:55 +02:00
|
|
|
if not typeclass:
|
|
|
|
|
typeclass = settings.BASE_PLAYER_TYPECLASS
|
2012-05-01 22:51:18 +02:00
|
|
|
elif isinstance(typeclass, _PlayerDB):
|
2013-07-11 18:03:07 +02:00
|
|
|
# this is an PlayerDB instance, extract its typeclass path
|
2011-10-09 16:32:55 +02:00
|
|
|
typeclass = typeclass.typeclass.path
|
2012-05-01 22:51:18 +02:00
|
|
|
elif isinstance(typeclass, _Player) or utils.inherits_from(typeclass, _Player):
|
2013-07-11 18:03:07 +02:00
|
|
|
# this is Player object typeclass, extract its path
|
2012-04-21 16:15:37 +02:00
|
|
|
typeclass = typeclass.path
|
2013-07-11 18:03:07 +02:00
|
|
|
|
|
|
|
|
# assign the typeclass
|
|
|
|
|
typeclass = utils.to_unicode(typeclass)
|
|
|
|
|
new_db_player.typeclass_path = typeclass
|
2011-10-09 16:32:55 +02:00
|
|
|
|
|
|
|
|
# this will either load the typeclass or the default one
|
|
|
|
|
new_player = new_db_player.typeclass
|
|
|
|
|
|
2012-05-01 22:51:18 +02:00
|
|
|
if not _GA(new_db_player, "is_typeclass")(typeclass, exact=True):
|
2011-10-09 16:32:55 +02:00
|
|
|
# this will fail if we gave a typeclass as input and it still gave us a default
|
|
|
|
|
SharedMemoryModel.delete(new_db_player)
|
2012-04-21 16:15:37 +02:00
|
|
|
if report_to:
|
2012-05-01 22:51:18 +02:00
|
|
|
_GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_player.key, typeclass,
|
2012-11-05 00:55:25 +01:00
|
|
|
_GA(new_db_player, "typeclass_last_errmsg")))
|
2012-04-21 16:15:37 +02:00
|
|
|
return None
|
|
|
|
|
else:
|
2012-05-01 22:51:18 +02:00
|
|
|
raise Exception(_GA(new_db_player, "typeclass_last_errmsg"))
|
2011-10-01 22:00:22 +02:00
|
|
|
|
2011-10-09 16:32:55 +02:00
|
|
|
new_player.basetype_setup() # setup the basic locks and cmdset
|
|
|
|
|
# call hook method (may override default permissions)
|
|
|
|
|
new_player.at_player_creation()
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-04-21 16:15:37 +02:00
|
|
|
# custom given arguments potentially overrides the hook
|
2011-10-09 16:32:55 +02:00
|
|
|
if permissions:
|
2013-08-24 23:57:44 +02:00
|
|
|
new_player.permissions.add(permissions)
|
2011-10-09 16:32:55 +02:00
|
|
|
elif not new_player.permissions:
|
2013-08-24 23:57:44 +02:00
|
|
|
new_player.permissions.add(settings.PERMISSION_PLAYER_DEFAULT)
|
2011-10-09 16:32:55 +02:00
|
|
|
if locks:
|
|
|
|
|
new_player.locks.add(locks)
|
|
|
|
|
return new_player
|
2013-07-11 18:03:07 +02:00
|
|
|
|
2013-02-03 00:25:06 +01:00
|
|
|
except Exception:
|
2013-07-11 18:03:07 +02:00
|
|
|
# a failure in creating the player; we try to clean
|
|
|
|
|
# up as much as we can
|
|
|
|
|
logger.log_trace()
|
|
|
|
|
try:
|
|
|
|
|
new_player.delete()
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
try:
|
|
|
|
|
del new_player
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
2013-02-03 00:25:06 +01:00
|
|
|
raise
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-03-25 14:01:51 +02:00
|
|
|
# alias
|
|
|
|
|
player = create_player
|