Moved Players over to the new proxy system, made the start-hook called by the save-signal system into at_first_save()
This commit is contained in:
parent
db512cbbf5
commit
9af9f94fa0
9 changed files with 465 additions and 584 deletions
|
|
@ -840,7 +840,7 @@ class DefaultObject(ObjectDB):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def at_instance_creation(self):
|
def at_first_save(self):
|
||||||
"""
|
"""
|
||||||
This is called by the typeclass system whenever an instance of
|
This is called by the typeclass system whenever an instance of
|
||||||
this class is saved for the first time. It is a generic hook
|
this class is saved for the first time. It is a generic hook
|
||||||
|
|
@ -874,6 +874,7 @@ class DefaultObject(ObjectDB):
|
||||||
updates.append("db_destination")
|
updates.append("db_destination")
|
||||||
if updates:
|
if updates:
|
||||||
self.save(update_fields=updates)
|
self.save(update_fields=updates)
|
||||||
|
|
||||||
if cdict["permissions"]:
|
if cdict["permissions"]:
|
||||||
self.permissions.add(cdict["permissions"])
|
self.permissions.add(cdict["permissions"])
|
||||||
if cdict["locks"]:
|
if cdict["locks"]:
|
||||||
|
|
@ -883,6 +884,7 @@ class DefaultObject(ObjectDB):
|
||||||
if cdict["location"]:
|
if cdict["location"]:
|
||||||
cdict["location"].at_object_receive(self, None)
|
cdict["location"].at_object_receive(self, None)
|
||||||
self.at_after_move(None)
|
self.at_after_move(None)
|
||||||
|
del self._createdict
|
||||||
|
|
||||||
self.basetype_posthook_setup()
|
self.basetype_posthook_setup()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ class PlayerDBManager(TypedObjectManager, UserManager):
|
||||||
get_player_from_uid
|
get_player_from_uid
|
||||||
get_player_from_name
|
get_player_from_name
|
||||||
player_search (equivalent to ev.search_player)
|
player_search (equivalent to ev.search_player)
|
||||||
swap_character
|
#swap_character
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def num_total_players(self):
|
def num_total_players(self):
|
||||||
|
|
@ -123,33 +123,33 @@ class PlayerDBManager(TypedObjectManager, UserManager):
|
||||||
else:
|
else:
|
||||||
return self.filter(username__icontains=ostring)
|
return self.filter(username__icontains=ostring)
|
||||||
|
|
||||||
def swap_character(self, player, new_character, delete_old_character=False):
|
# def swap_character(self, player, new_character, delete_old_character=False):
|
||||||
"""
|
# """
|
||||||
This disconnects a player from the current character (if any) and
|
# This disconnects a player from the current character (if any) and
|
||||||
connects to a new character object.
|
# connects to a new character object.
|
||||||
|
#
|
||||||
"""
|
# """
|
||||||
|
#
|
||||||
if new_character.player:
|
# if new_character.player:
|
||||||
# the new character is already linked to a player!
|
# # the new character is already linked to a player!
|
||||||
return False
|
# return False
|
||||||
|
#
|
||||||
# do the swap
|
# # do the swap
|
||||||
old_character = player.character
|
# old_character = player.character
|
||||||
if old_character:
|
# if old_character:
|
||||||
old_character.player = None
|
# old_character.player = None
|
||||||
try:
|
# try:
|
||||||
player.character = new_character
|
# player.character = new_character
|
||||||
new_character.player = player
|
# new_character.player = player
|
||||||
except Exception:
|
# except Exception:
|
||||||
# recover old setup
|
# # recover old setup
|
||||||
if old_character:
|
# if old_character:
|
||||||
old_character.player = player
|
# old_character.player = player
|
||||||
player.character = old_character
|
# player.character = old_character
|
||||||
return False
|
# return False
|
||||||
if old_character and delete_old_character:
|
# if old_character and delete_old_character:
|
||||||
old_character.delete()
|
# old_character.delete()
|
||||||
return True
|
# return True
|
||||||
|
|
||||||
class PlayerManager(PlayerDBManager, TypeclassManager):
|
class PlayerManager(PlayerDBManager, TypeclassManager):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -22,21 +22,14 @@ from django.contrib.auth.models import AbstractUser
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import smart_str
|
||||||
|
|
||||||
from src.players.manager import PlayerDBManager
|
from src.players.manager import PlayerDBManager
|
||||||
from src.scripts.models import ScriptDB
|
|
||||||
from src.typeclasses.models import TypedObject
|
from src.typeclasses.models import TypedObject
|
||||||
from src.commands import cmdhandler
|
from src.utils.utils import make_iter
|
||||||
from src.utils import utils, logger
|
|
||||||
from src.utils.utils import to_str, make_iter
|
|
||||||
|
|
||||||
from django.utils.translation import ugettext as _
|
|
||||||
|
|
||||||
__all__ = ("PlayerDB",)
|
__all__ = ("PlayerDB",)
|
||||||
|
|
||||||
#_ME = _("me")
|
#_ME = _("me")
|
||||||
#_SELF = _("self")
|
#_SELF = _("self")
|
||||||
|
|
||||||
_SESSIONS = None
|
|
||||||
_AT_SEARCH_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
|
||||||
_MULTISESSION_MODE = settings.MULTISESSION_MODE
|
_MULTISESSION_MODE = settings.MULTISESSION_MODE
|
||||||
|
|
||||||
_GA = object.__getattribute__
|
_GA = object.__getattribute__
|
||||||
|
|
@ -147,7 +140,7 @@ class PlayerDB(TypedObject, AbstractUser):
|
||||||
cmdset_storage = property(cmdset_storage_get, cmdset_storage_set, cmdset_storage_del)
|
cmdset_storage = property(cmdset_storage_get, cmdset_storage_set, cmdset_storage_del)
|
||||||
|
|
||||||
#
|
#
|
||||||
# PlayerDB main class properties and methods
|
# property/field access
|
||||||
#
|
#
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
@ -182,230 +175,3 @@ class PlayerDB(TypedObject, AbstractUser):
|
||||||
def __uid_del(self):
|
def __uid_del(self):
|
||||||
raise Exception("User id cannot be deleted!")
|
raise Exception("User id cannot be deleted!")
|
||||||
uid = property(__uid_get, __uid_set, __uid_del)
|
uid = property(__uid_get, __uid_set, __uid_del)
|
||||||
|
|
||||||
#
|
|
||||||
# PlayerDB class access methods
|
|
||||||
#
|
|
||||||
|
|
||||||
# session-related methods
|
|
||||||
|
|
||||||
def get_session(self, sessid):
|
|
||||||
"""
|
|
||||||
Return session with given sessid connected to this player.
|
|
||||||
note that the sessionhandler also accepts sessid as an iterable.
|
|
||||||
"""
|
|
||||||
global _SESSIONS
|
|
||||||
if not _SESSIONS:
|
|
||||||
from src.server.sessionhandler import SESSIONS as _SESSIONS
|
|
||||||
return _SESSIONS.session_from_player(self, sessid)
|
|
||||||
|
|
||||||
def get_all_sessions(self):
|
|
||||||
"Return all sessions connected to this player"
|
|
||||||
global _SESSIONS
|
|
||||||
if not _SESSIONS:
|
|
||||||
from src.server.sessionhandler import SESSIONS as _SESSIONS
|
|
||||||
return _SESSIONS.sessions_from_player(self)
|
|
||||||
sessions = property(get_all_sessions) # alias shortcut
|
|
||||||
|
|
||||||
def disconnect_session_from_player(self, sessid):
|
|
||||||
"""
|
|
||||||
Access method for disconnecting a given session from the player
|
|
||||||
(connection happens automatically in the sessionhandler)
|
|
||||||
"""
|
|
||||||
# this should only be one value, loop just to make sure to
|
|
||||||
# clean everything
|
|
||||||
sessions = (session for session in self.get_all_sessions()
|
|
||||||
if session.sessid == sessid)
|
|
||||||
for session in sessions:
|
|
||||||
# this will also trigger unpuppeting
|
|
||||||
session.sessionhandler.disconnect(session)
|
|
||||||
|
|
||||||
# puppeting operations
|
|
||||||
|
|
||||||
def puppet_object(self, sessid, obj, normal_mode=True):
|
|
||||||
"""
|
|
||||||
Use the given session to control (puppet) the given object (usually
|
|
||||||
a Character type). Note that we make no puppet checks here, that must
|
|
||||||
have been done before calling this method.
|
|
||||||
|
|
||||||
sessid - session id of session to connect
|
|
||||||
obj - the object to connect to
|
|
||||||
normal_mode - trigger hooks and extra checks - this is turned off when
|
|
||||||
the server reloads, to quickly re-connect puppets.
|
|
||||||
|
|
||||||
returns True if successful, False otherwise
|
|
||||||
"""
|
|
||||||
session = self.get_session(sessid)
|
|
||||||
if not session:
|
|
||||||
return False
|
|
||||||
if normal_mode and session.puppet:
|
|
||||||
# cleanly unpuppet eventual previous object puppeted by this session
|
|
||||||
self.unpuppet_object(sessid)
|
|
||||||
if obj.player and obj.player.is_connected and obj.player != self:
|
|
||||||
# we don't allow to puppet an object already controlled by an active
|
|
||||||
# player. To kick a player, call unpuppet_object on them explicitly.
|
|
||||||
return
|
|
||||||
# if we get to this point the character is ready to puppet or it
|
|
||||||
# was left with a lingering player/sessid reference from an unclean
|
|
||||||
# server kill or similar
|
|
||||||
|
|
||||||
if normal_mode:
|
|
||||||
obj.at_pre_puppet(self, sessid=sessid)
|
|
||||||
# do the connection
|
|
||||||
obj.sessid.add(sessid)
|
|
||||||
obj.player = self
|
|
||||||
session.puid = obj.id
|
|
||||||
session.puppet = obj
|
|
||||||
# validate/start persistent scripts on object
|
|
||||||
ScriptDB.objects.validate(obj=obj)
|
|
||||||
if normal_mode:
|
|
||||||
obj.at_post_puppet()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def unpuppet_object(self, sessid):
|
|
||||||
"""
|
|
||||||
Disengage control over an object
|
|
||||||
|
|
||||||
sessid - the session id to disengage
|
|
||||||
|
|
||||||
returns True if successful
|
|
||||||
"""
|
|
||||||
session = self.get_session(sessid)
|
|
||||||
if not session:
|
|
||||||
return False
|
|
||||||
obj = hasattr(session, "puppet") and session.puppet or None
|
|
||||||
if not obj:
|
|
||||||
return False
|
|
||||||
# do the disconnect, but only if we are the last session to puppet
|
|
||||||
obj.at_pre_unpuppet()
|
|
||||||
obj.dbobj.sessid.remove(sessid)
|
|
||||||
if not obj.dbobj.sessid.count():
|
|
||||||
del obj.dbobj.player
|
|
||||||
obj.at_post_unpuppet(self, sessid=sessid)
|
|
||||||
session.puppet = None
|
|
||||||
session.puid = None
|
|
||||||
return True
|
|
||||||
|
|
||||||
def unpuppet_all(self):
|
|
||||||
"""
|
|
||||||
Disconnect all puppets. This is called by server
|
|
||||||
before a reset/shutdown.
|
|
||||||
"""
|
|
||||||
for session in self.get_all_sessions():
|
|
||||||
self.unpuppet_object(session.sessid)
|
|
||||||
|
|
||||||
def get_puppet(self, sessid, return_dbobj=False):
|
|
||||||
"""
|
|
||||||
Get an object puppeted by this session through this player. This is
|
|
||||||
the main method for retrieving the puppeted object from the
|
|
||||||
player's end.
|
|
||||||
|
|
||||||
sessid - return character connected to this sessid,
|
|
||||||
character - return character if connected to this player, else None.
|
|
||||||
|
|
||||||
"""
|
|
||||||
session = self.get_session(sessid)
|
|
||||||
if not session:
|
|
||||||
return None
|
|
||||||
if return_dbobj:
|
|
||||||
return session.puppet
|
|
||||||
return session.puppet and session.puppet or None
|
|
||||||
|
|
||||||
def get_all_puppets(self, return_dbobj=False):
|
|
||||||
"""
|
|
||||||
Get all currently puppeted objects as a list
|
|
||||||
"""
|
|
||||||
puppets = [session.puppet for session in self.get_all_sessions()
|
|
||||||
if session.puppet]
|
|
||||||
if return_dbobj:
|
|
||||||
return puppets
|
|
||||||
return [puppet for puppet in puppets]
|
|
||||||
|
|
||||||
def __get_single_puppet(self):
|
|
||||||
"""
|
|
||||||
This is a legacy convenience link for users of
|
|
||||||
MULTISESSION_MODE 0 or 1. It will return
|
|
||||||
only the first puppet. For mode 2, this returns
|
|
||||||
a list of all characters.
|
|
||||||
"""
|
|
||||||
puppets = self.get_all_puppets()
|
|
||||||
if _MULTISESSION_MODE in (0, 1):
|
|
||||||
return puppets and puppets[0] or None
|
|
||||||
return puppets
|
|
||||||
character = property(__get_single_puppet)
|
|
||||||
puppet = property(__get_single_puppet)
|
|
||||||
|
|
||||||
# utility methods
|
|
||||||
|
|
||||||
def delete(self, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Deletes the player permanently.
|
|
||||||
"""
|
|
||||||
for session in self.get_all_sessions():
|
|
||||||
# unpuppeting all objects and disconnecting the user, if any
|
|
||||||
# sessions remain (should usually be handled from the
|
|
||||||
# deleting command)
|
|
||||||
self.unpuppet_object(session.sessid)
|
|
||||||
session.sessionhandler.disconnect(session, reason=_("Player being deleted."))
|
|
||||||
self.scripts.stop()
|
|
||||||
_GA(self, "attributes").clear()
|
|
||||||
_GA(self, "nicks").clear()
|
|
||||||
_GA(self, "aliases").clear()
|
|
||||||
super(PlayerDB, self).delete(*args, **kwargs)
|
|
||||||
|
|
||||||
def execute_cmd(self, raw_string, sessid=None, **kwargs):
|
|
||||||
"""
|
|
||||||
Do something as this player. This method is never called normally,
|
|
||||||
but only when the player object itself is supposed to execute the
|
|
||||||
command. It takes player nicks into account, but not nicks of
|
|
||||||
eventual puppets.
|
|
||||||
|
|
||||||
raw_string - raw command input coming from the command line.
|
|
||||||
sessid - the optional session id to be responsible for the command-send
|
|
||||||
**kwargs - other keyword arguments will be added to the found command
|
|
||||||
object instace as variables before it executes. This is
|
|
||||||
unused by default Evennia but may be used to set flags and
|
|
||||||
change operating paramaters for commands at run-time.
|
|
||||||
"""
|
|
||||||
raw_string = utils.to_unicode(raw_string)
|
|
||||||
raw_string = self.nicks.nickreplace(raw_string,
|
|
||||||
categories=("inputline", "channel"), include_player=False)
|
|
||||||
if not sessid and _MULTISESSION_MODE in (0, 1):
|
|
||||||
# in this case, we should either have only one sessid, or the sessid
|
|
||||||
# should not matter (since the return goes to all of them we can
|
|
||||||
# just use the first one as the source)
|
|
||||||
try:
|
|
||||||
sessid = self.get_all_sessions()[0].sessid
|
|
||||||
except IndexError:
|
|
||||||
# this can happen for bots
|
|
||||||
sessid = None
|
|
||||||
return cmdhandler.cmdhandler(self, raw_string,
|
|
||||||
callertype="player", sessid=sessid, **kwargs)
|
|
||||||
|
|
||||||
def search(self, searchdata, return_puppet=False, **kwargs):
|
|
||||||
"""
|
|
||||||
This is similar to the ObjectDB search method but will search for
|
|
||||||
Players only. Errors will be echoed, and None returned if no Player
|
|
||||||
is found.
|
|
||||||
searchdata - search criterion, the Player's key or dbref to search for
|
|
||||||
return_puppet - will try to return the object the player controls
|
|
||||||
instead of the Player object itself. If no
|
|
||||||
puppeted object exists (since Player is OOC), None will
|
|
||||||
be returned.
|
|
||||||
Extra keywords are ignored, but are allowed in call in order to make
|
|
||||||
API more consistent with objects.models.TypedObject.search.
|
|
||||||
"""
|
|
||||||
#TODO deprecation
|
|
||||||
if "return_character" in kwargs:
|
|
||||||
logger.log_depmsg("Player.search's 'return_character' keyword is deprecated. Use the return_puppet keyword instead.")
|
|
||||||
return_puppet = kwargs.get("return_character")
|
|
||||||
|
|
||||||
matches = _GA(self, "__class__").objects.player_search(searchdata)
|
|
||||||
matches = _AT_SEARCH_RESULT(self, searchdata, matches, global_search=True)
|
|
||||||
if matches and return_puppet:
|
|
||||||
try:
|
|
||||||
return _GA(matches, "puppet")
|
|
||||||
except AttributeError:
|
|
||||||
return None
|
|
||||||
return matches
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,23 @@ from src.typeclasses.models import TypeclassBase
|
||||||
from src.players.manager import PlayerManager
|
from src.players.manager import PlayerManager
|
||||||
from src.players.models import PlayerDB
|
from src.players.models import PlayerDB
|
||||||
from src.comms.models import ChannelDB
|
from src.comms.models import ChannelDB
|
||||||
|
from src.commands import cmdhandler
|
||||||
|
from src.scripts.models import ScriptDB
|
||||||
from src.utils import logger
|
from src.utils import logger
|
||||||
from src.utils.utils import lazy_property, to_str, make_iter
|
from src.utils.utils import (lazy_property, to_str,
|
||||||
|
make_iter, to_unicode,
|
||||||
|
variable_from_module)
|
||||||
from src.typeclasses.attributes import NickHandler
|
from src.typeclasses.attributes import NickHandler
|
||||||
from src.scripts.scripthandler import ScriptHandler
|
from src.scripts.scripthandler import ScriptHandler
|
||||||
from src.commands.cmdsethandler import CmdSetHandler
|
from src.commands.cmdsethandler import CmdSetHandler
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
__all__ = ("DefaultPlayer",)
|
__all__ = ("DefaultPlayer",)
|
||||||
|
|
||||||
|
_SESSIONS = None
|
||||||
|
|
||||||
|
_AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||||
_MULTISESSION_MODE = settings.MULTISESSION_MODE
|
_MULTISESSION_MODE = settings.MULTISESSION_MODE
|
||||||
_CMDSET_PLAYER = settings.CMDSET_PLAYER
|
_CMDSET_PLAYER = settings.CMDSET_PLAYER
|
||||||
_CONNECT_CHANNEL = None
|
_CONNECT_CHANNEL = None
|
||||||
|
|
@ -74,7 +82,7 @@ class DefaultPlayer(PlayerDB):
|
||||||
* Helper methods
|
* Helper methods
|
||||||
|
|
||||||
msg(outgoing_string, from_obj=None, **kwargs)
|
msg(outgoing_string, from_obj=None, **kwargs)
|
||||||
swap_character(new_character, delete_old_character=False)
|
#swap_character(new_character, delete_old_character=False)
|
||||||
execute_cmd(raw_string)
|
execute_cmd(raw_string)
|
||||||
search(ostring, global_search=False, attribute_name=None,
|
search(ostring, global_search=False, attribute_name=None,
|
||||||
use_nicks=False, location=None,
|
use_nicks=False, location=None,
|
||||||
|
|
@ -122,6 +130,171 @@ class DefaultPlayer(PlayerDB):
|
||||||
return NickHandler(self)
|
return NickHandler(self)
|
||||||
|
|
||||||
|
|
||||||
|
# session-related methods
|
||||||
|
|
||||||
|
def get_session(self, sessid):
|
||||||
|
"""
|
||||||
|
Return session with given sessid connected to this player.
|
||||||
|
note that the sessionhandler also accepts sessid as an iterable.
|
||||||
|
"""
|
||||||
|
global _SESSIONS
|
||||||
|
if not _SESSIONS:
|
||||||
|
from src.server.sessionhandler import SESSIONS as _SESSIONS
|
||||||
|
return _SESSIONS.session_from_player(self, sessid)
|
||||||
|
|
||||||
|
def get_all_sessions(self):
|
||||||
|
"Return all sessions connected to this player"
|
||||||
|
global _SESSIONS
|
||||||
|
if not _SESSIONS:
|
||||||
|
from src.server.sessionhandler import SESSIONS as _SESSIONS
|
||||||
|
return _SESSIONS.sessions_from_player(self)
|
||||||
|
sessions = property(get_all_sessions) # alias shortcut
|
||||||
|
|
||||||
|
def disconnect_session_from_player(self, sessid):
|
||||||
|
"""
|
||||||
|
Access method for disconnecting a given session from the player
|
||||||
|
(connection happens automatically in the sessionhandler)
|
||||||
|
"""
|
||||||
|
# this should only be one value, loop just to make sure to
|
||||||
|
# clean everything
|
||||||
|
sessions = (session for session in self.get_all_sessions()
|
||||||
|
if session.sessid == sessid)
|
||||||
|
for session in sessions:
|
||||||
|
# this will also trigger unpuppeting
|
||||||
|
session.sessionhandler.disconnect(session)
|
||||||
|
|
||||||
|
# puppeting operations
|
||||||
|
|
||||||
|
def puppet_object(self, sessid, obj, normal_mode=True):
|
||||||
|
"""
|
||||||
|
Use the given session to control (puppet) the given object (usually
|
||||||
|
a Character type). Note that we make no puppet checks here, that must
|
||||||
|
have been done before calling this method.
|
||||||
|
|
||||||
|
sessid - session id of session to connect
|
||||||
|
obj - the object to connect to
|
||||||
|
normal_mode - trigger hooks and extra checks - this is turned off when
|
||||||
|
the server reloads, to quickly re-connect puppets.
|
||||||
|
|
||||||
|
returns True if successful, False otherwise
|
||||||
|
"""
|
||||||
|
session = self.get_session(sessid)
|
||||||
|
if not session:
|
||||||
|
return False
|
||||||
|
if normal_mode and session.puppet:
|
||||||
|
# cleanly unpuppet eventual previous object puppeted by this session
|
||||||
|
self.unpuppet_object(sessid)
|
||||||
|
if obj.player and obj.player.is_connected and obj.player != self:
|
||||||
|
# we don't allow to puppet an object already controlled by an active
|
||||||
|
# player. To kick a player, call unpuppet_object on them explicitly.
|
||||||
|
return
|
||||||
|
# if we get to this point the character is ready to puppet or it
|
||||||
|
# was left with a lingering player/sessid reference from an unclean
|
||||||
|
# server kill or similar
|
||||||
|
|
||||||
|
if normal_mode:
|
||||||
|
obj.at_pre_puppet(self, sessid=sessid)
|
||||||
|
# do the connection
|
||||||
|
obj.sessid.add(sessid)
|
||||||
|
obj.player = self
|
||||||
|
session.puid = obj.id
|
||||||
|
session.puppet = obj
|
||||||
|
# validate/start persistent scripts on object
|
||||||
|
ScriptDB.objects.validate(obj=obj)
|
||||||
|
if normal_mode:
|
||||||
|
obj.at_post_puppet()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def unpuppet_object(self, sessid):
|
||||||
|
"""
|
||||||
|
Disengage control over an object
|
||||||
|
|
||||||
|
sessid - the session id to disengage
|
||||||
|
|
||||||
|
returns True if successful
|
||||||
|
"""
|
||||||
|
session = self.get_session(sessid)
|
||||||
|
if not session:
|
||||||
|
return False
|
||||||
|
obj = hasattr(session, "puppet") and session.puppet or None
|
||||||
|
if not obj:
|
||||||
|
return False
|
||||||
|
# do the disconnect, but only if we are the last session to puppet
|
||||||
|
obj.at_pre_unpuppet()
|
||||||
|
obj.dbobj.sessid.remove(sessid)
|
||||||
|
if not obj.dbobj.sessid.count():
|
||||||
|
del obj.dbobj.player
|
||||||
|
obj.at_post_unpuppet(self, sessid=sessid)
|
||||||
|
session.puppet = None
|
||||||
|
session.puid = None
|
||||||
|
return True
|
||||||
|
|
||||||
|
def unpuppet_all(self):
|
||||||
|
"""
|
||||||
|
Disconnect all puppets. This is called by server
|
||||||
|
before a reset/shutdown.
|
||||||
|
"""
|
||||||
|
for session in self.get_all_sessions():
|
||||||
|
self.unpuppet_object(session.sessid)
|
||||||
|
|
||||||
|
def get_puppet(self, sessid, return_dbobj=False):
|
||||||
|
"""
|
||||||
|
Get an object puppeted by this session through this player. This is
|
||||||
|
the main method for retrieving the puppeted object from the
|
||||||
|
player's end.
|
||||||
|
|
||||||
|
sessid - return character connected to this sessid,
|
||||||
|
character - return character if connected to this player, else None.
|
||||||
|
|
||||||
|
"""
|
||||||
|
session = self.get_session(sessid)
|
||||||
|
if not session:
|
||||||
|
return None
|
||||||
|
if return_dbobj:
|
||||||
|
return session.puppet
|
||||||
|
return session.puppet and session.puppet or None
|
||||||
|
|
||||||
|
def get_all_puppets(self, return_dbobj=False):
|
||||||
|
"""
|
||||||
|
Get all currently puppeted objects as a list
|
||||||
|
"""
|
||||||
|
puppets = [session.puppet for session in self.get_all_sessions()
|
||||||
|
if session.puppet]
|
||||||
|
if return_dbobj:
|
||||||
|
return puppets
|
||||||
|
return [puppet for puppet in puppets]
|
||||||
|
|
||||||
|
def __get_single_puppet(self):
|
||||||
|
"""
|
||||||
|
This is a legacy convenience link for users of
|
||||||
|
MULTISESSION_MODE 0 or 1. It will return
|
||||||
|
only the first puppet. For mode 2, this returns
|
||||||
|
a list of all characters.
|
||||||
|
"""
|
||||||
|
puppets = self.get_all_puppets()
|
||||||
|
if _MULTISESSION_MODE in (0, 1):
|
||||||
|
return puppets and puppets[0] or None
|
||||||
|
return puppets
|
||||||
|
character = property(__get_single_puppet)
|
||||||
|
puppet = property(__get_single_puppet)
|
||||||
|
|
||||||
|
# utility methods
|
||||||
|
|
||||||
|
def delete(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Deletes the player permanently.
|
||||||
|
"""
|
||||||
|
for session in self.get_all_sessions():
|
||||||
|
# unpuppeting all objects and disconnecting the user, if any
|
||||||
|
# sessions remain (should usually be handled from the
|
||||||
|
# deleting command)
|
||||||
|
self.unpuppet_object(session.sessid)
|
||||||
|
session.sessionhandler.disconnect(session, reason=_("Player being deleted."))
|
||||||
|
self.scripts.stop()
|
||||||
|
self.attributes.clear()
|
||||||
|
self.nicks.clear()
|
||||||
|
self.aliases.clear()
|
||||||
|
super(PlayerDB, self).delete(*args, **kwargs)
|
||||||
## methods inherited from database model
|
## methods inherited from database model
|
||||||
|
|
||||||
def msg(self, text=None, from_obj=None, sessid=None, **kwargs):
|
def msg(self, text=None, from_obj=None, sessid=None, **kwargs):
|
||||||
|
|
@ -167,48 +340,38 @@ class DefaultPlayer(PlayerDB):
|
||||||
for sess in self.get_all_sessions():
|
for sess in self.get_all_sessions():
|
||||||
sess.msg(text=text, **kwargs)
|
sess.msg(text=text, **kwargs)
|
||||||
|
|
||||||
def swap_character(self, new_character, delete_old_character=False):
|
|
||||||
"""
|
|
||||||
Swaps the character controlled by this Player, if possible.
|
|
||||||
|
|
||||||
new_character (Object) - character/object to swap to
|
|
||||||
delete_old_character (bool) - delete the old character when swapping
|
|
||||||
|
|
||||||
Returns: True/False depending on if swap suceeded or not.
|
|
||||||
"""
|
|
||||||
return super(DefaultPlayer, self).swap_character(new_character, delete_old_character=delete_old_character)
|
|
||||||
|
|
||||||
def execute_cmd(self, raw_string, sessid=None, **kwargs):
|
def execute_cmd(self, raw_string, sessid=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
Do something as this object. This command transparently
|
Do something as this player. This method is never called normally,
|
||||||
lets its typeclass execute the command. This method
|
but only when the player object itself is supposed to execute the
|
||||||
is -not- called by Evennia normally, it is here to be
|
command. It takes player nicks into account, but not nicks of
|
||||||
called explicitly in code.
|
eventual puppets.
|
||||||
|
|
||||||
Argument:
|
raw_string - raw command input coming from the command line.
|
||||||
raw_string (string) - raw command input
|
sessid - the optional session id to be responsible for the command-send
|
||||||
sessid (int) - id of session executing the command. This sets the
|
|
||||||
sessid property on the command
|
|
||||||
**kwargs - other keyword arguments will be added to the found command
|
**kwargs - other keyword arguments will be added to the found command
|
||||||
object instace as variables before it executes. This is
|
object instace as variables before it executes. This is
|
||||||
unused by default Evennia but may be used to set flags and
|
unused by default Evennia but may be used to set flags and
|
||||||
change operating paramaters for commands at run-time.
|
change operating paramaters for commands at run-time.
|
||||||
|
|
||||||
Returns Deferred - this is an asynchronous Twisted object that will
|
|
||||||
not fire until the command has actually finished executing. To
|
|
||||||
overload this one needs to attach callback functions to it, with
|
|
||||||
addCallback(function). This function will be called with an
|
|
||||||
eventual return value from the command execution.
|
|
||||||
|
|
||||||
This return is not used at all by Evennia by default, but might
|
|
||||||
be useful for coders intending to implement some sort of nested
|
|
||||||
command structure.
|
|
||||||
"""
|
"""
|
||||||
return super(DefaultPlayer, self).execute_cmd(raw_string, sessid=sessid, **kwargs)
|
raw_string = to_unicode(raw_string)
|
||||||
|
raw_string = self.nicks.nickreplace(raw_string,
|
||||||
|
categories=("inputline", "channel"), include_player=False)
|
||||||
|
if not sessid and _MULTISESSION_MODE in (0, 1):
|
||||||
|
# in this case, we should either have only one sessid, or the sessid
|
||||||
|
# should not matter (since the return goes to all of them we can
|
||||||
|
# just use the first one as the source)
|
||||||
|
try:
|
||||||
|
sessid = self.get_all_sessions()[0].sessid
|
||||||
|
except IndexError:
|
||||||
|
# this can happen for bots
|
||||||
|
sessid = None
|
||||||
|
return cmdhandler.cmdhandler(self, raw_string,
|
||||||
|
callertype="player", sessid=sessid, **kwargs)
|
||||||
|
|
||||||
def search(self, searchdata, return_puppet=False, **kwargs):
|
def search(self, searchdata, return_puppet=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
This is similar to the Object search method but will search for
|
This is similar to the ObjectDB search method but will search for
|
||||||
Players only. Errors will be echoed, and None returned if no Player
|
Players only. Errors will be echoed, and None returned if no Player
|
||||||
is found.
|
is found.
|
||||||
searchdata - search criterion, the Player's key or dbref to search for
|
searchdata - search criterion, the Player's key or dbref to search for
|
||||||
|
|
@ -224,7 +387,14 @@ class DefaultPlayer(PlayerDB):
|
||||||
# handle wrapping of common terms
|
# handle wrapping of common terms
|
||||||
if searchdata.lower() in ("me", "*me", "self", "*self",):
|
if searchdata.lower() in ("me", "*me", "self", "*self",):
|
||||||
return self
|
return self
|
||||||
return super(DefaultPlayer, self).search(searchdata, return_puppet=return_puppet, **kwargs)
|
matches = self.__class__.objects.player_search(searchdata)
|
||||||
|
matches = _AT_SEARCH_RESULT(self, searchdata, matches, global_search=True)
|
||||||
|
if matches and return_puppet:
|
||||||
|
try:
|
||||||
|
return matches.puppet
|
||||||
|
except AttributeError:
|
||||||
|
return None
|
||||||
|
return matches
|
||||||
|
|
||||||
def is_typeclass(self, typeclass, exact=False):
|
def is_typeclass(self, typeclass, exact=False):
|
||||||
"""
|
"""
|
||||||
|
|
@ -332,6 +502,7 @@ class DefaultPlayer(PlayerDB):
|
||||||
lockstring = "attrread:perm(Admins);attredit:perm(Admins);attrcreate:perm(Admins)"
|
lockstring = "attrread:perm(Admins);attredit:perm(Admins);attrcreate:perm(Admins)"
|
||||||
self.attributes.add("_playable_characters", [], lockstring=lockstring)
|
self.attributes.add("_playable_characters", [], lockstring=lockstring)
|
||||||
|
|
||||||
|
# TODO - handle this in __init__ instead.
|
||||||
def at_init(self):
|
def at_init(self):
|
||||||
"""
|
"""
|
||||||
This is always called whenever this object is initiated --
|
This is always called whenever this object is initiated --
|
||||||
|
|
@ -344,12 +515,35 @@ class DefaultPlayer(PlayerDB):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Note that the hooks below also exist in the character object's
|
# Note that the hooks below also exist in the character object's
|
||||||
# typeclass. You can often ignore these and rely on the character
|
# typeclass. You can often ignore these and rely on the character
|
||||||
# ones instead, unless you are implementing a multi-character game
|
# ones instead, unless you are implementing a multi-character game
|
||||||
# and have some things that should be done regardless of which
|
# and have some things that should be done regardless of which
|
||||||
# character is currently connected to this player.
|
# character is currently connected to this player.
|
||||||
|
|
||||||
|
def at_first_save(self):
|
||||||
|
"""
|
||||||
|
This is a generic hook called by Evennia when this object is
|
||||||
|
saved to the database the very first time. You generally
|
||||||
|
don't override this method but the hooks called by it.
|
||||||
|
"""
|
||||||
|
self.basetype_setup()
|
||||||
|
self.at_player_creation()
|
||||||
|
|
||||||
|
permissions = settings.PERMISSION_PLAYER_DEFAULT
|
||||||
|
if hasattr(self, "_createdict"):
|
||||||
|
# this will only be set if the utils.create_player
|
||||||
|
# function was used to create the object.
|
||||||
|
cdict = self._createdict
|
||||||
|
if "locks" in cdict:
|
||||||
|
self.locks.add(cdict["locks"])
|
||||||
|
if "permissions" in cdict:
|
||||||
|
permissions = cdict["permissions"]
|
||||||
|
del self._createdict
|
||||||
|
|
||||||
|
self.permissions.add(permissions)
|
||||||
|
|
||||||
def at_access(self, result, accessing_obj, access_type, **kwargs):
|
def at_access(self, result, accessing_obj, access_type, **kwargs):
|
||||||
"""
|
"""
|
||||||
This is called with the result of an access call, along with
|
This is called with the result of an access call, along with
|
||||||
|
|
@ -373,8 +567,7 @@ class DefaultPlayer(PlayerDB):
|
||||||
|
|
||||||
def at_first_login(self):
|
def at_first_login(self):
|
||||||
"""
|
"""
|
||||||
Only called once, the very first
|
Called the very first time this player logs into the game.
|
||||||
time the user logs in.
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -472,6 +665,7 @@ class DefaultPlayer(PlayerDB):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Guest(DefaultPlayer):
|
class Guest(DefaultPlayer):
|
||||||
"""
|
"""
|
||||||
This class is used for guest logins. Unlike Players, Guests and their
|
This class is used for guest logins. Unlike Players, Guests and their
|
||||||
|
|
|
||||||
|
|
@ -158,23 +158,23 @@ class ScriptDB(TypedObject):
|
||||||
object = property(__get_obj, __set_obj)
|
object = property(__get_obj, __set_obj)
|
||||||
|
|
||||||
|
|
||||||
def at_typeclass_error(self):
|
# def at_typeclass_error(self):
|
||||||
"""
|
# """
|
||||||
If this is called, it means the typeclass has a critical
|
# If this is called, it means the typeclass has a critical
|
||||||
error and cannot even be loaded. We don't allow a script
|
# error and cannot even be loaded. We don't allow a script
|
||||||
to be created under those circumstances. Already created,
|
# to be created under those circumstances. Already created,
|
||||||
permanent scripts are set to already be active so they
|
# permanent scripts are set to already be active so they
|
||||||
won't get activated now (next reboot the bug might be fixed)
|
# won't get activated now (next reboot the bug might be fixed)
|
||||||
"""
|
# """
|
||||||
# By setting is_active=True, we trick the script not to run "again".
|
# # By setting is_active=True, we trick the script not to run "again".
|
||||||
self.is_active = True
|
# self.is_active = True
|
||||||
return super(ScriptDB, self).at_typeclass_error()
|
# return super(ScriptDB, self).at_typeclass_error()
|
||||||
|
#
|
||||||
delete_iter = 0
|
# delete_iter = 0
|
||||||
def delete(self):
|
# def delete(self):
|
||||||
"Delete script"
|
# "Delete script"
|
||||||
if self.delete_iter > 0:
|
# if self.delete_iter > 0:
|
||||||
return
|
# return
|
||||||
self.delete_iter += 1
|
# self.delete_iter += 1
|
||||||
_GA(self, "attributes").clear()
|
# _GA(self, "attributes").clear()
|
||||||
super(ScriptDB, self).delete()
|
# super(ScriptDB, self).delete()
|
||||||
|
|
|
||||||
|
|
@ -350,12 +350,6 @@ class ScriptBase(ScriptDB):
|
||||||
#
|
#
|
||||||
|
|
||||||
class Script(ScriptBase):
|
class Script(ScriptBase):
|
||||||
"""
|
|
||||||
This is the class you should inherit from, it implements
|
|
||||||
the hooks called by the script machinery.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""
|
"""
|
||||||
This is the base TypeClass for all Scripts. Scripts describe events,
|
This is the base TypeClass for all Scripts. Scripts describe events,
|
||||||
timers and states in game, they can have a time component or describe
|
timers and states in game, they can have a time component or describe
|
||||||
|
|
@ -440,20 +434,63 @@ class Script(ScriptBase):
|
||||||
temporary variables you want should survive a reload.
|
temporary variables you want should survive a reload.
|
||||||
at_server_shutdown() - called at a full server shutdown.
|
at_server_shutdown() - called at a full server shutdown.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
super(Script, self).__init__(*args, **kwargs)
|
def at_first_save(self):
|
||||||
|
"""
|
||||||
|
This is called after very first time this object is saved.
|
||||||
|
Generally, you don't need to overload this, but only the hooks
|
||||||
|
called by this method.
|
||||||
|
"""
|
||||||
|
self.at_script_creation(self)
|
||||||
|
|
||||||
|
if hasattr(self, "_createdict"):
|
||||||
|
# this will only be set if the utils.create_script
|
||||||
|
# function was used to create the object. We want
|
||||||
|
# the create call's kwargs to override the values
|
||||||
|
# set by hooks.
|
||||||
|
cdict = self._createdict
|
||||||
|
updates = []
|
||||||
|
if not cdict["key"]:
|
||||||
|
self.db_key = "#%i" % self.dbid
|
||||||
|
updates.append("db_key")
|
||||||
|
elif self.key != cdict["db_key"]:
|
||||||
|
self.db_key = cdict["key"]
|
||||||
|
updates.append("db_key")
|
||||||
|
if cdict["interval"] and self.interval != cdict["interval"]:
|
||||||
|
self.db_interval = cdict["interval"]
|
||||||
|
updates.append("db_interval")
|
||||||
|
if cdict["start_delay"] and self.start_delay != cdict["start_delay"]:
|
||||||
|
self.db_start_delay = cdict["start_delay"]
|
||||||
|
updates.append("db_start_delay")
|
||||||
|
if cdict["repeats"] and self.repeats != cdict["repeats"]:
|
||||||
|
self.db_repeats = cdict["repeats"]
|
||||||
|
updates.append("db_repeats")
|
||||||
|
if cdict["persistent"] and self.persistent != cdict["persistent"]:
|
||||||
|
self.db_persistent = cdict["persistent"]
|
||||||
|
updates.append("db_persistent")
|
||||||
|
if updates:
|
||||||
|
self.save(update_fields=updates)
|
||||||
|
|
||||||
|
if cdict["permissions"]:
|
||||||
|
self.permissions.add(cdict["permissions"])
|
||||||
|
if cdict["locks"]:
|
||||||
|
self.locks.add(cdict["locks"])
|
||||||
|
if cdict["aliases"]:
|
||||||
|
self.aliases.add(cdict["aliases"])
|
||||||
|
|
||||||
|
if not cdict["autostart"]:
|
||||||
|
# don't auto-start the script
|
||||||
|
return
|
||||||
|
|
||||||
|
# auto-start script (default)
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
|
||||||
def at_script_creation(self):
|
def at_script_creation(self):
|
||||||
"""
|
"""
|
||||||
Only called once, by the create function.
|
Only called once, by the create function.
|
||||||
"""
|
"""
|
||||||
self.key = "<unnamed>"
|
pass
|
||||||
self.desc = ""
|
|
||||||
self.interval = 0 # infinite
|
|
||||||
self.start_delay = False
|
|
||||||
self.repeats = 0 # infinite
|
|
||||||
self.persistent = False
|
|
||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,10 @@ _SA = object.__setattr__
|
||||||
# signal receivers. Assigned in __new__
|
# signal receivers. Assigned in __new__
|
||||||
def post_save(sender, instance, created, **kwargs):
|
def post_save(sender, instance, created, **kwargs):
|
||||||
"""
|
"""
|
||||||
Is called Receive a signal just after the object is saved.
|
Receives a signal just after the object is saved.
|
||||||
"""
|
"""
|
||||||
if created:
|
if created:
|
||||||
instance.at_instance_creation()
|
instance.at_first_save()
|
||||||
#TODO - put OOB handler here?
|
#TODO - put OOB handler here?
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -363,7 +363,8 @@ class TypedObject(SharedMemoryModel):
|
||||||
self.nattributes.clear()
|
self.nattributes.clear()
|
||||||
|
|
||||||
if run_start_hooks:
|
if run_start_hooks:
|
||||||
self.at_instance_creation()
|
# fake this call to mimic the first save
|
||||||
|
self.at_first_save()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Lock / permission methods
|
# Lock / permission methods
|
||||||
|
|
|
||||||
|
|
@ -48,33 +48,6 @@ __all__ = ("create_object", "create_script", "create_help_entry",
|
||||||
|
|
||||||
_GA = object.__getattribute__
|
_GA = object.__getattribute__
|
||||||
|
|
||||||
# Helper function
|
|
||||||
|
|
||||||
def handle_dbref(inp, objclass, raise_errors=True):
|
|
||||||
"""
|
|
||||||
Convert a #dbid to a valid object of objclass. objclass
|
|
||||||
should be a valid object class to filter against (objclass.filter ...)
|
|
||||||
If not raise_errors is set, this will swallow errors of non-existing
|
|
||||||
objects.
|
|
||||||
"""
|
|
||||||
if not (isinstance(inp, basestring) and inp.startswith("#")):
|
|
||||||
return inp
|
|
||||||
# a string, analyze it
|
|
||||||
inp = inp.lstrip('#')
|
|
||||||
try:
|
|
||||||
if int(inp) < 0:
|
|
||||||
return None
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# if we get to this point, inp is an integer dbref; get the matching object
|
|
||||||
try:
|
|
||||||
return objclass.objects.get(id=inp)
|
|
||||||
except Exception:
|
|
||||||
if raise_errors:
|
|
||||||
raise
|
|
||||||
return inp
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Game Object creation
|
# Game Object creation
|
||||||
#
|
#
|
||||||
|
|
@ -128,7 +101,7 @@ def create_object(typeclass=None, key=None, location=None,
|
||||||
"locks":locks, "aliases":aliases, "destination":destination,
|
"locks":locks, "aliases":aliases, "destination":destination,
|
||||||
"report_to":report_to, "nohome":nohome}
|
"report_to":report_to, "nohome":nohome}
|
||||||
# this will trigger the save signal which in turn calls the
|
# this will trigger the save signal which in turn calls the
|
||||||
# at_instance_creation hook on the typeclass, where the _createdict can be
|
# at_first_save hook on the typeclass, where the _createdict can be
|
||||||
# used.
|
# used.
|
||||||
new_object.save()
|
new_object.save()
|
||||||
return new_object
|
return new_object
|
||||||
|
|
@ -168,83 +141,33 @@ def create_script(typeclass, key=None, obj=None, player=None, locks=None,
|
||||||
error will be raised. If set, this method will
|
error will be raised. If set, this method will
|
||||||
return None upon errors.
|
return None upon errors.
|
||||||
"""
|
"""
|
||||||
global _Script, _ScriptDB
|
typeclass = typeclass if typeclass else settings.BASE_SCRIPT_TYPECLASS
|
||||||
if not _Script:
|
|
||||||
from src.scripts.scripts import Script as _Script
|
|
||||||
if not _ScriptDB:
|
|
||||||
from src.scripts.models import ScriptDB as _ScriptDB
|
|
||||||
|
|
||||||
if not typeclass:
|
if isinstance(typeclass, basestring):
|
||||||
typeclass = settings.BASE_SCRIPT_TYPECLASS
|
# a path is given. Load the actual typeclass
|
||||||
elif isinstance(typeclass, _ScriptDB):
|
typeclass = class_from_module(typeclass, settings.SCRIPT_TYPECLASS_PATHS)
|
||||||
# this is already an scriptdb instance, extract its typeclass
|
|
||||||
typeclass = typeclass.typeclass.path
|
|
||||||
elif isinstance(typeclass, _Script) or utils.inherits_from(typeclass, _Script):
|
|
||||||
# this is already an object typeclass, extract its path
|
|
||||||
typeclass = typeclass.path
|
|
||||||
|
|
||||||
# create new database script
|
# validate input
|
||||||
new_db_script = _ScriptDB()
|
player = dbid_to_obj(player)
|
||||||
|
obj = dbid_to_obj(obj)
|
||||||
|
|
||||||
# assign the typeclass
|
# create new instance
|
||||||
typeclass = utils.to_unicode(typeclass)
|
new_script = typeclass(db_key=key, db_obj=obj, db_player=player,
|
||||||
new_db_script.typeclass_path = typeclass
|
db_interval=interval, db_start_delay=start_delay,
|
||||||
|
db_repeats=repeats, db_peristent=persistent)
|
||||||
# the name/key is often set later in the typeclass. This
|
# store the call signature for the signal
|
||||||
# is set here as a failsafe.
|
new_script._createdict = {"key":key, "obj":obj, "player":player,
|
||||||
if key:
|
"locks":locks, "interval":interval,
|
||||||
new_db_script.key = key
|
"start_delay":start_delay, "repeats":repeats,
|
||||||
else:
|
"persistent":persistent, "autostart":autostart,
|
||||||
new_db_script.key = "#%i" % new_db_script.id
|
"report_to":report_to}
|
||||||
|
|
||||||
# this will either load the typeclass or the default one
|
|
||||||
new_script = new_db_script.typeclass
|
|
||||||
|
|
||||||
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
|
|
||||||
SharedMemoryModel.delete(new_db_script)
|
|
||||||
if report_to:
|
|
||||||
_GA(report_to, "msg")("Error creating %s (%s): %s" % (new_db_script.key, typeclass,
|
|
||||||
_GA(new_db_script, "typeclass_last_errmsg")))
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
raise Exception(_GA(new_db_script, "typeclass_last_errmsg"))
|
|
||||||
|
|
||||||
if obj:
|
|
||||||
new_script.obj = obj
|
|
||||||
if player:
|
|
||||||
new_script.player = player
|
|
||||||
|
|
||||||
# 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
|
|
||||||
if key:
|
|
||||||
new_script.key = key
|
|
||||||
if locks:
|
|
||||||
new_script.locks.add(locks)
|
|
||||||
if interval is not None:
|
|
||||||
new_script.interval = interval
|
|
||||||
if start_delay is not None:
|
|
||||||
new_script.start_delay = start_delay
|
|
||||||
if repeats is not None:
|
|
||||||
new_script.repeats = repeats
|
|
||||||
if persistent is not None:
|
|
||||||
new_script.persistent = persistent
|
|
||||||
|
|
||||||
# must do this before starting the script since some
|
|
||||||
# scripts may otherwise run for a very short time and
|
|
||||||
# try to delete itself before we have a time to save it.
|
|
||||||
new_db_script.save()
|
|
||||||
|
|
||||||
# a new created script should usually be started.
|
|
||||||
if autostart:
|
|
||||||
new_script.start()
|
|
||||||
|
|
||||||
|
# this will trigger the save signal which in turn calls the
|
||||||
|
# at_first_save hook on the tyepclass, where the _createdict
|
||||||
|
# can be used.
|
||||||
|
new_script.save()
|
||||||
return new_script
|
return new_script
|
||||||
|
|
||||||
#alias
|
#alias
|
||||||
script = create_script
|
script = create_script
|
||||||
|
|
||||||
|
|
@ -413,11 +336,16 @@ def create_player(key, email, password,
|
||||||
operations and is thus not suitable for play-testing the game.
|
operations and is thus not suitable for play-testing the game.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
global _PlayerDB, _Player
|
typeclass = typeclass if typeclass else settings.BASE_PLAYER_TYPECLASS
|
||||||
if not _PlayerDB:
|
|
||||||
from src.players.models import PlayerDB as _PlayerDB
|
if isinstance(typeclass, basestring):
|
||||||
if not _Player:
|
# a path is given. Load the actual typeclass.
|
||||||
from src.players.player import Player as _Player
|
typeclass = class_from_module(typeclass, settings.OBJECT_TYPECLASS_PATHS)
|
||||||
|
typeclass_path = typeclass.path
|
||||||
|
|
||||||
|
# setup input for the create command. We use PlayerDB as baseclass
|
||||||
|
# here to give us maximum freedom (the typeclasses will load
|
||||||
|
# correctly when each object is recovered).
|
||||||
|
|
||||||
if not email:
|
if not email:
|
||||||
email = "dummy@dummy.com"
|
email = "dummy@dummy.com"
|
||||||
|
|
@ -425,69 +353,23 @@ def create_player(key, email, password,
|
||||||
raise ValueError("A Player with the name '%s' already exists." % key)
|
raise ValueError("A Player with the name '%s' already exists." % key)
|
||||||
|
|
||||||
# this handles a given dbref-relocate to a player.
|
# this handles a given dbref-relocate to a player.
|
||||||
report_to = handle_dbref(report_to, _PlayerDB)
|
report_to = dbid_to_obj(report_to, _PlayerDB)
|
||||||
|
|
||||||
try:
|
# create the correct player object
|
||||||
|
|
||||||
# create the correct Player object
|
|
||||||
if is_superuser:
|
if is_superuser:
|
||||||
new_db_player = _PlayerDB.objects.create_superuser(key, email, password)
|
new_player = _PlayerDB.objects.create_superuser(key, email, password)
|
||||||
else:
|
else:
|
||||||
new_db_player = _PlayerDB.objects.create_user(key, email, password)
|
new_player = _PlayerDB.objects.create_user(key, email, password)
|
||||||
|
new_player.db_typeclass_path = typeclass_path
|
||||||
|
# store the call signature for the signal
|
||||||
|
new_player._createdict = {"locks":locks, "permissions":permissions,
|
||||||
|
"report_to":report_to}
|
||||||
|
|
||||||
if not typeclass:
|
# saving will trigger the signal that calls the
|
||||||
typeclass = settings.BASE_PLAYER_TYPECLASS
|
# at_first_save hook on the typeclass, where the _createdict
|
||||||
elif isinstance(typeclass, _PlayerDB):
|
# can be used.
|
||||||
# this is an PlayerDB instance, extract its typeclass path
|
new_player.save()
|
||||||
typeclass = typeclass.typeclass.path
|
|
||||||
elif isinstance(typeclass, _Player) or utils.inherits_from(typeclass, _Player):
|
|
||||||
# this is Player object typeclass, extract its path
|
|
||||||
typeclass = typeclass.path
|
|
||||||
|
|
||||||
# assign the typeclass
|
|
||||||
typeclass = utils.to_unicode(typeclass)
|
|
||||||
new_db_player.typeclass_path = typeclass
|
|
||||||
|
|
||||||
# this will either load the typeclass or the default one
|
|
||||||
new_player = new_db_player.typeclass
|
|
||||||
|
|
||||||
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)
|
|
||||||
if report_to:
|
|
||||||
_GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_player.key, typeclass,
|
|
||||||
_GA(new_db_player, "typeclass_last_errmsg")))
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
raise Exception(_GA(new_db_player, "typeclass_last_errmsg"))
|
|
||||||
|
|
||||||
new_player.basetype_setup() # setup the basic locks and cmdset
|
|
||||||
# call hook method (may override default permissions)
|
|
||||||
new_player.at_player_creation()
|
|
||||||
|
|
||||||
# custom given arguments potentially overrides the hook
|
|
||||||
if permissions:
|
|
||||||
new_player.permissions.add(permissions)
|
|
||||||
elif not new_player.permissions:
|
|
||||||
new_player.permissions.add(settings.PERMISSION_PLAYER_DEFAULT)
|
|
||||||
if locks:
|
|
||||||
new_player.locks.add(locks)
|
|
||||||
return new_player
|
return new_player
|
||||||
|
|
||||||
except Exception:
|
|
||||||
# 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
|
|
||||||
raise
|
|
||||||
|
|
||||||
# alias
|
# alias
|
||||||
player = create_player
|
player = create_player
|
||||||
|
|
|
||||||
|
|
@ -76,12 +76,11 @@ os.environ['DJANGO_SETTINGS_MODULE'] = 'game.settings'
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from random import randint
|
from random import randint
|
||||||
from src.objects.models import ObjectDB
|
from src.objects.models import ObjectDB
|
||||||
from src.utils.create import handle_dbref
|
from src.utils.utils import make_iter, all_from_module, dbid_to_obj
|
||||||
from src.utils.utils import make_iter, all_from_module
|
|
||||||
|
|
||||||
_CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination")
|
_CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination")
|
||||||
|
|
||||||
_handle_dbref = lambda inp: handle_dbref(inp, ObjectDB)
|
_handle_dbref = lambda inp: dbid_to_obj(inp, ObjectDB)
|
||||||
|
|
||||||
|
|
||||||
def _validate_prototype(key, prototype, protparents, visited):
|
def _validate_prototype(key, prototype, protparents, visited):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue