Removing direct access to Account.db._playable_characters in favor of Account.add_character(char) and Account.remove_character(char). Account.characters already handles all filtering so am cleaning up lots of repeated list comprehensions which remove/filter deleted characters.
This commit is contained in:
parent
a8cf8e166a
commit
f782cd8fc8
10 changed files with 124 additions and 60 deletions
|
|
@ -236,6 +236,39 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
|
|
||||||
return objs
|
return objs
|
||||||
|
|
||||||
|
def add_character(self, character: "DefaultCharacter"):
|
||||||
|
"""
|
||||||
|
Add a character to this account's list of playable characters.
|
||||||
|
"""
|
||||||
|
if character not in self.db._playable_characters:
|
||||||
|
self.db._playable_characters.append(character)
|
||||||
|
self.at_post_add_character(character)
|
||||||
|
|
||||||
|
def at_post_add_character(self, character: "DefaultCharacter"):
|
||||||
|
"""
|
||||||
|
Called after a character is added to this account's list of playable characters.
|
||||||
|
|
||||||
|
Use it to easily implement custom logic when a character is added to an account.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def remove_character(self, character):
|
||||||
|
"""
|
||||||
|
Remove a character from this account's list of playable characters.
|
||||||
|
"""
|
||||||
|
if character in self.db._playable_characters:
|
||||||
|
self.db._playable_characters.remove(character)
|
||||||
|
self.at_post_remove_character(character)
|
||||||
|
|
||||||
|
def at_post_remove_character(self, character):
|
||||||
|
"""
|
||||||
|
Called after a character is removed from this account's list of playable characters.
|
||||||
|
|
||||||
|
Use it to easily implement custom logic when a character is removed from an account.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def uses_screenreader(self, session=None):
|
def uses_screenreader(self, session=None):
|
||||||
"""
|
"""
|
||||||
Shortcut to determine if a session uses a screenreader. If no session given,
|
Shortcut to determine if a session uses a screenreader. If no session given,
|
||||||
|
|
@ -743,8 +776,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
)
|
)
|
||||||
if character:
|
if character:
|
||||||
# Update playable character list
|
# Update playable character list
|
||||||
if character not in self.characters:
|
self.add_character(character)
|
||||||
self.db._playable_characters.append(character)
|
|
||||||
|
|
||||||
# We need to set this to have @ic auto-connect to this character
|
# We need to set this to have @ic auto-connect to this character
|
||||||
self.db._last_puppet = character
|
self.db._last_puppet = character
|
||||||
|
|
@ -1483,11 +1515,8 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
||||||
else:
|
else:
|
||||||
# In this mode we don't auto-connect but by default end up at a character selection
|
# In this mode we don't auto-connect but by default end up at a character selection
|
||||||
# screen. We execute look on the account.
|
# screen. We execute look on the account.
|
||||||
# we make sure to clean up the _playable_characters list in case
|
|
||||||
# any was deleted in the interim.
|
|
||||||
self.db._playable_characters = [char for char in self.db._playable_characters if char]
|
|
||||||
self.msg(
|
self.msg(
|
||||||
self.at_look(target=self.db._playable_characters, session=session), session=session
|
self.at_look(target=self.characters, session=session), session=session
|
||||||
)
|
)
|
||||||
|
|
||||||
def at_failed_login(self, session, **kwargs):
|
def at_failed_login(self, session, **kwargs):
|
||||||
|
|
@ -1825,11 +1854,8 @@ class DefaultGuest(DefaultAccount):
|
||||||
be on the safe side.
|
be on the safe side.
|
||||||
"""
|
"""
|
||||||
super().at_server_shutdown()
|
super().at_server_shutdown()
|
||||||
characters = self.db._playable_characters
|
for character in self.characters:
|
||||||
if characters:
|
character.delete()
|
||||||
for character in characters:
|
|
||||||
if character:
|
|
||||||
character.delete()
|
|
||||||
|
|
||||||
def at_post_disconnect(self, **kwargs):
|
def at_post_disconnect(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1841,8 +1867,6 @@ class DefaultGuest(DefaultAccount):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
super().at_post_disconnect()
|
super().at_post_disconnect()
|
||||||
characters = self.db._playable_characters
|
for character in self.characters:
|
||||||
for character in characters:
|
character.delete()
|
||||||
if character:
|
|
||||||
character.delete()
|
|
||||||
self.delete()
|
self.delete()
|
||||||
|
|
|
||||||
|
|
@ -60,12 +60,7 @@ class MuxAccountLookCommand(COMMAND_DEFAULT_CLASS):
|
||||||
|
|
||||||
super().parse()
|
super().parse()
|
||||||
|
|
||||||
playable = self.account.db._playable_characters
|
playable = self.account.characters
|
||||||
if playable is not None:
|
|
||||||
# clean up list if character object was deleted in between
|
|
||||||
if None in playable:
|
|
||||||
playable = [character for character in playable if character]
|
|
||||||
self.account.db._playable_characters = playable
|
|
||||||
# store playable property
|
# store playable property
|
||||||
if self.args:
|
if self.args:
|
||||||
self.playable = dict((utils.to_str(char.key.lower()), char) for char in playable).get(
|
self.playable = dict((utils.to_str(char.key.lower()), char) for char in playable).get(
|
||||||
|
|
@ -155,8 +150,8 @@ class CmdCharCreate(COMMAND_DEFAULT_CLASS):
|
||||||
if (
|
if (
|
||||||
not account.is_superuser
|
not account.is_superuser
|
||||||
and not account.check_permstring("Developer")
|
and not account.check_permstring("Developer")
|
||||||
and account.db._playable_characters
|
and account.characters
|
||||||
and len(account.db._playable_characters) >= _MAX_NR_CHARACTERS
|
and len(account.characters) >= _MAX_NR_CHARACTERS
|
||||||
):
|
):
|
||||||
plural = "" if _MAX_NR_CHARACTERS == 1 else "s"
|
plural = "" if _MAX_NR_CHARACTERS == 1 else "s"
|
||||||
self.msg(f"You may only have a maximum of {_MAX_NR_CHARACTERS} character{plural}.")
|
self.msg(f"You may only have a maximum of {_MAX_NR_CHARACTERS} character{plural}.")
|
||||||
|
|
@ -184,7 +179,7 @@ class CmdCharCreate(COMMAND_DEFAULT_CLASS):
|
||||||
"puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer);delete:id(%i) or"
|
"puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer);delete:id(%i) or"
|
||||||
" perm(Admin)" % (new_character.id, account.id, account.id)
|
" perm(Admin)" % (new_character.id, account.id, account.id)
|
||||||
)
|
)
|
||||||
account.db._playable_characters.append(new_character)
|
account.add_character(new_character)
|
||||||
if desc:
|
if desc:
|
||||||
new_character.db.desc = desc
|
new_character.db.desc = desc
|
||||||
elif not new_character.db.desc:
|
elif not new_character.db.desc:
|
||||||
|
|
@ -223,7 +218,7 @@ class CmdCharDelete(COMMAND_DEFAULT_CLASS):
|
||||||
# use the playable_characters list to search
|
# use the playable_characters list to search
|
||||||
match = [
|
match = [
|
||||||
char
|
char
|
||||||
for char in utils.make_iter(account.db._playable_characters)
|
for char in utils.make_iter(account.characters)
|
||||||
if char.key.lower() == self.args.lower()
|
if char.key.lower() == self.args.lower()
|
||||||
]
|
]
|
||||||
if not match:
|
if not match:
|
||||||
|
|
@ -243,9 +238,7 @@ class CmdCharDelete(COMMAND_DEFAULT_CLASS):
|
||||||
# only take action
|
# only take action
|
||||||
delobj = caller.ndb._char_to_delete
|
delobj = caller.ndb._char_to_delete
|
||||||
key = delobj.key
|
key = delobj.key
|
||||||
caller.db._playable_characters = [
|
caller.remove_character(delobj)
|
||||||
pc for pc in caller.db._playable_characters if pc != delobj
|
|
||||||
]
|
|
||||||
delobj.delete()
|
delobj.delete()
|
||||||
self.msg(f"Character '{key}' was permanently deleted.")
|
self.msg(f"Character '{key}' was permanently deleted.")
|
||||||
logger.log_sec(
|
logger.log_sec(
|
||||||
|
|
@ -314,13 +307,13 @@ class CmdIC(COMMAND_DEFAULT_CLASS):
|
||||||
else:
|
else:
|
||||||
# argument given
|
# argument given
|
||||||
|
|
||||||
if account.db._playable_characters:
|
if (playables := account.characters):
|
||||||
# look at the playable_characters list first
|
# look at the playable_characters list first
|
||||||
character_candidates.extend(
|
character_candidates.extend(
|
||||||
utils.make_iter(
|
utils.make_iter(
|
||||||
account.search(
|
account.search(
|
||||||
self.args,
|
self.args,
|
||||||
candidates=account.db._playable_characters,
|
candidates=playables,
|
||||||
search_object=True,
|
search_object=True,
|
||||||
quiet=True,
|
quiet=True,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -465,3 +465,64 @@ class CmdUnconnectedInfo(COMMAND_DEFAULT_CLASS):
|
||||||
utils.get_evennia_version(),
|
utils.get_evennia_version(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_account(session, accountname, password, permissions, typeclass=None, email=None):
|
||||||
|
"""
|
||||||
|
Helper function, creates an account of the specified typeclass.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
new_account = create.create_account(
|
||||||
|
accountname, email, password, permissions=permissions, typeclass=typeclass
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
session.msg(
|
||||||
|
"There was an error creating the Account:\n%s\n If this problem persists, contact an"
|
||||||
|
" admin." % e
|
||||||
|
)
|
||||||
|
logger.log_trace()
|
||||||
|
return False
|
||||||
|
|
||||||
|
# This needs to be set so the engine knows this account is
|
||||||
|
# logging in for the first time. (so it knows to call the right
|
||||||
|
# hooks during login later)
|
||||||
|
new_account.db.FIRST_LOGIN = True
|
||||||
|
|
||||||
|
# join the new account to the public channel
|
||||||
|
pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"])
|
||||||
|
if not pchannel or not pchannel.connect(new_account):
|
||||||
|
string = "New account '%s' could not connect to public channel!" % new_account.key
|
||||||
|
logger.log_err(string)
|
||||||
|
return new_account
|
||||||
|
|
||||||
|
|
||||||
|
def _create_character(session, new_account, typeclass, home, permissions):
|
||||||
|
"""
|
||||||
|
Helper function, creates a character based on an account's name.
|
||||||
|
This is meant for Guest and AUTO_CREATRE_CHARACTER_WITH_ACCOUNT=True situations.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
new_character = create.create_object(
|
||||||
|
typeclass, key=new_account.key, home=home, permissions=permissions
|
||||||
|
)
|
||||||
|
# set playable character list
|
||||||
|
new_account.add_character(new_character)
|
||||||
|
|
||||||
|
# allow only the character itself and the account to puppet this character (and Developers).
|
||||||
|
new_character.locks.add(
|
||||||
|
"puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer)"
|
||||||
|
% (new_character.id, new_account.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
# If no description is set, set a default description
|
||||||
|
if not new_character.db.desc:
|
||||||
|
new_character.db.desc = "This is a character."
|
||||||
|
# We need to set this to have ic auto-connect to this character
|
||||||
|
new_account.db._last_puppet = new_character
|
||||||
|
except Exception as e:
|
||||||
|
session.msg(
|
||||||
|
"There was an error creating the Character:\n%s\n If this problem persists, contact an"
|
||||||
|
" admin." % e
|
||||||
|
)
|
||||||
|
logger.log_trace()
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ class ContribCmdCharCreate(MuxAccountCommand):
|
||||||
session = self.session
|
session = self.session
|
||||||
|
|
||||||
# only one character should be in progress at a time, so we check for WIPs first
|
# only one character should be in progress at a time, so we check for WIPs first
|
||||||
in_progress = [chara for chara in account.db._playable_characters if chara.db.chargen_step]
|
in_progress = [chara for chara in account.characters if chara.db.chargen_step]
|
||||||
|
|
||||||
if len(in_progress):
|
if len(in_progress):
|
||||||
# we're continuing chargen for a WIP character
|
# we're continuing chargen for a WIP character
|
||||||
|
|
@ -64,7 +64,7 @@ class ContribCmdCharCreate(MuxAccountCommand):
|
||||||
charmax = settings.MAX_NR_CHARACTERS
|
charmax = settings.MAX_NR_CHARACTERS
|
||||||
|
|
||||||
if not account.is_superuser and (
|
if not account.is_superuser and (
|
||||||
account.db._playable_characters and len(account.db._playable_characters) >= charmax
|
account.characters and len(account.characters) >= charmax
|
||||||
):
|
):
|
||||||
plural = "" if charmax == 1 else "s"
|
plural = "" if charmax == 1 else "s"
|
||||||
self.msg(f"You may only create a maximum of {charmax} character{plural}.")
|
self.msg(f"You may only create a maximum of {charmax} character{plural}.")
|
||||||
|
|
@ -90,7 +90,7 @@ class ContribCmdCharCreate(MuxAccountCommand):
|
||||||
)
|
)
|
||||||
# initalize the new character to the beginning of the chargen menu
|
# initalize the new character to the beginning of the chargen menu
|
||||||
new_character.db.chargen_step = "menunode_welcome"
|
new_character.db.chargen_step = "menunode_welcome"
|
||||||
account.db._playable_characters.append(new_character)
|
account.add_character(new_character)
|
||||||
|
|
||||||
# set the menu node to start at to the character's last saved step
|
# set the menu node to start at to the character's last saved step
|
||||||
startnode = new_character.db.chargen_step
|
startnode = new_character.db.chargen_step
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,7 @@ def node_apply_character(caller, raw_string, **kwargs):
|
||||||
"""
|
"""
|
||||||
tmp_character = kwargs["tmp_character"]
|
tmp_character = kwargs["tmp_character"]
|
||||||
new_character = tmp_character.apply(caller)
|
new_character = tmp_character.apply(caller)
|
||||||
caller.db._playable_characters.append(new_character)
|
caller.add_character(new_character)
|
||||||
|
|
||||||
text = "Character created!"
|
text = "Character created!"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1149,10 +1149,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
||||||
# sever the connection (important!)
|
# sever the connection (important!)
|
||||||
if self.account:
|
if self.account:
|
||||||
# Remove the object from playable characters list
|
# Remove the object from playable characters list
|
||||||
if self in self.account.db._playable_characters:
|
self.account.remove_character(self)
|
||||||
self.account.db._playable_characters = [
|
|
||||||
x for x in self.account.db._playable_characters if x != self
|
|
||||||
]
|
|
||||||
for session in self.sessions.all():
|
for session in self.sessions.all():
|
||||||
self.account.unpuppet_object(session)
|
self.account.unpuppet_object(session)
|
||||||
|
|
||||||
|
|
@ -2562,8 +2559,7 @@ class DefaultCharacter(DefaultObject):
|
||||||
obj.db.creator_ip = ip
|
obj.db.creator_ip = ip
|
||||||
if account:
|
if account:
|
||||||
obj.db.creator_id = account.id
|
obj.db.creator_id = account.id
|
||||||
if obj not in account.characters:
|
account.add_character(obj)
|
||||||
account.db._playable_characters.append(obj)
|
|
||||||
|
|
||||||
# Add locks
|
# Add locks
|
||||||
if not locks and account:
|
if not locks and account:
|
||||||
|
|
|
||||||
|
|
@ -98,16 +98,15 @@ def create_objects():
|
||||||
|
|
||||||
# Create the in-game god-character for account #1 and set
|
# Create the in-game god-character for account #1 and set
|
||||||
# it to exist in Limbo.
|
# it to exist in Limbo.
|
||||||
character_typeclass = settings.BASE_CHARACTER_TYPECLASS
|
|
||||||
try:
|
try:
|
||||||
superuser_character = ObjectDB.objects.get(id=1)
|
superuser_character = ObjectDB.objects.get(id=1)
|
||||||
except ObjectDB.DoesNotExist:
|
except ObjectDB.DoesNotExist:
|
||||||
superuser_character = create.create_object(
|
superuser_character, errors = superuser.create_character(
|
||||||
character_typeclass, key=superuser.username, nohome=True
|
key=superuser.username, nohome=True, description=_("This is User #1.")
|
||||||
)
|
)
|
||||||
|
if errors:
|
||||||
|
raise Exception(str(errors))
|
||||||
|
|
||||||
superuser_character.db_typeclass_path = character_typeclass
|
|
||||||
superuser_character.db.desc = _("This is User #1.")
|
|
||||||
superuser_character.locks.add(
|
superuser_character.locks.add(
|
||||||
"examine:perm(Developer);edit:false();delete:false();boot:false();msg:all();puppet:false()"
|
"examine:perm(Developer);edit:false();delete:false();boot:false();msg:all();puppet:false()"
|
||||||
)
|
)
|
||||||
|
|
@ -118,11 +117,6 @@ def create_objects():
|
||||||
superuser.attributes.add("_first_login", True)
|
superuser.attributes.add("_first_login", True)
|
||||||
superuser.attributes.add("_last_puppet", superuser_character)
|
superuser.attributes.add("_last_puppet", superuser_character)
|
||||||
|
|
||||||
try:
|
|
||||||
superuser.db._playable_characters.append(superuser_character)
|
|
||||||
except AttributeError:
|
|
||||||
superuser.db_playable_characters = [superuser_character]
|
|
||||||
|
|
||||||
room_typeclass = settings.BASE_ROOM_TYPECLASS
|
room_typeclass = settings.BASE_ROOM_TYPECLASS
|
||||||
try:
|
try:
|
||||||
limbo_obj = ObjectDB.objects.get(id=2)
|
limbo_obj = ObjectDB.objects.get(id=2)
|
||||||
|
|
|
||||||
|
|
@ -647,9 +647,8 @@ class Evennia:
|
||||||
for guest in AccountDB.objects.all().filter(
|
for guest in AccountDB.objects.all().filter(
|
||||||
db_typeclass_path=settings.BASE_GUEST_TYPECLASS
|
db_typeclass_path=settings.BASE_GUEST_TYPECLASS
|
||||||
):
|
):
|
||||||
for character in guest.db._playable_characters:
|
for character in guest.characters:
|
||||||
if character:
|
character.delete()
|
||||||
character.delete()
|
|
||||||
guest.delete()
|
guest.delete()
|
||||||
for mod in SERVER_STARTSTOP_MODULES:
|
for mod in SERVER_STARTSTOP_MODULES:
|
||||||
if hasattr(mod, "at_server_cold_start"):
|
if hasattr(mod, "at_server_cold_start"):
|
||||||
|
|
|
||||||
|
|
@ -310,7 +310,7 @@ class ObjectAdmin(admin.ModelAdmin):
|
||||||
This will:
|
This will:
|
||||||
|
|
||||||
- Set account.db._last_puppet to this object
|
- Set account.db._last_puppet to this object
|
||||||
- Add object to account.db._playable_characters
|
- Add object to account.characters
|
||||||
- Change object locks to allow puppeting by account
|
- Change object locks to allow puppeting by account
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
@ -319,10 +319,7 @@ class ObjectAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
if account:
|
if account:
|
||||||
account.db._last_puppet = obj
|
account.db._last_puppet = obj
|
||||||
if not account.db._playable_characters:
|
account.add_character(obj)
|
||||||
account.db._playable_characters = []
|
|
||||||
if obj not in account.db._playable_characters:
|
|
||||||
account.db._playable_characters.append(obj)
|
|
||||||
if not obj.access(account, "puppet"):
|
if not obj.access(account, "puppet"):
|
||||||
lock = obj.locks.get("puppet")
|
lock = obj.locks.get("puppet")
|
||||||
lock += f" or pid({account.id})"
|
lock += f" or pid({account.id})"
|
||||||
|
|
@ -331,7 +328,7 @@ class ObjectAdmin(admin.ModelAdmin):
|
||||||
request,
|
request,
|
||||||
"Did the following (where possible): "
|
"Did the following (where possible): "
|
||||||
f"Set Account.db._last_puppet = {obj}, "
|
f"Set Account.db._last_puppet = {obj}, "
|
||||||
f"Added {obj} to Account.db._playable_characters list, "
|
f"Added {obj} to Account.characters list, "
|
||||||
f"Added 'puppet:pid({account.id})' lock to {obj}.",
|
f"Added 'puppet:pid({account.id})' lock to {obj}.",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ def collect_topics(account):
|
||||||
cmd_help_topics = []
|
cmd_help_topics = []
|
||||||
if not str(account) == "AnonymousUser":
|
if not str(account) == "AnonymousUser":
|
||||||
# create list of account and account's puppets
|
# create list of account and account's puppets
|
||||||
puppets = account.db._playable_characters + [account]
|
puppets = account.characters + [account]
|
||||||
# add the account's and puppets' commands to cmd_help_topics list
|
# add the account's and puppets' commands to cmd_help_topics list
|
||||||
for puppet in puppets:
|
for puppet in puppets:
|
||||||
for cmdset in puppet.cmdset.get():
|
for cmdset in puppet.cmdset.get():
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue