mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
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
|
||||
|
||||
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):
|
||||
"""
|
||||
Shortcut to determine if a session uses a screenreader. If no session given,
|
||||
|
|
@ -743,8 +776,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
)
|
||||
if character:
|
||||
# Update playable character list
|
||||
if character not in self.characters:
|
||||
self.db._playable_characters.append(character)
|
||||
self.add_character(character)
|
||||
|
||||
# We need to set this to have @ic auto-connect to this character
|
||||
self.db._last_puppet = character
|
||||
|
|
@ -1483,11 +1515,8 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
|
|||
else:
|
||||
# In this mode we don't auto-connect but by default end up at a character selection
|
||||
# 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.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):
|
||||
|
|
@ -1825,11 +1854,8 @@ class DefaultGuest(DefaultAccount):
|
|||
be on the safe side.
|
||||
"""
|
||||
super().at_server_shutdown()
|
||||
characters = self.db._playable_characters
|
||||
if characters:
|
||||
for character in characters:
|
||||
if character:
|
||||
character.delete()
|
||||
for character in self.characters:
|
||||
character.delete()
|
||||
|
||||
def at_post_disconnect(self, **kwargs):
|
||||
"""
|
||||
|
|
@ -1841,8 +1867,6 @@ class DefaultGuest(DefaultAccount):
|
|||
|
||||
"""
|
||||
super().at_post_disconnect()
|
||||
characters = self.db._playable_characters
|
||||
for character in characters:
|
||||
if character:
|
||||
character.delete()
|
||||
for character in self.characters:
|
||||
character.delete()
|
||||
self.delete()
|
||||
|
|
|
|||
|
|
@ -60,12 +60,7 @@ class MuxAccountLookCommand(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
super().parse()
|
||||
|
||||
playable = self.account.db._playable_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
|
||||
playable = self.account.characters
|
||||
# store playable property
|
||||
if self.args:
|
||||
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 (
|
||||
not account.is_superuser
|
||||
and not account.check_permstring("Developer")
|
||||
and account.db._playable_characters
|
||||
and len(account.db._playable_characters) >= _MAX_NR_CHARACTERS
|
||||
and account.characters
|
||||
and len(account.characters) >= _MAX_NR_CHARACTERS
|
||||
):
|
||||
plural = "" if _MAX_NR_CHARACTERS == 1 else "s"
|
||||
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"
|
||||
" perm(Admin)" % (new_character.id, account.id, account.id)
|
||||
)
|
||||
account.db._playable_characters.append(new_character)
|
||||
account.add_character(new_character)
|
||||
if desc:
|
||||
new_character.db.desc = desc
|
||||
elif not new_character.db.desc:
|
||||
|
|
@ -223,7 +218,7 @@ class CmdCharDelete(COMMAND_DEFAULT_CLASS):
|
|||
# use the playable_characters list to search
|
||||
match = [
|
||||
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 not match:
|
||||
|
|
@ -243,9 +238,7 @@ class CmdCharDelete(COMMAND_DEFAULT_CLASS):
|
|||
# only take action
|
||||
delobj = caller.ndb._char_to_delete
|
||||
key = delobj.key
|
||||
caller.db._playable_characters = [
|
||||
pc for pc in caller.db._playable_characters if pc != delobj
|
||||
]
|
||||
caller.remove_character(delobj)
|
||||
delobj.delete()
|
||||
self.msg(f"Character '{key}' was permanently deleted.")
|
||||
logger.log_sec(
|
||||
|
|
@ -314,13 +307,13 @@ class CmdIC(COMMAND_DEFAULT_CLASS):
|
|||
else:
|
||||
# argument given
|
||||
|
||||
if account.db._playable_characters:
|
||||
if (playables := account.characters):
|
||||
# look at the playable_characters list first
|
||||
character_candidates.extend(
|
||||
utils.make_iter(
|
||||
account.search(
|
||||
self.args,
|
||||
candidates=account.db._playable_characters,
|
||||
candidates=playables,
|
||||
search_object=True,
|
||||
quiet=True,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -465,3 +465,64 @@ class CmdUnconnectedInfo(COMMAND_DEFAULT_CLASS):
|
|||
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
|
||||
|
||||
# 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):
|
||||
# we're continuing chargen for a WIP character
|
||||
|
|
@ -64,7 +64,7 @@ class ContribCmdCharCreate(MuxAccountCommand):
|
|||
charmax = settings.MAX_NR_CHARACTERS
|
||||
|
||||
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"
|
||||
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
|
||||
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
|
||||
startnode = new_character.db.chargen_step
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ def node_apply_character(caller, raw_string, **kwargs):
|
|||
"""
|
||||
tmp_character = kwargs["tmp_character"]
|
||||
new_character = tmp_character.apply(caller)
|
||||
caller.db._playable_characters.append(new_character)
|
||||
caller.add_character(new_character)
|
||||
|
||||
text = "Character created!"
|
||||
|
||||
|
|
|
|||
|
|
@ -1149,10 +1149,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
|
|||
# sever the connection (important!)
|
||||
if self.account:
|
||||
# Remove the object from playable characters list
|
||||
if self in self.account.db._playable_characters:
|
||||
self.account.db._playable_characters = [
|
||||
x for x in self.account.db._playable_characters if x != self
|
||||
]
|
||||
self.account.remove_character(self)
|
||||
for session in self.sessions.all():
|
||||
self.account.unpuppet_object(session)
|
||||
|
||||
|
|
@ -2562,8 +2559,7 @@ class DefaultCharacter(DefaultObject):
|
|||
obj.db.creator_ip = ip
|
||||
if account:
|
||||
obj.db.creator_id = account.id
|
||||
if obj not in account.characters:
|
||||
account.db._playable_characters.append(obj)
|
||||
account.add_character(obj)
|
||||
|
||||
# Add locks
|
||||
if not locks and account:
|
||||
|
|
|
|||
|
|
@ -98,16 +98,15 @@ def create_objects():
|
|||
|
||||
# Create the in-game god-character for account #1 and set
|
||||
# it to exist in Limbo.
|
||||
character_typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||
try:
|
||||
superuser_character = ObjectDB.objects.get(id=1)
|
||||
except ObjectDB.DoesNotExist:
|
||||
superuser_character = create.create_object(
|
||||
character_typeclass, key=superuser.username, nohome=True
|
||||
superuser_character, errors = superuser.create_character(
|
||||
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(
|
||||
"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("_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
|
||||
try:
|
||||
limbo_obj = ObjectDB.objects.get(id=2)
|
||||
|
|
|
|||
|
|
@ -647,9 +647,8 @@ class Evennia:
|
|||
for guest in AccountDB.objects.all().filter(
|
||||
db_typeclass_path=settings.BASE_GUEST_TYPECLASS
|
||||
):
|
||||
for character in guest.db._playable_characters:
|
||||
if character:
|
||||
character.delete()
|
||||
for character in guest.characters:
|
||||
character.delete()
|
||||
guest.delete()
|
||||
for mod in SERVER_STARTSTOP_MODULES:
|
||||
if hasattr(mod, "at_server_cold_start"):
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ class ObjectAdmin(admin.ModelAdmin):
|
|||
This will:
|
||||
|
||||
- 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
|
||||
|
||||
"""
|
||||
|
|
@ -319,10 +319,7 @@ class ObjectAdmin(admin.ModelAdmin):
|
|||
|
||||
if account:
|
||||
account.db._last_puppet = obj
|
||||
if not account.db._playable_characters:
|
||||
account.db._playable_characters = []
|
||||
if obj not in account.db._playable_characters:
|
||||
account.db._playable_characters.append(obj)
|
||||
account.add_character(obj)
|
||||
if not obj.access(account, "puppet"):
|
||||
lock = obj.locks.get("puppet")
|
||||
lock += f" or pid({account.id})"
|
||||
|
|
@ -331,7 +328,7 @@ class ObjectAdmin(admin.ModelAdmin):
|
|||
request,
|
||||
"Did the following (where possible): "
|
||||
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}.",
|
||||
)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ def collect_topics(account):
|
|||
cmd_help_topics = []
|
||||
if not str(account) == "AnonymousUser":
|
||||
# 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
|
||||
for puppet in puppets:
|
||||
for cmdset in puppet.cmdset.get():
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue