Add evennia connectsions wizard functionality

This commit is contained in:
Griatch 2019-06-27 23:07:35 +02:00
parent c9893c6e65
commit 1172067afc
7 changed files with 126 additions and 81 deletions

View file

@ -35,6 +35,13 @@
- Change webclient from old txws version to use more supported/feature-rich Autobahn websocket library
#### Evennia game index
- Made Evennia game index client a part of core - now configured from settings file (old configs
need to be moved)
- The `evennia connections` command starts a wizard that helps you connect your game to the game index.
- The game index now accepts games with no public telnet/webclient info (for early prototypes).
#### New golden-layout based Webclient UI (@friarzen)
- Features
- Much slicker behavior and more professional look

View file

@ -3,9 +3,10 @@ Link Evennia to external resources (wizard plugin for evennia_launcher)
"""
import sys
from os import path
import pprint
from django.conf import settings
from evennia.utils.utils import list_to_string
from evennia.utils.utils import list_to_string, mod_import
class ConnectionWizard(object):
@ -33,7 +34,7 @@ class ConnectionWizard(object):
"""
opt_txt = "\n".join(f" {key}: {desc}" for key, (desc, _, _) in options.items())
self.display(opt_txt)
self.display(opt_txt + "\n")
while True:
resp = input(prompt).strip()
@ -78,7 +79,7 @@ class ConnectionWizard(object):
elif resp.lower() in ("quit", "q"):
sys.exit()
def ask_choice(self, prompt="> ", options=None, default=None):
def ask_choice(self, prompt=" > ", options=None, default=None):
"""
Ask multiple-choice question, get response inline.
@ -91,7 +92,7 @@ class ConnectionWizard(object):
"""
opt_txt = "\n".join(f" {ind + 1}: {desc}" for ind, desc in enumerate(options))
self.display(opt_txt)
self.display(opt_txt + "\n")
while True:
resp = input(prompt).strip()
@ -109,13 +110,16 @@ class ConnectionWizard(object):
return selection
self.display(" Select one of the given options.")
def ask_input(self, prompt="> ", default=None, verify=True, max_len=None):
def ask_input(self, prompt=" > ", default=None, validator=None):
"""
Get arbitrary input inline.
Kwargs:
prompt (str): The display prompt.
default (str, optional): If empty input, use this.
default (str): If empty input, use this.
validator (callable): If given, the input will be passed
into this callable. It should return True unless validation
fails (and is expected to echo why if so).
Returns:
inp (str): The input given, or default.
@ -123,11 +127,19 @@ class ConnectionWizard(object):
"""
while True:
resp = input(prompt).strip()
if not resp and default:
resp = str(default)
if resp.lower() in ('q', 'quit'):
sys.exit()
if resp.lower() == 'none':
resp = ''
if validator and not validator(resp):
continue
ok = input("\n Leave blank? [Y]/N: ")
if ok.lower() in ('n', 'no'):
continue
@ -135,18 +147,15 @@ class ConnectionWizard(object):
sys.exit()
return resp
if verify:
self.display(resp)
if max_len:
nlen = len(resp)
if nlen > max_len:
self.display(f" This text is {nlen} characters long. Max is {max_len}.")
continue
ok = input("\n Is the above looking correct? [Y]/N: ")
if ok.lower() in ("n", "no"):
continue
elif ok.lower() in ('q', 'quit'):
sys.exit()
if validator and not validator(resp):
continue
self.display(resp)
ok = input("\n Is this correct? [Y]/N: ")
if ok.lower() in ("n", "no"):
continue
elif ok.lower() in ('q', 'quit'):
sys.exit()
return resp
@ -155,10 +164,12 @@ def node_start(wizard):
This wizard helps activate external networks with Evennia. It will create
a config that will be attached to the bottom of the game settings file.
Use `quit` at any time to abort and throw away any changes.
Make sure you have at least started the game once before continuing!
Use `quit` at any time to abort and throw away unsaved changes.
"""
options = {
"1": ("Add game to Evennia game index (also for closed dev games)",
"1": ("Add game to Evennia game index (also for closed-dev games)",
node_game_index_start, {}),
"2": ("Add MSSP information (for mud-list crawlers)",
node_mssp_start, {}),
@ -231,9 +242,18 @@ def node_game_index_fields(wizard, status=None):
{sdesc_default}
"""
def sdesc_validator(inp):
tmax = 255
tlen = len(inp)
if tlen > 255:
print(f"The short desc must be shorter than {tmax} characters (was {tlen}).")
wizard.ask_continue()
return False
return True
wizard.display(text)
wizard.game_index_listing['short_description'] = \
wizard.ask_input(default=sdesc_default, max_len=255)
wizard.ask_input(default=sdesc_default, validator=sdesc_validator)
# long desc
@ -265,9 +285,16 @@ def node_game_index_fields(wizard, status=None):
{listing_default}
"""
def contact_validator(inp):
if not inp or "@" not in inp:
print("This should be an email and cannot be blank.")
wizard.ask_continue()
return False
return True
wizard.display(text)
wizard.game_index_listing['listing_contact'] = \
wizard.ask_input(default=listing_default)
wizard.ask_input(default=listing_default, validator=contact_validator)
# telnet hostname
@ -359,17 +386,29 @@ def node_game_index_fields(wizard, status=None):
def node_mssp_start(wizard):
mssp_module = mod_import(settings.MSSP_META_MODULE)
filename = mssp_module.__file__
text = f"""
MSSP (Mud Server Status Protocol) allows online MUD-listing sites/crawlers
to continuously monitor your game and list information about it. Some of
this, like active player-count, Evennia will automatically add for you,
whereas many fields is info about your game.
whereas many fields are manually added info about your game.
To use MSSP you should generally have a publicly open game that external
players can connect to.
players can connect to. You also need to register at a MUD listing site to
tell them to list your game.
MSSP has a large number of configuration options and we found it was simply
a lot easier to set them in a file rather than using this wizard. So to
configure MSSP, edit the empty template listing found here:
'{filename}'
"""
wizard.mssp_table
wizard.display(text)
wizard.ask_continue()
node_start(wizard)
# Admin
@ -378,7 +417,30 @@ def _save_changes(wizard):
"""
Perform the save
"""
print("saving!")
# add import statement to settings file
import_stanza = "from .connection_settings import *"
setting_module = mod_import("server.conf.settings")
with open(setting_module.__file__, 'r+') as f:
txt = f.read() # moves pointer to end of file
if import_stanza not in txt:
# add to the end of the file
f.write("\n\n"
"try:\n"
" # Created by the `evennia connections` wizard\n"
f" {import_stanza}\n"
"except ImportError:\n"
" pass")
connect_settings_file = path.join(settings.GAME_DIR,
"server", "conf", "connection_settings.py")
with open(connect_settings_file, 'w') as f:
f.write("# This file is auto-generated by the `evennia connections` wizard.\n"
"# Don't edit manually, your changes will be overwritten.\n\n")
f.write(wizard.save_output)
wizard.display(f"saving to {connect_settings_file} ...")
def node_view_and_apply_settings(wizard):
"""
@ -393,18 +455,22 @@ def node_view_and_apply_settings(wizard):
if wizard.game_index_listing != settings.GAME_INDEX_LISTING:
game_index_txt = "No changes to save for Game Index."
else:
game_index_txt = pp.pformat(wizard.game_index_listing)
game_index_txt = ("GAME_INDEX_ENABLED = True\n"
"GAME_INDEX_LISTING = \\\n" +
pp.pformat(wizard.game_index_listing))
saves = True
text = game_index_txt
print("- Game index:\n" + text)
wizard.display(f"Settings to save:\n\n{text}")
if saves:
if wizard.ask_yesno("Do you want to save these settings?") == 'yes':
wizard.save_output = text
_save_changes(wizard)
wizard.display("... saved!")
else:
print("Cancelled. Returning ...")
wizard.display("... cancelled.")
wizard.ask_continue()
node_start(wizard)

View file

@ -50,6 +50,8 @@ def check_errors(settings):
if hasattr(settings, "ACCOUNT_TYPECLASS_PATHS"):
raise DeprecationWarning(deprstring % "ACCOUNT_TYPECLASS_PATHS")
if hasattr(settings, "CHANNEL_TYPECLASS_PATHS"):
raise DeprecationWarning(deprstring % "CHANNEL_TYPECLASS_PATHS")
if hasattr(settings, "SEARCH_MULTIMATCH_SEPARATOR"):
raise DeprecationWarning(
"settings.SEARCH_MULTIMATCH_SEPARATOR was replaced by "
"SEARCH_MULTIMATCH_REGEX and SEARCH_MULTIMATCH_TEMPLATE. "

View file

@ -66,6 +66,7 @@ class EvenniaGameIndexClient(object):
'Failed to send game details to Evennia Game Index. HTTP '
'status code was %s. Message was: %s' % (status_code, response_body)
)
if status_code == 400 and self._on_bad_request:
# Improperly formed request. Defer to the callback as far as what
# to do. Probably not a great idea to continue attempting to send

View file

@ -18,6 +18,9 @@ MSSP = b'\x46'
MSSP_VAR = b'\x01'
MSSP_VAL = b'\x02'
# try to get the customized mssp info, if it exists.
MSSPTable_CUSTOM = utils.variable_from_module(settings.MSSP_META_MODULE, "MSSPTable", default={})
class Mssp(object):
"""
@ -109,7 +112,8 @@ class Mssp(object):
}
# update the static table with the custom one
self.mssp_table.update(settings.MSSP_TABLE)
if MSSPTable_CUSTOM:
self.mssp_table.update(MSSPTable_CUSTOM)
varlist = ''
for variable, value in self.mssp_table.items():

View file

@ -39,7 +39,7 @@ class TestDeprecations(TestCase):
"CHARACTER_DEFAULT_HOME", "OBJECT_TYPECLASS_PATHS", "SCRIPT_TYPECLASS_PATHS",
"ACCOUNT_TYPECLASS_PATHS", "CHANNEL_TYPECLASS_PATHS", "SEARCH_MULTIMATCH_SEPARATOR",
"TIME_SEC_PER_MIN", "TIME_MIN_PER_HOUR", "TIME_HOUR_PER_DAY", "TIME_DAY_PER_WEEK",
"TIME_WEEK_PER_MONTH", "TIME_MONTH_PER_YEAR")
"TIME_WEEK_PER_MONTH", "TIME_MONTH_PER_YEAR", "GAME_DIRECTORY_LISTING")
def test_check_errors(self):
"""

View file

@ -25,6 +25,9 @@ import sys
# This is the name of your game. Make it catchy!
SERVERNAME = "Evennia"
# Short one-sentence blurb describing your game. Shown under the title
# on the website and could be used in online listings of your game etc.
GAME_SLOGAN = "Python MU* creation system"
# Lockdown mode will cut off the game from any external connections
# and only allow connections from localhost. Requires a cold reboot.
LOCKDOWN_MODE = False
@ -343,6 +346,9 @@ SERVER_SERVICES_PLUGIN_MODULES = ["server.conf.server_services_plugins"]
# main Evennia Portal application when the Portal is initiated.
# It will be called last in the startup sequence.
PORTAL_SERVICES_PLUGIN_MODULES = ["server.conf.portal_services_plugins"]
# Module holding MSSP meta data. This is used by MUD-crawlers to determine
# what type of game you are running, how many accounts you have etc.
MSSP_META_MODULE = "server.conf.mssp"
# Module for web plugins.
WEB_PLUGINS_MODULE = "server.conf.web_plugins"
# Tuple of modules implementing lock functions. All callable functions
@ -683,13 +689,19 @@ CHANNEL_CONNECTINFO = None
# External Connections
######################################################################
# Note: You do *not* have to make your MUD open to
# the public to use the external connections, they
# operate as long as you have an internet connection,
# just like stand-alone chat clients.
# The Evennia Game Index is a dynamic listing of Evennia games. You can add your game
# to this list also if it is in closed pre-alpha development.
GAME_INDEX_ENABLED = False
# This dict
GAME_INDEX_LISTING = {
'game_status': 'closed-dev', # closed-dev, pre-alpha, pre-alpha, alpha, beta or launched
'short_description': '',
'game_name': SERVERNAME,
'game_status': 'pre-alpha', # pre-alpha, alpha, beta or launched
'short_description': GAME_SLOGAN,
'long_description': '',
'listing_contact': '', # email
'telnet_hostname': '', # mygame.com
@ -697,57 +709,11 @@ GAME_INDEX_LISTING = {
'game_website': '', # http://mygame.com
'web_client_url': '' # http://mygame.com/webclient
}
# MSSP (Mud Server Status Protocol) is used by MUD-crawlers to determine
# what type of game you are running, how many players you have etc. Some of
# this (like server name and current number of players) is handled by Evennia
# automatically, other fields are set by you.
MSSP_TABLE = {
"HOSTNAME": "", "PORT": "", # telnet host/port
"CONTACT": "", "CREATED": "", # email, year of game creation
"IP": "", "ICON": "", # ip address; url to icon 32x32or larger; <32kb.
"LANGUAGE": "English", "LOCATION": "", # server country location, like "Sweden"
"MINIMUM AGE": "0", # set to 0 if not applicable
"WEBSITE": "www.evennia.com",
"GENRE": "None", # Adult, Fantasy, Historical, Horror, Modern, None, or Science Fiction
"GAMEPLAY": "None", # Adventure, Educational, Hack and Slash, None,
# Player versus Player, Player versus Environment,
# Roleplaying, Simulation, Social or Strategy
"STATUS": "Alpha", # Alpha, Closed Beta, Open Beta, Live
"GAMESYSTEM": "Custom", # D&D, d20 System, World of Darkness, etc. Use Custom if homebrew
"SUBGENRE": "None", # Freeform, like LASG, Medieval Fantasy, World War II, Frankenstein,
# Cyberpunk, Dragonlance, etc. Or None if not available.
# use 0 if not applicable or off
"AREAS": "0", "HELPFILES": "0", "MOBILES": "0", "OBJECTS": "0",
"ROOMS": "0", "CLASSES": "0", "LEVELS": "0", "RACES": "0", "SKILLS": "0",
"PAY TO PLAY": "0", "PAY FOR PERKS": "0",
"HIRING BUILDERS": "0", "HIRING CODERS": "0",
"DBSIZE": "0", "EXITS": "0", "EXTRA DESCRIPTIONS": "0",
"MUDPROGS": "0", "MUDTRIGS": "0", "RESETS": "0",
"ADULT MATERIAL": "0", "MULTICLASSING": "0", "NEWBIE FRIENDLY": "0", "PLAYER CITIES": "0",
"PLAYER CLANS": "0", "PLAYER CRAFTING": "0", "PLAYER GUILDS": "0",
"EQUIPMENT SYSTEM": "None", # "None", "Level", "Skill", "Both"
"MULTIPLAYING": "None", # "None", "Restricted", "Full"
"PLAYERKILLING": "None", # "None", "Restricted", "Full"
"QUEST SYSTEM": "None", # "None", "Immortal Run", "Automated", "Integrated"
"ROLEPLAYING": "None", # "None", "Accepted", "Encouraged", "Enforced"
"TRAINING SYSTEM": "None", # "None", "Level", "Skill", "Both"
"WORLD ORIGINALITY": "None", # "All Stock", "Mostly Stock", "Mostly Original", "All Original"
}
# Note: You do *not* have to make your MUD open to
# the public to use the external connections, they
# operate as long as you have an internet connection,
# just like stand-alone chat clients. IRC requires
# that you have twisted.words installed.
# Evennia can connect to external IRC channels and
# echo what is said on the channel to IRC and vice
# versa. Obs - make sure the IRC network allows bots.
# When enabled, command @irc2chan will be available in-game
# IRC requires that you have twisted.words installed.
IRC_ENABLED = False
# RSS allows to connect RSS feeds (from forum updates, blogs etc) to
# an in-game channel. The channel will be updated when the rss feed
@ -757,7 +723,6 @@ IRC_ENABLED = False
# http://code.google.com/p/feedparser/)
RSS_ENABLED = False
RSS_UPDATE_INTERVAL = 60 * 10 # 10 minutes
# Grapevine (grapevine.haus) is a network for listing MUDs as well as allow
# users of said MUDs to communicate with each other on shared channels. To use,
# your game must first be registered by logging in and creating a game entry at