Added new templates to gamesrc/*/examples. The old base* modules still in place. Some cleanup of the API.

This commit is contained in:
Griatch 2012-03-25 16:35:22 +02:00
parent 3408f3ca3f
commit 4398d42360
12 changed files with 686 additions and 11 deletions

2
ev.py
View file

@ -6,7 +6,7 @@ This basically a set of shortcuts to the main modules in src/.
Import this from ./manage.py shell or set DJANGO_SETTINGS_MODULE manually for proper
functionality.
1) You should import things excplicitly from the root of this module - you can generally
1) You should import things explicitly from the root of this module - you can generally
not use dot-notation to import deeper. Hence, to access a default command, you can do
the following:

View file

@ -0,0 +1,116 @@
"""
Example command set template module.
To create new commands to populate the cmdset, see
examples/command.py.
To extend the default command set:
- copy this file up one level to gamesrc/commands and name it
something fitting.
- change settings.CMDSET_DEFAULT to point to the new module's
DefaultCmdSet
- import/add commands at the end of DefaultCmdSet's add() method.
To add a new command set
- copy this file up one level to gamesrc/commands and name it
something fitting.
- add a new cmdset class
- add it objects with obj.cmdset.add(path.to.the.module.and.class)
"""
from ev import CmdSet, Command
from ev import default_cmds
#from contrib import menusystem, lineeditor
#from contrib import misc_commands
#from contrib import chargen
class ExampleCmdSet(CmdSet):
"""
Implements an empty, example cmdset.
"""
key = "ExampleSet"
def at_cmdset_creation(self):
"""
This is the only method defined in a cmdset, called during
its creation. It should populate the set with command instances.
Here we just add the empty base Command object. It prints some info.
"""
self.add(Command())
class DefaultCmdSet(default_cmds.DefaultCmdSet):
"""
This is an example of how to overload the default command
set defined in src/commands/default/cmdset_default.py.
Here we copy everything by calling the parent, but you can
copy&paste any combination of the default command to customize
your default set. Next you change settings.CMDSET_DEFAULT to point
to this class.
"""
key = "DefaultMUX"
def at_cmdset_creation(self):
"""
Populates the cmdset
"""
# calling setup in src.commands.default.cmdset_default
super(DefaultCmdSet, self).at_cmdset_creation()
#
# any commands you add below will overload the default ones.
#
#self.add(menusystem.CmdMenuTest())
#self.add(lineeditor.CmdEditor())
#self.add(misc_commands.CmdQuell())
class UnloggedinCmdSet(default_cmds.UnloggedinCmdSet):
"""
This is an example of how to overload the command set of the
unloggedin commands, defined in
src/commands/default/cmdset_unloggedin.py.
Here we copy everything by calling the parent, but you can
copy&paste any combination of the default command to customize
your default set. Next you change settings.CMDSET_UNLOGGEDIN to
point to this class.
"""
key = "Unloggedin"
def at_cmdset_creation(self):
"""
Populates the cmdset
"""
# calling setup in src.commands.default.cmdset_unloggedin
super(UnloggedinCmdSet, self).at_cmdset_creation()
#
# any commands you add below will overload the default ones.
#
class OOCCmdSet(default_cmds.OOCCmdSet):
"""
This is set is available to the player when they have no
character connected to them (i.e. they are out-of-character, ooc).
"""
key = "OOC"
def at_cmdset_creation(self):
"""
Populates the cmdset
"""
# calling setup in src.commands.default.cmdset_ooc
super(OOCCmdSet, self).at_cmdset_creation()
#
# any commands you add below will overload the default ones.
#

View file

@ -0,0 +1,132 @@
"""
Example command module template
Copy this module up one level to gamesrc/commands/ and name it as
befits your use. You can then use it as a template to define your new
commands. To use them you also need to group them in a CommandSet (see
examples/cmdset.py)
"""
from ev import Command as BaseCommand
from ev import default_cmd
from ev import utils
class Command(BaseCommand):
"""
Inherit from this if you want to create your own
command styles. Note that Evennia's default commands
use MuxCommand instead (next in this module)
Note that the class's __doc__ string (this text) is
used by Evennia to create the automatic help entry for
the command, so make sure to document consistently here.
"""
# these need to be specified
key = "MyCommand"
aliases = ["mycmd", "myc"]
locks = "cmd:all()"
help_category = "General"
# auto_help = False # uncomment to deactive auto-help for this command.
# arg_regex = r"\s.*?|$" # optional regex detailing how the part after
# the cmdname must look to match this command.
# (we don't implement hook method access() here, you don't need to
# modify that unless you want to change how the lock system works
# (in that case see src.commands.command.Command))
def at_pre_cmd(self):
"""
This hook is called before self.parse() on all commands
"""
pass
def parse(self):
"""
This method is called by the cmdhandler once the command name
has been identified. It creates a new set of member variables
that can be later accessed from self.func() (see below)
The following variables are available to us:
# class variables:
self.key - the name of this command ('mycommand')
self.aliases - the aliases of this cmd ('mycmd','myc')
self.locks - lock string for this command ("cmd:all()")
self.help_category - overall category of command ("General")
# added at run-time by cmdhandler:
self.caller - the object calling this command
self.cmdstring - the actual command name used to call this
(this allows you to know which alias was used,
for example)
self.args - the raw input; everything following self.cmdstring.
self.cmdset - the cmdset from which this command was picked. Not
often used (useful for commands like 'help' or to
list all available commands etc)
self.obj - the object on which this command was defined. It is often
the same as self.caller.
"""
pass
def func(self):
"""
This is the hook function that actually does all the work. It is called
by the cmdhandler right after self.parser() finishes, and so has access
to all the variables defined therein.
"""
self.caller.msg("Command called!")
def at_post_cmd(self):
"""
This hook is called after self.func().
"""
pass
class MuxCommand(default_cmd.MuxCommand):
"""
This sets up the basis for a Evennia's 'MUX-like' command
style. The idea is that most other Mux-related commands should
just inherit from this and don't have to implement parsing of
their own unless they do something particularly advanced.
A MUXCommand command understands the following possible syntax:
name[ with several words][/switch[/switch..]] arg1[,arg2,...] [[=|,] arg[,..]]
The 'name[ with several words]' part is already dealt with by the
cmdhandler at this point, and stored in self.cmdname. The rest is stored
in self.args.
The MuxCommand parser breaks self.args into its constituents and stores them in the
following variables:
self.switches = optional list of /switches (without the /)
self.raw = This is the raw argument input, including switches
self.args = This is re-defined to be everything *except* the switches
self.lhs = Everything to the left of = (lhs:'left-hand side'). If
no = is found, this is identical to self.args.
self.rhs: Everything to the right of = (rhs:'right-hand side').
If no '=' is found, this is None.
self.lhslist - self.lhs split into a list by comma
self.rhslist - list of self.rhs split into a list by comma
self.arglist = list of space-separated args (including '=' if it exists)
All args and list members are stripped of excess whitespace around the
strings, but case is preserved.
"""
def func(self):
"""
This is the hook function that actually does all the work. It is called
by the cmdhandler right after self.parser() finishes, and so has access
to all the variables defined therein.
"""
# this can be removed in your child class, it's just
# printing the ingoing variables as a demo.
super(MuxCommand, self).func()

View file

@ -0,0 +1,41 @@
"""
Template for Characters
Copy this module up one level and name it as you like, then
use it as a template to create your own Character class.
To make new logins default to creating characters
of your new type, change settings.BASE_CHARACTER_TYPECLASS to point to
your new class, e.g.
settings.BASE_CHARACTER_TYPECLASS = "game.gamesrc.objects.mychar.MyChar"
Note that objects already created in the database will not notice
this change, you have to convert them manually e.g. with the
@typeclass command.
"""
from ev import Character
class ExampleCharacter(Character):
"""
The Character is like any normal Object (see example/object.py for
a list of properties and methods), except it actually implements
some of its hook methods to do some work:
at_basetype_setup - always assigns the default_cmdset to this object type
(important!)sets locks so character cannot be picked up
and its commands only be called by itself, not anyone else.
(to change things, use at_object_creation() instead)
at_after_move - launches the "look" command
at_disconnect - stores the current location, so the "unconnected" character
object does not need to stay on grid but can be given a
None-location while offline.
at_post_login - retrieves the character's old location and puts it back
on the grid with a "charname has connected" message echoed
to the room
"""
pass

View file

@ -0,0 +1,43 @@
"""
Template module for Exits
Copy this module up one level and name it as you like, then
use it as a template to create your own Exits.
To make the default commands (such as @dig/@open) default to creating exits
of your new type, change settings.BASE_EXIT_TYPECLASS to point to
your new class, e.g.
settings.BASE_EXIT_TYPECLASS = "game.gamesrc.objects.myexit.MyExit"
Note that objects already created in the database will not notice
this change, you have to convert them manually e.g. with the
@typeclass command.
"""
from ev import Exit
class ExampleExit(Exit):
"""
Exits are connectors between rooms. Exits are normal Objects except
they defines the 'destination' property. It also does work in the
following methods:
basetype_setup() - sets default exit locks (to change, use at_object_creation instead)
at_cmdset_get() - this auto-creates and caches a command and a command set on itself
with the same name as the Exit object. This
allows users to use the exit by only giving its
name alone on the command line.
at_failed_traverse() - gives a default error message ("You cannot
go there") if exit traversal fails and an
attribute err_traverse is not defined.
Relevant hooks to overload (compared to other types of Objects):
at_before_traverse(traveller) - called just before traversing
at_after_traverse(traveller, source_loc) - called just after traversing
at_failed_traverse(traveller) - called if traversal failed for some reason. Will
not be called if the attribute 'err_traverse' is
defined, in which case that will simply be echoed.
"""
pass

View file

@ -0,0 +1,123 @@
"""
Template for Objects
Copy this module up one level and name it as you like, then
use it as a template to create your own Objects.
To make the default commands default to creating objects of your new
type (and also change the "fallback" object used when typeclass
creation fails), change settings.BASE_OBJECT_TYPECLASS to point to
your new class, e.g.
settings.BASE_OBJECT_TYPECLASS = "game.gamesrc.objects.myobj.MyObj"
Note that objects already created in the database will not notice
this change, you have to convert them manually e.g. with the
@typeclass command.
"""
from ev import Object
class ExampleObject(Object):
"""
This is the root typeclass object, implementing an in-game Evennia
game object, such as having a location, being able to be
manipulated or looked at, etc. If you create a new typeclass, it
must always inherit from this object (or any of the other objects
in this file, since they all actually inherit from BaseObject, as
seen in src.object.objects).
The BaseObject class implements several hooks tying into the game
engine. By re-implementing these hooks you can control the
system. You should never need to re-implement special Python
methods, such as __init__ and especially never __getattribute__ and
__setattr__ since these are used heavily by the typeclass system
of Evennia and messing with them might well break things for you.
* Base properties defined/available on all Objects
key (string) - name of object
name (string)- same as key
aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings.
dbref (int, read-only) - unique #id-number. Also "id" can be used.
dbobj (Object, read-only) - link to database model. dbobj.typeclass points back to this class
typeclass (Object, read-only) - this links back to this class as an identified only. Use self.swap_typeclass() to switch.
date_created (string) - time stamp of object creation
permissions (list of strings) - list of permission strings
player (Player) - controlling player (will also return offline player)
location (Object) - current location. Is None if this is a room
home (Object) - safety start-location
sessions (list of Sessions, read-only) - returns all sessions connected to this object
has_player (bool, read-only)- will only return *connected* players
contents (list of Objects, read-only) - returns all objects inside this object (including exits)
exits (list of Objects, read-only) - returns all exits from this object, if any
destination (Object) - only set if this object is an exit.
is_superuser (bool, read-only) - True/False if this user is a superuser
* Handlers available
locks - lock-handler: use locks.add() to add new lock strings
db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr
ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data
scripts - script-handler. Add new scripts to object with scripts.add()
cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object
nicks - nick-handler. New nicks with nicks.add().
* Helper methods (see src.objects.objects.py for full headers)
search(ostring, global_search=False, attribute_name=None, use_nicks=False, location=None, ignore_errors=False, player=False)
execute_cmd(raw_string)
msg(message, from_obj=None, data=None)
msg_contents(message, exclude=None, from_obj=None, data=None)
move_to(destination, quiet=False, emit_to_obj=None, use_destination=True)
copy(new_key=None)
delete()
is_typeclass(typeclass, exact=False)
swap_typeclass(new_typeclass, clean_attributes=False, no_default=True)
access(accessing_obj, access_type='read', default=False)
check_permstring(permstring)
* Hooks (these are class methods, so their arguments should also start with self):
basetype_setup() - only called once, used for behind-the-scenes setup. Normally not modified.
basetype_posthook_setup() - customization in basetype, after the object has been created; Normally not modified.
at_object_creation() - only called once, when object is first created. Object customizations go here.
at_object_delete() - called just before deleting an object. If returning False, deletion is aborted. Note that all objects
inside a deleted object are automatically moved to their <home>, they don't need to be removed here.
at_init() - called whenever typeclass is cached from memory, at least once every server restart/reload
at_cmdset_get() - this is called just before the command handler requests a cmdset from this object
at_first_login() - (player-controlled objects only) called once, the very first time user logs in.
at_pre_login() - (player-controlled objects only) called every time the user connects, after they have identified, before other setup
at_post_login() - (player-controlled objects only) called at the end of login, just before setting the player loose in the world.
at_disconnect() - (player-controlled objects only) called just before the user disconnects (or goes linkless)
at_server_reload() - called before server is reloaded
at_server_shutdown() - called just before server is fully shut down
at_before_move(destination) - called just before moving object to the destination. If returns False, move is cancelled.
announce_move_from(destination) - called in old location, just before move, if obj.move_to() has quiet=False
announce_move_to(source_location) - called in new location, just after move, if obj.move_to() has quiet=False
at_after_move(source_location) - always called after a move has been successfully performed.
at_object_leave(obj, target_location) - called when an object leaves this object in any fashion
at_object_receive(obj, source_location) - called when this object receives another object
at_before_traverse(traversing_object) - (exit-objects only) called just before an object traverses this object
at_after_traverse(traversing_object, source_location) - (exit-objects only) called just after a traversal has happened.
at_failed_traverse(traversing_object) - (exit-objects only) called if traversal fails and property err_traverse is not defined.
at_msg_receive(self, msg, from_obj=None, data=None) - called when a message (via self.msg()) is sent to this obj.
If returns false, aborts send.
at_msg_send(self, msg, to_obj=None, data=None) - called when this objects sends a message to someone via self.msg().
return_appearance(looker) - describes this object. Used by "look" command by default
at_desc(looker=None) - called by 'look' whenever the appearance is requested.
at_get(getter) - called after object has been picked up. Does not stop pickup.
at_drop(dropper) - called when this object has been dropped.
at_say(speaker, message) - by default, called if an object inside this object speaks
"""
pass

View file

@ -0,0 +1,90 @@
"""
Template module for Players
Copy this module up one level and name it as you like, then
use it as a template to create your own Player class.
To make the default account login default to using a Player
of your new type, change settings.BASE_PLAYER_TYPECLASS to point to
your new class, e.g.
settings.BASE_PLAYER_TYPECLASS = "game.gamesrc.objects.myplayer.MyPlayer"
Note that objects already created in the database will not notice
this change, you have to convert them manually e.g. with the
@typeclass command.
"""
from ev import Player
class ExamplePlayer(Player):
"""
This class describes the actual OOC player (i.e. the user connecting
to the MUD). It does NOT have visual appearance in the game world (that
is handled by the character which is connected to this). Comm channels
are attended/joined using this object.
It can be useful e.g. for storing configuration options for your game, but
should generally not hold any character-related info (that's best handled
on the character level).
Can be set using BASE_PLAYER_TYPECLASS.
* available properties
key (string) - name of player
name (string)- wrapper for user.username
aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings.
dbref (int, read-only) - unique #id-number. Also "id" can be used.
dbobj (Player, read-only) - link to database model. dbobj.typeclass points back to this class
typeclass (Player, read-only) - this links back to this class as an identified only. Use self.swap_typeclass() to switch.
date_created (string) - time stamp of object creation
permissions (list of strings) - list of permission strings
user (User, read-only) - django User authorization object
obj (Object) - game object controlled by player. 'character' can also be used.
sessions (list of Sessions) - sessions connected to this player
is_superuser (bool, read-only) - if the connected user is a superuser
* Handlers
locks - lock-handler: use locks.add() to add new lock strings
db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr
ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data
scripts - script-handler. Add new scripts to object with scripts.add()
cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object
nicks - nick-handler. New nicks with nicks.add().
* Helper methods
msg(outgoing_string, from_obj=None, data=None)
swap_character(new_character, delete_old_character=False)
execute_cmd(raw_string)
search(ostring, global_search=False, attribute_name=None, use_nicks=False, location=None, ignore_errors=False, player=False)
is_typeclass(typeclass, exact=False)
swap_typeclass(new_typeclass, clean_attributes=False, no_default=True)
access(accessing_obj, access_type='read', default=False)
check_permstring(permstring)
* Hook methods (when re-implementation, remember methods need to have self as first arg)
basetype_setup()
at_player_creation()
- note that the following hooks are also found on Objects and are
usually handled on the character level:
at_init()
at_cmdset_get()
at_first_login()
at_post_login()
at_disconnect()
at_message_receive()
at_message_send()
at_server_reload()
at_server_shutdown()
"""
pass

View file

@ -0,0 +1,32 @@
"""
Template module for Rooms
Copy this module up one level and name it as you like, then
use it as a template to create your own Objects.
To make the default commands (such as @dig) default to creating rooms
of your new type, change settings.BASE_ROOM_TYPECLASS to point to
your new class, e.g.
settings.BASE_ROOM_TYPECLASS = "game.gamesrc.objects.myroom.MyRoom"
Note that objects already created in the database will not notice
this change, you have to convert them manually e.g. with the
@typeclass command.
"""
from ev import Room
class ExampleRoom(Room):
"""
Rooms are like any Object, except their location is None
(which is default). They also use basetype_setup() to
add locks so they cannot be puppeted or picked up.
(to change that, use at_object_creation instead)
See examples/object.py for a list of
properties and methods available on all Objects.
"""
pass

View file

@ -1,5 +1,13 @@
"""
The base object to inherit from when implementing new Scripts.
Template module for Scripts
Copy this module up one level to gamesrc/scripts and name it
appropriately, then use that as a template to create your own script.
Test scripts in-game e.g. with the @script command. In code you can
create new scripts of a given class with
script = ev.create.script("path.to.module.and.class")
Scripts are objects that handle everything in the game having
a time-component (i.e. that may change with time, with or without
@ -10,17 +18,13 @@ checking if its state changes, so as to update it. Evennia use several
in-built scripts to keep track of things like time, to clean out
dropped connections etc.
New Script objects (from these classes) are created using the
src.utils.create.create_script(scriptclass, ...) where scriptclass
is the python path to the specific class of script you want to use.
"""
from ev import Script as BaseScript
class Script(BaseScript):
"""
All scripts should inherit from this class and implement
some or all of its hook functions and variables.
A script type is customized by redefining some or all of its hook methods and variables.
* available properties

View file

@ -0,0 +1,87 @@
"""
Template module for Scripts
Copy this module up one level to gamesrc/scripts and name it
appropriately, then use that as a template to create your own script.
Test scripts in-game e.g. with the @script command. In code you can
create new scripts of a given class with
script = ev.create.script("path.to.module.and.class")
Scripts are objects that handle everything in the game having
a time-component (i.e. that may change with time, with or without
a player being involved in the change). Scripts can work like "events",
in that they are triggered at regular intervals to do a certain script,
but an Script set on an object can also be responsible for silently
checking if its state changes, so as to update it. Evennia use several
in-built scripts to keep track of things like time, to clean out
dropped connections etc.
"""
from ev import Script
class ExampleScript(BaseScript):
"""
A script type is customized by redefining some or all of its hook methods and variables.
* available properties
key (string) - name of object
name (string)- same as key
aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings.
dbref (int, read-only) - unique #id-number. Also "id" can be used.
dbobj (Object, read-only) - link to database model. dbobj.typeclass points back to this class
typeclass (Object, read-only) - this links back to this class as an identified only. Use self.swap_typeclass() to switch.
date_created (string) - time stamp of object creation
permissions (list of strings) - list of permission strings
desc (string) - optional description of script, shown in listings
obj (Object) - optional object that this script is connected to and acts on (set automatically by obj.scripts.add())
interval (int) - how often script should run, in seconds. <0 turns off ticker
start_delay (bool) - if the script should start repeating right away or wait self.interval seconds
repeats (int) - how many times the script should repeat before stopping. 0 means infinite repeats
persistent (bool) - if script should survive a server shutdown or not
is_active (bool) - if script is currently running
* Handlers
locks - lock-handler: use locks.add() to add new lock strings
db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr
ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data
* Helper methods
start() - start script (this usually happens automatically at creation and obj.script.add() etc)
stop() - stop script, and delete it
pause() - put the script on hold, until unpause() is called. If script is persistent, the pause state will survive a shutdown.
unpause() - restart a previously paused script. The script will continue as if it was never paused.
time_until_next_repeat() - if a timed script (interval>0), returns time until next tick
* Hook methods (should also include self as the first argument):
at_script_creation() - called only once, when an object of this
class is first created.
is_valid() - is called to check if the script is valid to be running
at the current time. If is_valid() returns False, the running
script is stopped and removed from the game. You can use this
to check state changes (i.e. an script tracking some combat
stats at regular intervals is only valid to run while there is
actual combat going on).
at_start() - Called every time the script is started, which for persistent
scripts is at least once every server start. Note that this is
unaffected by self.delay_start, which only delays the first call
to at_repeat().
at_repeat() - Called every self.interval seconds. It will be called immediately
upon launch unless self.delay_start is True, which will delay
the first call of this method by self.interval seconds. If
self.interval==0, this method will never be called.
at_stop() - Called as the script object is stopped and is about to be removed from
the game, e.g. because is_valid() returned False.
at_server_reload() - Called when server reloads. Can be used to save temporary
variables you want should survive a reload.
at_server_shutdown() - called at a full server shutdown.
"""
pass

View file

@ -1066,6 +1066,7 @@ class TypedObject(SharedMemoryModel):
to create a new object and just swap the player over to
that one instead.
Arguments:
new_typeclass (path/classobj) - type to switch to
clean_attributes (bool/list) - will delete all attributes
stored on this object (but not any
@ -1079,6 +1080,9 @@ class TypedObject(SharedMemoryModel):
swapping to a default typeclass in case the given
one fails for some reason. Instead the old one
will be preserved.
Returns:
boolean True/False depending on if the swap worked or not.
"""
if callable(new_typeclass):
# this is an actual class object - build the path

View file

@ -32,10 +32,13 @@ from src.utils.utils import is_iter, has_parent, inherits_from
# limit symbol import from API
__all__ = ("object", "script", "help_entry", "message", "channel", "player")
GA = object.__getattribute__
#
# Game Object creation
#
def create_object(typeclass, key=None, location=None,
home=None, player=None, permissions=None, locks=None,
aliases=None, destination=None):
@ -81,7 +84,7 @@ def create_object(typeclass, key=None, location=None,
new_object = new_db_object.typeclass
if not object.__getattribute__(new_db_object, "is_typeclass")(typeclass, exact=True):
if not GA(new_db_object, "is_typeclass")(typeclass, exact=True):
# this will fail if we gave a typeclass as input and it still gave us a default
SharedMemoryModel.delete(new_db_object)
return None
@ -190,7 +193,7 @@ def create_script(typeclass, key=None, obj=None, locks=None,
# this will either load the typeclass or the default one
new_script = new_db_script.typeclass
if not object.__getattribute__(new_db_script, "is_typeclass")(typeclass, exact=True):
if not GA(new_db_script, "is_typeclass")(typeclass, exact=True):
# this will fail if we gave a typeclass as input and it still gave us a default
print "failure:", new_db_script, typeclass
SharedMemoryModel.delete(new_db_script)
@ -462,7 +465,7 @@ def create_player(name, email, password,
# this will either load the typeclass or the default one
new_player = new_db_player.typeclass
if not object.__getattribute__(new_db_player, "is_typeclass")(typeclass, exact=True):
if not GA(new_db_player, "is_typeclass")(typeclass, exact=True):
# this will fail if we gave a typeclass as input and it still gave us a default
SharedMemoryModel.delete(new_db_player)
return None
@ -494,7 +497,6 @@ def create_player(name, email, password,
return new_player
except Exception,e:
# a failure in creating the character
print e
if not user:
# in there was a failure we clean up everything we can
logger.log_trace()
@ -510,6 +512,7 @@ def create_player(name, email, password,
del new_character
except Exception:
pass
raise
# alias
player = create_player