Reworked Menu-login contrib to latest EvMenu style.
This commit is contained in:
parent
b68a79ba27
commit
db3071356c
3 changed files with 175 additions and 281 deletions
|
|
@ -124,6 +124,7 @@ Web/Django standard initiative (@strikaco)
|
||||||
+ The `detail` command now also supports deleting details (like the tutorial-world version).
|
+ The `detail` command now also supports deleting details (like the tutorial-world version).
|
||||||
+ The new `ExtendedRoomCmdSet` includes all the extended-room commands and is now the recommended way
|
+ The new `ExtendedRoomCmdSet` includes all the extended-room commands and is now the recommended way
|
||||||
to install the extended-room contrib.
|
to install the extended-room contrib.
|
||||||
|
- Reworked `menu_login` contrib to use latest EvMenu standards. Now also supports guest logins.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ things you want from here into your game folder and change them there.
|
||||||
on a character and access it in an emote with a custom marker.
|
on a character and access it in an emote with a custom marker.
|
||||||
* Health Bar (Tim Ashley Jenkins 2017) - Tool to create colorful bars/meters.
|
* Health Bar (Tim Ashley Jenkins 2017) - Tool to create colorful bars/meters.
|
||||||
* Mail (grungies1138 2016) - An in-game mail system for communication.
|
* Mail (grungies1138 2016) - An in-game mail system for communication.
|
||||||
* Menu login (Griatch 2011) - A login system using menus asking
|
* Menu login (Griatch 2011, 2019, Vincent-lg 2016) - A login system using menus asking
|
||||||
for name/password rather than giving them as one command.
|
for name/password rather than giving them as one command.
|
||||||
* Map Builder (CloudKeeper 2016) - Build a game area based on a 2D
|
* Map Builder (CloudKeeper 2016) - Build a game area based on a 2D
|
||||||
"graphical" unicode map. Supports assymmetric exits.
|
"graphical" unicode map. Supports assymmetric exits.
|
||||||
|
|
|
||||||
|
|
@ -1,320 +1,209 @@
|
||||||
"""
|
"""
|
||||||
A login menu using EvMenu.
|
A login menu using EvMenu.
|
||||||
|
|
||||||
Contribution - Vincent-lg 2016
|
Contribution - Vincent-lg 2016, Griatch 2019 (rework for modern EvMenu)
|
||||||
|
|
||||||
This module contains the functions (nodes) of the EvMenu, with the
|
This changes the Evennia login to ask for the account name and password in
|
||||||
CmdSet and UnloggedCommand called when a user logs in. In other
|
sequence instead of requiring you to enter both at once.
|
||||||
words, instead of using the 'connect' or 'create' commands once on the
|
|
||||||
login screen, players navigates through a simple menu asking them to
|
|
||||||
enter their username followed by password, or to type 'new' to create
|
|
||||||
a new one. You will need to change update your login screen if you use
|
|
||||||
this system.
|
|
||||||
|
|
||||||
In order to install, to your settings file, add/edit the line:
|
To install, add this line to the settings file (`mygame/server/conf/settings.py`):
|
||||||
|
|
||||||
CMDSET_UNLOGGEDIN = "contrib.menu_login.UnloggedinCmdSet"
|
CMDSET_UNLOGGEDIN = "evennia.contrib.menu_login.UnloggedinCmdSet"
|
||||||
|
|
||||||
When you'll reload the server, new sessions will connect to the new
|
Reload the server and the new connection method will be active. Note that you must
|
||||||
login system, where they will be able to:
|
independently change the connection screen to match this login style, by editing
|
||||||
|
`mygame/server/conf/connection_screens.py`.
|
||||||
|
|
||||||
* Enter their username, assuming they have an existing account.
|
This uses Evennia's menu system EvMenu and is triggered by a command that is
|
||||||
* Enter 'NEW' to create a new account.
|
called automatically when a new user connects.
|
||||||
|
|
||||||
The top-level functions in this file are menu nodes (as described in
|
|
||||||
evennia.utils.evmenu.py). Each one of these functions is responsible
|
|
||||||
for prompting the user for a specific piece of information (username,
|
|
||||||
password and so on). At the bottom of the file is defined the CmdSet
|
|
||||||
for Unlogging users. This adds a new command that is called just after
|
|
||||||
a new session has been created, in order to create the menu. See the
|
|
||||||
specific documentation on functions (nodes) to see what each one
|
|
||||||
should do.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
|
||||||
from textwrap import dedent
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from evennia import Command, CmdSet
|
from evennia import Command, CmdSet
|
||||||
from evennia import logger
|
|
||||||
from evennia import managers
|
|
||||||
from evennia import ObjectDB
|
|
||||||
from evennia.server.models import ServerConfig
|
|
||||||
from evennia import syscmdkeys
|
from evennia import syscmdkeys
|
||||||
from evennia.utils.evmenu import EvMenu
|
from evennia.utils.evmenu import EvMenu
|
||||||
from evennia.utils.utils import random_string_from_module
|
from evennia.utils.utils import (
|
||||||
|
random_string_from_module, class_from_module, callables_from_module)
|
||||||
|
|
||||||
# Constants
|
_CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE
|
||||||
RE_VALID_USERNAME = re.compile(r"^[a-z]{3,}$", re.I)
|
_GUEST_ENABLED = settings.GUEST_ENABLED
|
||||||
LEN_PASSWD = 6
|
_ACCOUNT = class_from_module(settings.BASE_ACCOUNT_TYPECLASS)
|
||||||
CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE
|
_GUEST = class_from_module(settings.BASE_GUEST_TYPECLASS)
|
||||||
|
|
||||||
# Menu notes (top-level functions)
|
_ACCOUNT_HELP = ("Enter the name you used to log into the game before, "
|
||||||
|
"or a new account-name if you are new.")
|
||||||
|
_PASSWORD_HELP = ("Password should be a minimum of 8 characters (preferably longer) and "
|
||||||
|
"can contain a mix of letters, spaces, digits and @/./+/-/_/'/, only.")
|
||||||
|
|
||||||
|
# Menu nodes
|
||||||
|
|
||||||
|
|
||||||
def start(caller):
|
def _show_help(caller, raw_string, **kwargs):
|
||||||
"""The user should enter his/her username or NEW to create one.
|
"""Echo help message, then re-run node that triggered it"""
|
||||||
|
help_entry = kwargs['help_entry']
|
||||||
|
caller.msg(help_entry)
|
||||||
|
return None # re-run calling node
|
||||||
|
|
||||||
This node is called at the very beginning of the menu, when
|
|
||||||
a session has been created OR if an error occurs further
|
def node_enter_username(caller, raw_text, **kwargs):
|
||||||
down the menu tree. From there, users can either enter a
|
"""
|
||||||
username (if this username exists) or type NEW (capitalized
|
Start node of menu
|
||||||
or not) to create a new account.
|
Start login by displaying the connection screen and ask for a user name.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
text = random_string_from_module(CONNECTION_SCREEN_MODULE)
|
def _check_input(caller, username, **kwargs):
|
||||||
text += "\n\nEnter your username or |yNEW|n to create a new account."
|
"""
|
||||||
options = (
|
'Goto-callable', set up to be called from the _default option below.
|
||||||
{"key": "",
|
|
||||||
"goto": "start"},
|
|
||||||
{"key": "new",
|
|
||||||
"goto": "create_account"},
|
|
||||||
{"key": "quit",
|
|
||||||
"goto": "quit"},
|
|
||||||
{"key": "_default",
|
|
||||||
"goto": "username"})
|
|
||||||
return text, options
|
|
||||||
|
|
||||||
|
Called when user enters a username string. Check if this username already exists and set the flag
|
||||||
|
'new_user' if not. Will also directly login if the username is 'guest'
|
||||||
|
and GUEST_ENABLED is True.
|
||||||
|
|
||||||
def username(caller, string_input):
|
The return from this goto-callable determines which node we go to next
|
||||||
"""Check that the username leads to an existing account.
|
and what kwarg it will be called with.
|
||||||
|
|
||||||
Check that the specified username exists. If the username doesn't
|
"""
|
||||||
exist, display an error message and ask the user to try again. If
|
username = username.rstrip('\n')
|
||||||
entering an empty string, return to start node. If user exists,
|
|
||||||
move to the next node (enter password).
|
|
||||||
|
|
||||||
"""
|
if username == 'guest' and _GUEST_ENABLED:
|
||||||
string_input = string_input.strip()
|
# do an immediate guest login
|
||||||
account = managers.accounts.get_account_from_name(string_input)
|
session = caller
|
||||||
if account is None:
|
address = session.address
|
||||||
text = dedent("""
|
account, errors = _GUEST.authenticate(ip=address)
|
||||||
|rThe username '{}' doesn't exist. Have you created it?|n
|
if account:
|
||||||
Try another name or leave empty to go back.
|
return "node_quit_or_login", {"login": True, "account": account}
|
||||||
""".strip("\n")).format(string_input)
|
else:
|
||||||
options = (
|
session.msg("|R{}|n".format("\n".join(errors)))
|
||||||
{"key": "",
|
return None # re-run the username node
|
||||||
"goto": "start"},
|
|
||||||
{"key": "_default",
|
|
||||||
"goto": "username"})
|
|
||||||
else:
|
|
||||||
caller.ndb._menutree.account = account
|
|
||||||
text = "Enter the password for the {} account.".format(account.name)
|
|
||||||
# Disables echo for the password
|
|
||||||
caller.msg("", options={"echo": False})
|
|
||||||
options = (
|
|
||||||
{"key": "",
|
|
||||||
"exec": lambda caller: caller.msg("", options={"echo": True}),
|
|
||||||
"goto": "start"},
|
|
||||||
{"key": "_default",
|
|
||||||
"goto": "ask_password"})
|
|
||||||
|
|
||||||
return text, options
|
|
||||||
|
|
||||||
|
|
||||||
def ask_password(caller, string_input):
|
|
||||||
"""Ask the user to enter the password to this account.
|
|
||||||
|
|
||||||
This is assuming the user exists (see 'create_username' and
|
|
||||||
'create_password'). This node "loops" if needed: if the
|
|
||||||
user specifies a wrong password, offers the user to try
|
|
||||||
again or to go back by entering 'b'.
|
|
||||||
If the password is correct, then login.
|
|
||||||
|
|
||||||
"""
|
|
||||||
menutree = caller.ndb._menutree
|
|
||||||
string_input = string_input.strip()
|
|
||||||
|
|
||||||
# Check the password and login is correct; also check for bans
|
|
||||||
|
|
||||||
account = menutree.account
|
|
||||||
password_attempts = menutree.password_attempts \
|
|
||||||
if hasattr(menutree, "password_attempts") else 0
|
|
||||||
bans = ServerConfig.objects.conf("server_bans")
|
|
||||||
banned = bans and (any(tup[0] == account.name.lower() for tup in bans) or
|
|
||||||
any(tup[2].match(caller.address) for tup in bans if tup[2]))
|
|
||||||
|
|
||||||
if not account.check_password(string_input):
|
|
||||||
# Didn't enter a correct password
|
|
||||||
password_attempts += 1
|
|
||||||
if password_attempts > 2:
|
|
||||||
# Too many tries
|
|
||||||
caller.sessionhandler.disconnect(
|
|
||||||
caller, "|rToo many failed attempts. Disconnecting.|n")
|
|
||||||
text = ""
|
|
||||||
options = {}
|
|
||||||
else:
|
|
||||||
menutree.password_attempts = password_attempts
|
|
||||||
text = dedent("""
|
|
||||||
|rIncorrect password.|n
|
|
||||||
Try again or leave empty to go back.
|
|
||||||
""".strip("\n"))
|
|
||||||
# Loops on the same node
|
|
||||||
options = (
|
|
||||||
{"key": "",
|
|
||||||
"exec": lambda caller: caller.msg("", options={"echo": True}),
|
|
||||||
"goto": "start"},
|
|
||||||
{"key": "_default",
|
|
||||||
"goto": "ask_password"})
|
|
||||||
elif banned:
|
|
||||||
# This is a banned IP or name!
|
|
||||||
string = dedent("""
|
|
||||||
|rYou have been banned and cannot continue from here.
|
|
||||||
If you feel this ban is in error, please email an admin.|n
|
|
||||||
Disconnecting.
|
|
||||||
""".strip("\n"))
|
|
||||||
caller.sessionhandler.disconnect(caller, string)
|
|
||||||
text = ""
|
|
||||||
options = {}
|
|
||||||
else:
|
|
||||||
# We are OK, log us in.
|
|
||||||
text = ""
|
|
||||||
options = {}
|
|
||||||
caller.msg("", options={"echo": True})
|
|
||||||
caller.sessionhandler.login(caller, account)
|
|
||||||
|
|
||||||
return text, options
|
|
||||||
|
|
||||||
|
|
||||||
def create_account(caller):
|
|
||||||
"""Create a new account.
|
|
||||||
|
|
||||||
This node simply prompts the user to entere a username.
|
|
||||||
The input is redirected to 'create_username'.
|
|
||||||
|
|
||||||
"""
|
|
||||||
text = "Enter your new account name."
|
|
||||||
options = (
|
|
||||||
{"key": "_default",
|
|
||||||
"goto": "create_username"},)
|
|
||||||
return text, options
|
|
||||||
|
|
||||||
|
|
||||||
def create_username(caller, string_input):
|
|
||||||
"""Prompt to enter a valid username (one that doesnt exist).
|
|
||||||
|
|
||||||
'string_input' contains the new username. If it exists, prompt
|
|
||||||
the username to retry or go back to the login screen.
|
|
||||||
|
|
||||||
"""
|
|
||||||
menutree = caller.ndb._menutree
|
|
||||||
string_input = string_input.strip()
|
|
||||||
account = managers.accounts.get_account_from_name(string_input)
|
|
||||||
|
|
||||||
# If an account with that name exists, a new one will not be created
|
|
||||||
if account:
|
|
||||||
text = dedent("""
|
|
||||||
|rThe account {} already exists.|n
|
|
||||||
Enter another username or leave blank to go back.
|
|
||||||
""".strip("\n")).format(string_input)
|
|
||||||
# Loops on the same node
|
|
||||||
options = (
|
|
||||||
{"key": "",
|
|
||||||
"goto": "start"},
|
|
||||||
{"key": "_default",
|
|
||||||
"goto": "create_username"})
|
|
||||||
elif not RE_VALID_USERNAME.search(string_input):
|
|
||||||
text = dedent("""
|
|
||||||
|rThis username isn't valid.|n
|
|
||||||
Only letters are accepted, without special characters.
|
|
||||||
The username must be at least 3 characters long.
|
|
||||||
Enter another username or leave blank to go back.
|
|
||||||
""".strip("\n"))
|
|
||||||
options = (
|
|
||||||
{"key": "",
|
|
||||||
"goto": "start"},
|
|
||||||
{"key": "_default",
|
|
||||||
"goto": "create_username"})
|
|
||||||
else:
|
|
||||||
# a valid username - continue getting the password
|
|
||||||
menutree.accountname = string_input
|
|
||||||
# Disables echo for entering password
|
|
||||||
caller.msg("", options={"echo": False})
|
|
||||||
# Redirects to the creation of a password
|
|
||||||
text = "Enter this account's new password."
|
|
||||||
options = (
|
|
||||||
{"key": "_default",
|
|
||||||
"goto": "create_password"},)
|
|
||||||
|
|
||||||
return text, options
|
|
||||||
|
|
||||||
|
|
||||||
def create_password(caller, string_input):
|
|
||||||
"""Ask the user to create a password.
|
|
||||||
|
|
||||||
This node is at the end of the menu for account creation. If
|
|
||||||
a proper MULTI_SESSION is configured, a character is also
|
|
||||||
created with the same name (we try to login into it).
|
|
||||||
|
|
||||||
"""
|
|
||||||
menutree = caller.ndb._menutree
|
|
||||||
text = ""
|
|
||||||
options = (
|
|
||||||
{"key": "",
|
|
||||||
"exec": lambda caller: caller.msg("", options={"echo": True}),
|
|
||||||
"goto": "start"},
|
|
||||||
{"key": "_default",
|
|
||||||
"goto": "create_password"})
|
|
||||||
|
|
||||||
password = string_input.strip()
|
|
||||||
accountname = menutree.accountname
|
|
||||||
|
|
||||||
if len(password) < LEN_PASSWD:
|
|
||||||
# The password is too short
|
|
||||||
text = dedent("""
|
|
||||||
|rYour password must be at least {} characters long.|n
|
|
||||||
Enter another password or leave it empty to go back.
|
|
||||||
""".strip("\n")).format(LEN_PASSWD)
|
|
||||||
else:
|
|
||||||
# Everything's OK. Create the new player account and
|
|
||||||
# possibly the character, depending on the multisession mode
|
|
||||||
from evennia.commands.default import unloggedin
|
|
||||||
# We make use of the helper functions from the default set here.
|
|
||||||
try:
|
try:
|
||||||
permissions = settings.PERMISSION_ACCOUNT_DEFAULT
|
_ACCOUNT.objects.get(username__iexact=username)
|
||||||
typeclass = settings.BASE_CHARACTER_TYPECLASS
|
except _ACCOUNT.DoesNotExist:
|
||||||
new_account = unloggedin._create_account(caller, accountname,
|
new_user = True
|
||||||
password, permissions)
|
|
||||||
if new_account:
|
|
||||||
if settings.MULTISESSION_MODE < 2:
|
|
||||||
default_home = ObjectDB.objects.get_id(
|
|
||||||
settings.DEFAULT_HOME)
|
|
||||||
unloggedin._create_character(caller, new_account,
|
|
||||||
typeclass, default_home, permissions)
|
|
||||||
except Exception:
|
|
||||||
# We are in the middle between logged in and -not, so we have
|
|
||||||
# to handle tracebacks ourselves at this point. If we don't, we
|
|
||||||
# won't see any errors at all.
|
|
||||||
caller.msg(dedent("""
|
|
||||||
|rAn error occurred.|n Please e-mail an admin if
|
|
||||||
the problem persists. Try another password or leave
|
|
||||||
it empty to go back to the login screen.
|
|
||||||
""".strip("\n")))
|
|
||||||
logger.log_trace()
|
|
||||||
else:
|
else:
|
||||||
text = ""
|
new_user = False
|
||||||
caller.msg("|gWelcome, your new account has been created!|n")
|
|
||||||
caller.msg("", options={"echo": True})
|
|
||||||
caller.sessionhandler.login(caller, new_account)
|
|
||||||
|
|
||||||
|
# pass username/new_user into next node as kwargs
|
||||||
|
return "node_enter_password", {'new_user': new_user, 'username': username}
|
||||||
|
|
||||||
|
callables = callables_from_module(_CONNECTION_SCREEN_MODULE)
|
||||||
|
if "connection_screen" in callables:
|
||||||
|
connection_screen = callables['connection_screen']()
|
||||||
|
else:
|
||||||
|
connection_screen = random_string_from_module(_CONNECTION_SCREEN_MODULE)
|
||||||
|
|
||||||
|
if _GUEST_ENABLED:
|
||||||
|
text = "Enter a new or existing user name to login (write 'guest' for a guest login):"
|
||||||
|
else:
|
||||||
|
text = "Enter a new or existing user name to login:"
|
||||||
|
text = "{}\n\n{}".format(connection_screen, text)
|
||||||
|
|
||||||
|
options = ({"key": "",
|
||||||
|
"goto": "node_enter_username"},
|
||||||
|
{"key": ("quit", "q"),
|
||||||
|
"goto": "node_quit_or_login"},
|
||||||
|
{"key": ("help", "h"),
|
||||||
|
"goto": (_show_help, {"help_entry": _ACCOUNT_HELP, **kwargs})},
|
||||||
|
{"key": "_default",
|
||||||
|
"goto": _check_input})
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
def quit(caller):
|
def node_enter_password(caller, raw_string, **kwargs):
|
||||||
caller.sessionhandler.disconnect(caller, "Goodbye! Logging off.")
|
"""
|
||||||
|
Handle password input.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def _check_input(caller, password, **kwargs):
|
||||||
|
"""
|
||||||
|
'Goto-callable', set up to be called from the _default option below.
|
||||||
|
|
||||||
|
Called when user enters a password string. Check username + password
|
||||||
|
viability. If it passes, the account will have been created and login
|
||||||
|
will be initiated.
|
||||||
|
|
||||||
|
The return from this goto-callable determines which node we go to next
|
||||||
|
and what kwarg it will be called with.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# these flags were set by the goto-callable
|
||||||
|
username = kwargs['username']
|
||||||
|
new_user = kwargs['new_user']
|
||||||
|
password = password.rstrip('\n')
|
||||||
|
|
||||||
|
session = caller
|
||||||
|
address = session.address
|
||||||
|
if new_user:
|
||||||
|
# create a new account
|
||||||
|
account, errors = _ACCOUNT.create(username=username, password=password,
|
||||||
|
ip=address, session=session)
|
||||||
|
else:
|
||||||
|
# check password against existing account
|
||||||
|
account, errors = _ACCOUNT.authenticate(username=username, password=password,
|
||||||
|
ip=address, session=session)
|
||||||
|
|
||||||
|
if account:
|
||||||
|
if new_user:
|
||||||
|
session.msg("|gA new account |c{}|g was created. Welcome!|n".format(username))
|
||||||
|
# pass login info to login node
|
||||||
|
return "node_quit_or_login", {"login": True, "account": account}
|
||||||
|
else:
|
||||||
|
# restart due to errors
|
||||||
|
session.msg("|R{}".format("\n".join(errors)))
|
||||||
|
kwargs['retry_password'] = True
|
||||||
|
return "node_enter_password", kwargs
|
||||||
|
|
||||||
|
def _restart_login(caller, *args, **kwargs):
|
||||||
|
caller.msg("|yCancelled login.|n")
|
||||||
|
return "node_enter_username"
|
||||||
|
|
||||||
|
username = kwargs['username']
|
||||||
|
if kwargs["new_user"]:
|
||||||
|
|
||||||
|
if kwargs.get('retry_password'):
|
||||||
|
# Attempting to fix password
|
||||||
|
text = "Enter a new password:"
|
||||||
|
else:
|
||||||
|
text = ("Creating a new account |c{}|n. "
|
||||||
|
"Enter a password (empty to abort):".format(username))
|
||||||
|
else:
|
||||||
|
text = "Enter the password for account |c{}|n (empty to abort):".format(username)
|
||||||
|
options = ({"key": "",
|
||||||
|
"goto": _restart_login},
|
||||||
|
{"key": ("quit", "q"),
|
||||||
|
"goto": "node_quit_or_login"},
|
||||||
|
{"key": ("help", "h"),
|
||||||
|
"goto": (_show_help, {"help_entry": _PASSWORD_HELP, **kwargs})},
|
||||||
|
{"key": "_default",
|
||||||
|
"goto": (_check_input, kwargs)})
|
||||||
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
|
def node_quit_or_login(caller, raw_text, **kwargs):
|
||||||
|
"""
|
||||||
|
Exit menu, either by disconnecting or logging in.
|
||||||
|
|
||||||
|
"""
|
||||||
|
session = caller
|
||||||
|
if kwargs.get("login"):
|
||||||
|
account = kwargs.get("account")
|
||||||
|
session.msg("|gLogging in ...|n")
|
||||||
|
session.sessionhandler.login(session, account)
|
||||||
|
else:
|
||||||
|
session.sessionhandler.disconnect(session, "Goodbye! Logging off.")
|
||||||
return "", {}
|
return "", {}
|
||||||
|
|
||||||
# Other functions
|
|
||||||
|
|
||||||
|
# EvMenu helper function
|
||||||
|
|
||||||
def _formatter(nodetext, optionstext, caller=None):
|
def _node_formatter(nodetext, optionstext, caller=None):
|
||||||
"""Do not display the options, only the text.
|
"""Do not display the options, only the text.
|
||||||
|
|
||||||
This function is used by EvMenu to format the text of nodes.
|
This function is used by EvMenu to format the text of nodes. The menu login
|
||||||
Options are not displayed for this menu, where it doesn't often
|
is just a series of prompts so we disable all automatic display decoration
|
||||||
make much sense to do so. Thus, only the node text is displayed.
|
and let the nodes handle everything on their own.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return nodetext
|
return nodetext
|
||||||
|
|
@ -337,13 +226,17 @@ class CmdUnloggedinLook(Command):
|
||||||
An unloggedin version of the look command. This is called by the server
|
An unloggedin version of the look command. This is called by the server
|
||||||
when the account first connects. It sets up the menu before handing off
|
when the account first connects. It sets up the menu before handing off
|
||||||
to the menu's own look command.
|
to the menu's own look command.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
key = syscmdkeys.CMD_LOGINSTART
|
key = syscmdkeys.CMD_LOGINSTART
|
||||||
locks = "cmd:all()"
|
locks = "cmd:all()"
|
||||||
arg_regex = r"^$"
|
arg_regex = r"^$"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
"Execute the menu"
|
"""
|
||||||
|
Run the menu using the nodes in this module.
|
||||||
|
|
||||||
|
"""
|
||||||
EvMenu(self.caller, "evennia.contrib.menu_login",
|
EvMenu(self.caller, "evennia.contrib.menu_login",
|
||||||
startnode="start", auto_look=False, auto_quit=False,
|
startnode="node_enter_username", auto_look=False, auto_quit=False,
|
||||||
cmd_on_exit=None, node_formatter=_formatter)
|
cmd_on_exit=None, node_formatter=_node_formatter)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue