Trunk: Merged griatch-branch. This implements a new reload mechanism - splitting Evennia into two processes: Server and Portal with different tasks. Also cleans and fixes several bugs in script systems as well as introduces i18n (courtesy of raydeejay).

This commit is contained in:
Griatch 2011-09-03 10:22:19 +00:00
parent 14dae44a46
commit f13e8cdf7c
50 changed files with 3175 additions and 2565 deletions

View file

@ -87,7 +87,7 @@ class CmdBoot(MuxCommand):
feedback += "\nReason given: %s" % reason
for session in boot_list:
name = session.name
name = session.uname
session.msg(feedback)
session.disconnect()
caller.msg("You booted %s." % name)

View file

@ -408,7 +408,8 @@ class CmdCreate(ObjManipCommand):
if caller.location:
obj.home = caller.location
obj.move_to(caller.location, quiet=True)
caller.msg(string)
if string:
caller.msg(string)
class CmdDebug(MuxCommand):
@ -1077,7 +1078,7 @@ class CmdOpen(ObjManipCommand):
exit_obj.destination = destination
string = "Created new Exit '%s' from %s to %s (aliases: %s)." % (exit_name,location.name,
destination.name,
exit_aliases)
", ".join([str(e) for e in exit_aliases]))
else:
string = "Error: Exit '%s' not created." % (exit_name)
# emit results
@ -1824,17 +1825,19 @@ class CmdScript(MuxCommand):
attach scripts
Usage:
@script[/switch] <obj> = <script.path or scriptkey>
@script[/switch] <obj> [= <script.path or scriptkey>]
Switches:
start - start a previously added script
stop - stop a previously added script
Attaches the given script to the object and starts it. Script path can be given
from the base location for scripts as given in settings.
If stopping/starting an already existing script, the script's key
can be given instead (if giving a path, *all* scripts with this path
on <obj> will be affected).
Attaches the given script to the object and starts it. Script path
can be given from the base location for scripts as given in
settings. If stopping/starting an already existing script, the
script's key can be given instead (if giving a path, *all* scripts
with this path on <obj> will be affected). If no script name is given,
all scripts on the object is affected (or displayed if no start/stop
switch is set).
"""
key = "@script"
@ -1847,8 +1850,8 @@ class CmdScript(MuxCommand):
caller = self.caller
if not self.rhs:
string = "Usage: @script[/switch] <obj> = <script.path or script key>"
if not self.args:
string = "Usage: @script[/switch] <obj> [= <script.path or script key>]"
caller.msg(string)
return
@ -1857,33 +1860,52 @@ class CmdScript(MuxCommand):
return
string = ""
if not self.switches:
# adding a new script, and starting it
ok = obj.scripts.add(self.rhs, autostart=True)
if not ok:
string += "\nScript %s could not be added and/or started." % self.rhs
if not self.rhs:
# no rhs means we want to operate on all scripts
scripts = obj.scripts.all()
if not scripts:
string += "No scripts defined on %s." % obj.key
elif not self.switches:
# view all scripts
from src.commands.default.system import format_script_list
string += format_script_list(scripts)
elif "start" in self.switches:
num = sum([obj.scripts.start(script.key) for script in scripts])
string += "%s scripts started on %s." % num
elif "stop" in self.switches:
for script in scripts:
string += "Stopping script %s." % script.key
script.stop()
string = string.strip()
obj.scripts.validate()
else: # rhs exists
if not self.switches:
# adding a new script, and starting it
ok = obj.scripts.add(self.rhs, autostart=True)
if not ok:
string += "\nScript %s could not be added and/or started." % self.rhs
else:
string = "Script successfully added and started."
else:
string = "Script successfully added and started."
else:
paths = [self.rhs] + ["%s.%s" % (prefix, self.rhs)
for prefix in settings.SCRIPT_TYPECLASS_PATHS]
if "stop" in self.switches:
# we are stopping an already existing script
for path in paths:
ok = obj.scripts.stop(path)
if not ok:
string += "\nScript %s could not be stopped. Does it exist?" % path
else:
string = "Script stopped and removed from object."
break
if "start" in self.switches:
# we are starting an already existing script
for path in paths:
ok = obj.scripts.start(path)
if not ok:
string += "\nScript %s could not be (re)started." % path
else:
string = "Script started successfully."
break
paths = [self.rhs] + ["%s.%s" % (prefix, self.rhs)
for prefix in settings.SCRIPT_TYPECLASS_PATHS]
if "stop" in self.switches:
# we are stopping an already existing script
for path in paths:
ok = obj.scripts.stop(path)
if not ok:
string += "\nScript %s could not be stopped. Does it exist?" % path
else:
string = "Script stopped and removed from object."
break
if "start" in self.switches:
# we are starting an already existing script
for path in paths:
ok = obj.scripts.start(path)
if not ok:
string += "\nScript %s could not be (re)started." % path
else:
string = "Script started successfully."
break
caller.msg(string.strip())

View file

@ -34,11 +34,12 @@ class DefaultCmdSet(CmdSet):
# System commands
self.add(system.CmdReload())
self.add(system.CmdReset())
self.add(system.CmdShutdown())
self.add(system.CmdPy())
self.add(system.CmdScripts())
self.add(system.CmdObjects())
self.add(system.CmdService())
self.add(system.CmdShutdown())
self.add(system.CmdVersion())
self.add(system.CmdTime())
self.add(system.CmdServerLoad())

View file

@ -13,7 +13,6 @@ from src.comms import irc, imc2
from src.comms.channelhandler import CHANNELHANDLER
from src.utils import create, utils
from src.commands.default.muxcommand import MuxCommand
from src.server.sessionhandler import SESSIONS
def find_channel(caller, channelname, silent=False, noaliases=False):
"""

View file

@ -56,7 +56,6 @@ class CmdLook(MuxCommand):
"""
caller = self.caller
args = self.args
if args:
# Use search to handle duplicate/nonexistant results.
looking_at_obj = caller.search(args, use_nicks=True)
@ -345,7 +344,7 @@ class CmdQuit(MuxCommand):
def func(self):
"hook function"
for session in self.caller.sessions:
session.msg("Quitting. Hope to see you soon again.")
session.msg("{RQuitting{n. Hope to see you soon again.")
session.session_disconnect()
class CmdWho(MuxCommand):

View file

@ -15,7 +15,7 @@ from src.scripts.models import ScriptDB
from src.objects.models import ObjectDB
from src.players.models import PlayerDB
from src.server.models import ServerConfig
from src.utils import reloads, create, logger, utils, gametime
from src.utils import create, logger, utils, gametime
from src.commands.default.muxcommand import MuxCommand
@ -26,8 +26,9 @@ class CmdReload(MuxCommand):
Usage:
@reload
This reloads the system modules and
re-validates all scripts.
This restarts the server. The Portal is not
affected. Non-persistent scripts will survive a @reload (use
@reset to purge) and at_reload() hooks will be called.
"""
key = "@reload"
locks = "cmd:perm(reload) or perm(Immortals)"
@ -37,7 +38,62 @@ class CmdReload(MuxCommand):
"""
Reload the system.
"""
reloads.start_reload_loop()
SESSIONS.announce_all(" Server restarting ...")
SESSIONS.server.shutdown(mode='reload')
class CmdReset(MuxCommand):
"""
Reset and reboot the system
Usage:
@reset
A cold reboot. This works like a mixture of @reload and @shutdown,
- all shutdown hooks will be called and non-persistent scrips will
be purged. But the Portal will not be affected and the server will
automatically restart again.
"""
key = "@reset"
aliases = ['@reboot']
locks = "cmd:perm(reload) or perm(Immortals)"
help_category = "System"
def func(self):
"""
Reload the system.
"""
SESSIONS.announce_all(" Server restarting ...")
SESSIONS.server.shutdown(mode='reset')
class CmdShutdown(MuxCommand):
"""
@shutdown
Usage:
@shutdown [announcement]
Gracefully shut down both Server and Portal.
"""
key = "@shutdown"
locks = "cmd:perm(shutdown) or perm(Immortals)"
help_category = "System"
def func(self):
"Define function"
try:
session = self.caller.sessions[0]
except Exception:
return
self.caller.msg('Shutting down server ...')
announcement = "\nServer is being SHUT DOWN!\n"
if self.args:
announcement += "%s\n" % self.args
logger.log_infomsg('Server shutdown by %s.' % self.caller.name)
SESSIONS.announce_all(announcement)
SESSIONS.portal_shutdown()
SESSIONS.server.shutdown(mode='shutdown')
class CmdPy(MuxCommand):
"""
@ -115,6 +171,58 @@ class CmdPy(MuxCommand):
except AssertionError: # this is a strange thing; the script looses its id somehow..?
pass
# helper function. Kept outside so it can be imported and run
# by other commands.
def format_script_list(scripts):
"Takes a list of scripts and formats the output."
if not scripts:
return "<No scripts>"
table = [["id"], ["obj"], ["key"], ["intval"], ["next"], ["rept"], ["db"], ["typeclass"], ["desc"]]
for script in scripts:
table[0].append(script.id)
if not hasattr(script, 'obj') or not script.obj:
table[1].append("<Global>")
else:
table[1].append(script.obj.key)
table[2].append(script.key)
if not hasattr(script, 'interval') or script.interval < 0:
table[3].append("--")
else:
table[3].append("%ss" % script.interval)
next = script.time_until_next_repeat()
if not next:
table[4].append("--")
else:
table[4].append("%ss" % next)
if not hasattr(script, 'repeats') or not script.repeats:
table[5].append("--")
else:
table[5].append("%s" % script.repeats)
if script.persistent:
table[6].append("*")
else:
table[6].append("-")
typeclass_path = script.typeclass_path.rsplit('.', 1)
table[7].append("%s" % typeclass_path[-1])
table[8].append(script.desc)
ftable = utils.format_table(table)
string = ""
for irow, row in enumerate(ftable):
if irow == 0:
srow = "\n" + "".join(row)
srow = "{w%s{n" % srow.rstrip()
else:
srow = "\n" + "{w%s{n" % row[0] + "".join(row[1:])
string += srow.rstrip()
return string.strip()
class CmdScripts(MuxCommand):
"""
Operate on scripts.
@ -137,54 +245,7 @@ class CmdScripts(MuxCommand):
aliases = "@listscripts"
locks = "cmd:perm(listscripts) or perm(Wizards)"
help_category = "System"
def format_script_list(self, scripts):
"Takes a list of scripts and formats the output."
if not scripts:
return "<No scripts>"
table = [["id"], ["obj"], ["key"], ["intval"], ["next"], ["rept"], ["db"], ["typeclass"], ["desc"]]
for script in scripts:
table[0].append(script.id)
if not hasattr(script, 'obj') or not script.obj:
table[1].append("<Global>")
else:
table[1].append(script.obj.key)
table[2].append(script.key)
if not hasattr(script, 'interval') or script.interval < 0:
table[3].append("--")
else:
table[3].append("%ss" % script.interval)
next = script.time_until_next_repeat()
if not next:
table[4].append("--")
else:
table[4].append("%ss" % next)
if not hasattr(script, 'repeats') or not script.repeats:
table[5].append("--")
else:
table[5].append("%s" % script.repeats)
if script.persistent:
table[6].append("*")
else:
table[6].append("-")
typeclass_path = script.typeclass_path.rsplit('.', 1)
table[7].append("%s" % typeclass_path[-1])
table[8].append(script.desc)
ftable = utils.format_table(table)
string = ""
for irow, row in enumerate(ftable):
if irow == 0:
srow = "\n" + "".join(row)
srow = "{w%s{n" % srow.rstrip()
else:
srow = "\n" + "{w%s{n" % row[0] + "".join(row[1:])
string += srow.rstrip()
return string.strip()
def func(self):
"implement method"
@ -232,7 +293,7 @@ class CmdScripts(MuxCommand):
else:
# multiple matches.
string = "Multiple script matches. Please refine your search:\n"
string += self.format_script_list(scripts)
string += format_script_list(scripts)
elif self.switches and self.switches[0] in ("validate", "valid", "val"):
# run validation on all found scripts
nr_started, nr_stopped = ScriptDB.objects.validate(scripts=scripts)
@ -240,7 +301,7 @@ class CmdScripts(MuxCommand):
string += "Started %s and stopped %s scripts." % (nr_started, nr_stopped)
else:
# No stopping or validation. We just want to view things.
string = self.format_script_list(scripts)
string = format_script_list(scripts)
caller.msg(string)
@ -411,34 +472,6 @@ class CmdService(MuxCommand):
caller.msg("Starting service '%s'." % self.args)
service.startService()
class CmdShutdown(MuxCommand):
"""
@shutdown
Usage:
@shutdown [announcement]
Shut the game server down gracefully.
"""
key = "@shutdown"
locks = "cmd:perm(shutdown) or perm(Immortals)"
help_category = "System"
def func(self):
"Define function"
try:
session = self.caller.sessions[0]
except Exception:
return
self.caller.msg('Shutting down server ...')
announcement = "\nServer is being SHUT DOWN!\n"
if self.args:
announcement += "%s\n" % self.args
logger.log_infomsg('Server shutdown by %s.' % self.caller.name)
SESSIONS.announce_all(announcement)
SESSIONS.server.shutdown()
class CmdVersion(MuxCommand):
"""
@version - game version

View file

@ -20,7 +20,7 @@ except ImportError:
from django.test import TestCase
from django.conf import settings
from src.utils import create, ansi
from src.server import session, sessionhandler
from src.server import serversession, sessionhandler
from src.locks.lockhandler import LockHandler
from src.server.models import ServerConfig
from src.comms.models import Channel, Msg, PlayerChannelConnection, ExternalChannelConnection
@ -46,15 +46,37 @@ def cleanup():
ExternalChannelConnection.objects.all().delete()
ServerConfig.objects.all().delete()
class FakeSession(session.Session):
class FakeSessionHandler(sessionhandler.ServerSessionHandler):
"""
Fake sessionhandler, without an amp connection
"""
def portal_shutdown(self):
pass
def disconnect(self, session, reason=""):
pass
def login(self, session):
pass
def session_sync(self):
pass
def data_out(self, session, string="", data=""):
return string
SESSIONS = FakeSessionHandler()
class FakeSession(serversession.ServerSession):
"""
A fake session that
implements dummy versions of the real thing; this is needed to
mimic a logged-in player.
"""
protocol_key = "TestProtocol"
sessdict = {'protocol_key':'telnet', 'address':('0.0.0.0','5000'), 'sessid':2, 'uid':2, 'uname':None,
'logged_in':False, 'cid':None, 'ndb':{}, 'encoding':'utf-8',
'conn_time':time.time(), 'cmd_last':time.time(), 'cmd_last_visible':time.time(), 'cmd_total':1}
def connectionMade(self):
self.session_connect('0,0,0,0')
self.load_sync_data(self.sessdict)
self.sessionhandler = SESSIONS
def disconnectClient(self):
pass
def lineReceived(self, raw_string):

View file

@ -212,7 +212,7 @@ class CmdQuit(MuxCommand):
"Simply close the connection."
session = self.caller
session.msg("Good bye! Disconnecting ...")
session.at_disconnect()
session.session_disconnect()
class CmdUnconnectedLook(MuxCommand):
"""