Merge branch 'develop' into contrib/evadventure

This commit is contained in:
Griatch 2022-09-17 13:23:13 +02:00
commit f05add7c5b
13 changed files with 381 additions and 357 deletions

View file

@ -45,6 +45,9 @@ _SESSIONS = None
_AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1))
_MULTISESSION_MODE = settings.MULTISESSION_MODE
_AUTO_CREATE_CHARACTER_WITH_ACCOUNT = settings.AUTO_CREATE_CHARACTER_WITH_ACCOUNT
_AUTO_PUPPET_ON_LOGIN = settings.AUTO_PUPPET_ON_LOGIN
_MAX_NR_SIMULTANEOUS_PUPPETS = settings.MAX_NR_SIMULTANEOUS_PUPPETS
_MAX_NR_CHARACTERS = settings.MAX_NR_CHARACTERS
_CMDSET_ACCOUNT = settings.CMDSET_ACCOUNT
_MUDINFO_CHANNEL = None
@ -338,7 +341,6 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
self.msg(_("|c{key}|R is already puppeted by another Account.").format(key=obj.key))
return
# do the puppeting
if session.puppet:
# cleanly unpuppet eventual previous object puppeted by this session
self.unpuppet_object(session)
@ -346,6 +348,21 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
# was left with a lingering account/session reference from an unclean
# server kill or similar
# check so we are not puppeting too much already
if _MAX_NR_SIMULTANEOUS_PUPPETS is not None:
already_puppeted = self.get_all_puppets()
if (
not self.is_superuser
and not self.check_permstring("Developer")
and obj not in already_puppeted
and len(self.get_all_puppets()) >= _MAX_NR_SIMULTANEOUS_PUPPETS
):
self.msg(
_(f"You cannot control any more puppets (max {_MAX_NR_SIMULTANEOUS_PUPPETS})")
)
return
# do the puppeting
obj.at_pre_puppet(self, session=session)
# do the connection
@ -452,7 +469,10 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
"""
ip = kwargs.get("ip", "").strip()
ip = kwargs.get("ip", "")
if isinstance(ip, (tuple, list)):
ip = ip[0]
ip = ip.strip()
username = kwargs.get("username", "").lower().strip()
# Check IP and/or name bans
@ -772,6 +792,9 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
typeclass = kwargs.get("typeclass", cls)
ip = kwargs.get("ip", "")
if isinstance(ip, (tuple, list)):
ip = ip[0]
if ip and CREATION_THROTTLE.check(ip):
errors.append(
_("You are creating too many accounts. Please log into an existing account.")
@ -843,7 +866,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
errors.append(string)
logger.log_err(string)
if account and settings.MULTISESSION_MODE < 2:
if account and _AUTO_CREATE_CHARACTER_WITH_ACCOUNT:
# Auto-create a character to go with this account
character, errs = account.create_character(
@ -1237,7 +1260,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
"""
# set an (empty) attribute holding the characters this account has
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("_saved_protocol_flags", {}, lockstring=lockstring)
@ -1434,7 +1457,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
Notes:
This is called *before* an eventual Character's
`at_post_login` hook. By default it is used to set up
auto-puppeting based on `MULTISESSION_MODE`.
auto-puppeting based on `MULTISESSION_MODE`
"""
# if we have saved protocol flags on ourselves, load them here.
@ -1447,23 +1470,15 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
session.msg(logged_in={})
self._send_to_connect_channel(_("|G{key} connected|n").format(key=self.key))
if _MULTISESSION_MODE == 0:
# in this mode we should have only one character available. We
# try to auto-connect to our last connected object, if any
if _AUTO_PUPPET_ON_LOGIN:
# in this mode we try to auto-connect to our last connected object, if any
try:
self.puppet_object(session, self.db._last_puppet)
except RuntimeError:
self.msg(_("The Character does not exist."))
return
elif _MULTISESSION_MODE == 1:
# in this mode all sessions connect to the same puppet.
try:
self.puppet_object(session, self.db._last_puppet)
except RuntimeError:
self.msg(_("The Character does not exist."))
return
elif _MULTISESSION_MODE in (2, 3):
# In this mode we by default end up at a character selection
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.
@ -1583,6 +1598,24 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
"""
pass
ooc_appearance_template = """
--------------------------------------------------------------------
{header}
{sessions}
|whelp|n - more commands
|wpublic <text>|n - talk on public channel
|wcharcreate <name> [=description]|n - create new character
|wchardelete <name>|n - delete a character
|wic <name>|n - enter the game as character (|wooc|n to get back here)
|wic|n - enter the game as latest character controlled.
{characters}
{footer}
--------------------------------------------------------------------
""".strip()
def at_look(self, target=None, session=None, **kwargs):
"""
Called when this object executes a look. It allows to customize
@ -1590,7 +1623,7 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
Args:
target (Object or list, optional): An object or a list
objects to inspect.
objects to inspect. This is normally a list of characters.
session (Session, optional): The session doing this look.
**kwargs (dict): Arbitrary, optional arguments for users
overriding the call (unused by default).
@ -1607,94 +1640,75 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase):
return target.return_appearance(self)
else:
return f"{target} has no in-game appearance."
else:
# list of targets - make list to disconnect from db
characters = list(tar for tar in target if tar) if target else []
sessions = self.sessions.all()
if not sessions:
# no sessions, nothing to report
return ""
is_su = self.is_superuser
# text shown when looking in the ooc area
result = [f"Account |g{self.key}|n (you are Out-of-Character)"]
# multiple targets - this is a list of characters
characters = list(tar for tar in target if tar) if target else []
ncars = len(characters)
sessions = self.sessions.all()
nsess = len(sessions)
nsess = len(sessions)
result.append(
nsess == 1
and "\n\n|wConnected session:|n"
or f"\n\n|wConnected sessions ({nsess}):|n"
if not nsess:
# no sessions, nothing to report
return ""
# header text
txt_header = f"Account |g{self.name}|n (you are Out-of-Character)"
# sessions
sess_strings = []
for isess, sess in enumerate(sessions):
ip_addr = sess.address[0] if isinstance(sess.address, tuple) else sess.address
addr = f"{sess.protocol_key} ({ip_addr})"
sess_str = (
f"|w* {isess + 1}|n"
if session and session.sessid == sess.sessid
else f" {isess + 1}"
)
for isess, sess in enumerate(sessions):
csessid = sess.sessid
addr = "%s (%s)" % (
sess.protocol_key,
isinstance(sess.address, tuple) and str(sess.address[0]) or str(sess.address),
)
result.append(
"\n %s %s"
% (
session
and session.sessid == csessid
and "|w* %s|n" % (isess + 1)
or " %s" % (isess + 1),
addr,
)
)
result.append("\n\n |whelp|n - more commands")
result.append("\n |wpublic <Text>|n - talk on public channel")
charmax = _MAX_NR_CHARACTERS
sess_strings.append(f"{sess_str} {addr}")
if is_su or len(characters) < charmax:
if not characters:
result.append(
"\n\n You don't have any characters yet. See |whelp charcreate|n for "
"creating one."
)
txt_sessions = "|wConnected session(s):|n\n" + "\n".join(sess_strings)
if not characters:
txt_characters = "You don't have a character yet. Use |wcharcreate|n."
else:
max_chars = (
"unlimited"
if self.is_superuser or _MAX_NR_CHARACTERS is None
else _MAX_NR_CHARACTERS
)
char_strings = []
for char in characters:
csessions = char.sessions.all()
if csessions:
for sess in csessions:
# character is already puppeted
sid = sess in sessions and sessions.index(sess) + 1
if sess and sid:
char_strings.append(
f" - |G{char.name}|n [{', '.join(char.permissions.all())}] "
f"(played by you in session {sid})"
)
else:
char_strings.append(
f" - |R{char.name}|n [{', '.join(char.permissions.all())}] "
"(played by someone else)"
)
else:
result.append("\n |wcharcreate <name> [=description]|n - create new character")
result.append(
"\n |wchardelete <name>|n - delete a character (cannot be undone!)"
)
# character is "free to puppet"
char_strings.append(f" - {char.name} [{', '.join(char.permissions.all())}]")
if characters:
string_s_ending = len(characters) > 1 and "s" or ""
result.append("\n |wic <character>|n - enter the game (|wooc|n to get back here)")
if is_su:
result.append(
f"\n\nAvailable character{string_s_ending} ({len(characters)}/unlimited):"
)
else:
result.append(
"\n\nAvailable character%s%s:"
% (
string_s_ending,
charmax > 1 and " (%i/%i)" % (len(characters), charmax) or "",
)
)
for char in characters:
csessions = char.sessions.all()
if csessions:
for sess in csessions:
# character is already puppeted
sid = sess in sessions and sessions.index(sess) + 1
if sess and sid:
result.append(
f"\n - |G{char.key}|n [{', '.join(char.permissions.all())}] "
f"(played by you in session {sid})"
)
else:
result.append(
f"\n - |R{char.key}|n [{', '.join(char.permissions.all())}] "
"(played by someone else)"
)
else:
# character is "free to puppet"
result.append(f"\n - {char.key} [{', '.join(char.permissions.all())}]")
look_string = ("-" * 68) + "\n" + "".join(result) + "\n" + ("-" * 68)
return look_string
txt_characters = (
f"Available character(s) ({ncars}/{max_chars}, |wic <name>|n to play):|n\n"
+ "\n".join(char_strings)
)
return self.ooc_appearance_template.format(
header=txt_header,
sessions=txt_sessions,
characters=txt_characters,
footer="",
)
class DefaultGuest(DefaultAccount):
@ -1789,8 +1803,9 @@ class DefaultGuest(DefaultAccount):
def at_post_login(self, session=None, **kwargs):
"""
In theory, guests only have one character regardless of which
MULTISESSION_MODE we're in. They don't get a choice.
By default, Guests only have one character regardless of which
MAX_NR_CHARACTERS we use. They also always auto-puppet a matching
character and don't get a choice.
Args:
session (Session, optional): Session connecting.

View file

@ -16,22 +16,16 @@ account info and OOC account configuration variables etc.
"""
from django.conf import settings
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.encoding import smart_str
from evennia.accounts.manager import AccountDBManager
from evennia.server.signals import SIGNAL_ACCOUNT_POST_RENAME
from evennia.typeclasses.models import TypedObject
from evennia.utils.utils import make_iter
from evennia.server.signals import SIGNAL_ACCOUNT_POST_RENAME
__all__ = ("AccountDB",)
# _ME = _("me")
# _SELF = _("self")
_MULTISESSION_MODE = settings.MULTISESSION_MODE
_GA = object.__getattribute__
_SA = object.__setattr__
_DA = object.__delattr__
@ -94,8 +88,10 @@ class AccountDB(TypedObject, AbstractUser):
"cmdset",
max_length=255,
null=True,
help_text="optional python path to a cmdset class. If creating a Character, this will "
"default to settings.CMDSET_CHARACTER.",
help_text=(
"optional python path to a cmdset class. If creating a Character, this will "
"default to settings.CMDSET_CHARACTER."
),
)
# marks if this is a "virtual" bot account object
db_is_bot = models.BooleanField(