Merge branch 'develop' into contrib/evadventure
This commit is contained in:
commit
f05add7c5b
13 changed files with 381 additions and 357 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue