Changed player.search to only search for players explicitly.

Added a MuxCommandOOC class to handle the OOC commands in a more uniform way.
Fixed the @ic/@ooc and page commands. Resolves issue 233. Resolves issue 234.
This commit is contained in:
Griatch 2012-05-17 19:42:37 +02:00
parent 96e95ca525
commit 8ad4f4a9fc
12 changed files with 253 additions and 168 deletions

View file

@ -12,7 +12,7 @@ from src.comms.models import Channel, Msg, PlayerChannelConnection, ExternalChan
from src.comms import irc, imc2, rss
from src.comms.channelhandler import CHANNELHANDLER
from src.utils import create, utils
from src.commands.default.muxcommand import MuxCommand
from src.commands.default.muxcommand import MuxCommand, MuxCommandOOC
# limit symbol import for API
__all__ = ("CommCommand", "CmdAddCom", "CmdDelCom", "CmdAllCom",
@ -624,7 +624,7 @@ class CmdCdesc(MuxCommand):
channel.save()
caller.msg("Description of channel '%s' set to '%s'." % (channel.key, self.rhs))
class CmdPage(MuxCommand):
class CmdPage(MuxCommandOOC):
"""
page - send private message
@ -647,18 +647,17 @@ class CmdPage(MuxCommand):
help_category = "Comms"
def func(self):
"Implement function using the Msg methods"
# this is a MuxCommandOOC, which means caller will be a Player.
caller = self.caller
player = caller
character = self.character
# get the messages we've sent
messages_we_sent = list(Msg.objects.get_messages_by_sender(player))
pages_we_sent = [msg for msg in messages_we_sent
if msg.receivers]
messages_we_sent = list(Msg.objects.get_messages_by_sender(caller))
pages_we_sent = [msg for msg in messages_we_sent if msg.receivers]
# get last messages we've got
pages_we_got = list(Msg.objects.get_messages_by_receiver(player))
pages_we_got = list(Msg.objects.get_messages_by_receiver(caller))
if 'last' in self.switches:
if pages_we_sent:
@ -718,9 +717,7 @@ class CmdPage(MuxCommand):
recobjs = []
for receiver in set(receivers):
if isinstance(receiver, basestring):
pobj = caller.search("*%s" % (receiver.lstrip('*')), global_search=True)
if not pobj:
return
pobj = caller.search(receiver)
elif hasattr(receiver, 'character'):
pobj = receiver.character
else:
@ -739,7 +736,7 @@ class CmdPage(MuxCommand):
message = "%s %s" % (caller.key, message.strip(':').strip())
# create the persistent message object
msg = create.create_message(player, message,
msg = create.create_message(caller, message,
receivers=recobjs)
# tell the players they got a message.

View file

@ -5,9 +5,9 @@ now.
import time
from django.conf import settings
from src.server.sessionhandler import SESSIONS
from src.utils import utils
from src.utils import utils, search
from src.objects.models import ObjectNick as Nick
from src.commands.default.muxcommand import MuxCommand
from src.commands.default.muxcommand import MuxCommand, MuxCommandOOC
# limit symbol import for API
__all__ = ("CmdHome", "CmdLook", "CmdPassword", "CmdNick",
@ -611,7 +611,7 @@ class CmdAccess(MuxCommand):
# OOC commands
class CmdOOCLook(CmdLook):
class CmdOOCLook(MuxCommandOOC, CmdLook):
"""
ooc look
@ -633,14 +633,6 @@ class CmdOOCLook(CmdLook):
def func(self):
"implement the ooc look command"
self.character = None
if utils.inherits_from(self.caller, "src.objects.objects.Object"):
# An object of some type is calling. Convert to player.
#print self.caller, self.caller.__class__
self.character = self.caller
if hasattr(self.caller, "player"):
self.caller = self.caller.player
if not self.character:
string = "You are out-of-character (OOC). "
string += "Use {w@ic{n to get back to the game, {whelp{n for more info."
@ -649,7 +641,7 @@ class CmdOOCLook(CmdLook):
self.caller = self.character # we have to put this back for normal look to work.
super(CmdOOCLook, self).func()
class CmdIC(MuxCommand):
class CmdIC(MuxCommandOOC):
"""
Switch control to an object
@ -674,8 +666,7 @@ class CmdIC(MuxCommand):
Simple puppet method
"""
caller = self.caller
if utils.inherits_from(caller, "src.objects.objects.Object"):
caller = caller.player
old_character = self.character
new_character = None
if not self.args:
@ -685,10 +676,12 @@ class CmdIC(MuxCommand):
return
if not new_character:
# search for a matching character
new_character = caller.search(self.args, global_search=True)
if not new_character:
# the search method handles error messages etc.
return
new_character = search.objects(self.args, caller, global_search=True, single_result=True)
if new_character:
new_character = new_character[0]
else:
# the search method handles error messages etc.
return
if new_character.player:
if new_character.player == caller:
caller.msg("{RYou already are {c%s{n." % new_character.name)
@ -698,13 +691,9 @@ class CmdIC(MuxCommand):
if not new_character.access(caller, "puppet"):
caller.msg("{rYou may not become %s.{n" % new_character.name)
return
old_char = None
if caller.character:
# save the old character. We only assign this to last_puppet if swap is successful.
old_char = caller.character
if caller.swap_character(new_character):
new_character.msg("\n{gYou become {c%s{n.\n" % new_character.name)
caller.db.last_puppet = old_char
caller.db.last_puppet = old_character
if not new_character.location:
# this might be due to being hidden away at logout; check
loc = new_character.db.prelogout_location
@ -718,7 +707,7 @@ class CmdIC(MuxCommand):
else:
caller.msg("{rYou cannot become {C%s{n." % new_character.name)
class CmdOOC(MuxCommand):
class CmdOOC(MuxCommandOOC):
"""
@ooc - go ooc

View file

@ -1,5 +1,6 @@
"""
The command template for the default MUX-style command set
The command template for the default MUX-style command set. There
is also an OOC version that makes sure caller is a Player object.
"""
from src.utils import utils
@ -11,7 +12,7 @@ __all__ = ("MuxCommand",)
class MuxCommand(Command):
"""
This sets up the basis for a MUX command. The idea
is that most other Mux-related commands should just
is tkhat most other Mux-related commands should just
inherit from this and don't have to implement much
parsing of their own unless they do something particularly
advanced.
@ -161,3 +162,33 @@ class MuxCommand(Command):
string += "rhs, comma separated (self.rhslist): {w%s{n\n" % self.rhslist
string += "-" * 50
self.caller.msg(string)
class MuxCommandOOC(MuxCommand):
"""
This is an OOC version of the MuxCommand. Since OOC commands sit
on Players rather than on Characters/Objects, we need to check
this in the parser.
OOC commands are strictly speaking also available when IC, it's
just that they are applied with a lower priority and are always
available, also when disconnected from a character (i.e. "ooc").
This class makes sure that caller is always a Player object, while
creating a new property "character" that is set only if a
character is actually attached to the Player.
"""
def parse(self):
"""
We run the parent parser as usual, then fix the result
"""
super(MuxCommandOOC, self).parse()
if utils.inherits_from(self.caller, "src.objects.objects.Object"):
# caller is an Object/Character
self.character = self.caller
self.caller = self.caller.player
elif hasattr(self.caller, "character"):
# caller was already a Player
self.character = self.caller.character
else:
self.character = None

View file

@ -33,10 +33,11 @@ from src.objects.models import ObjectDB
# ------------------------------------------------------------
# print all feedback from test commands (can become very verbose!)
VERBOSE = False
VERBOSE = True
NOMANGLE = True # mangle command input for extra testing
def cleanup():
print "cleaning test database ..."
User.objects.all().delete()
PlayerDB.objects.all().delete()
ObjectDB.objects.all().delete()
@ -45,6 +46,7 @@ def cleanup():
PlayerChannelConnection.objects.all().delete()
ExternalChannelConnection.objects.all().delete()
ServerConfig.objects.all().delete()
cleanup()
class FakeSessionHandler(sessionhandler.ServerSessionHandler):
"""
@ -82,6 +84,7 @@ class FakeSession(serversession.ServerSession):
def lineReceived(self, raw_string):
pass
def msg(self, message, data=None):
global VERBOSE
if message.startswith("Traceback (most recent call last):"):
#retval = "Traceback last line: %s" % message.split('\n')[-4:]
raise AssertionError(message)
@ -103,6 +106,7 @@ class FakeSession(serversession.ServerSession):
raise AssertionError(retval)
if VERBOSE:
print message
# setting up objects
class CommandTest(TestCase):
"""
@ -111,53 +115,77 @@ class CommandTest(TestCase):
Inherit new tests from this.
"""
NOMANGLE = True # mangle command input for extra testing
print "creating command testing objects ..."
ROOM1 = create.create_object(settings.BASE_ROOM_TYPECLASS, key="room1")
ROOM2 = create.create_object(settings.BASE_ROOM_TYPECLASS, key="room2")
# create a faux player/character for testing.
CHAR1 = create.create_player("TestChar", "testplayer@test.com", "testpassword", character_location=ROOM1)
CHAR1.player.user.is_superuser = True
CHAR1.lock_storage = ""
CHAR1.locks = LockHandler(CHAR1)
CHAR1.ndb.return_string = None
sess = FakeSession()
sess.connectionMade()
sess.session_login(CHAR1.player)
# create second player
CHAR2 = create.create_player("TestChar2", "testplayer2@test.com", "testpassword2", character_location=ROOM1)
CHAR2.player.user.is_superuser = False
CHAR2.lock_storage = ""
CHAR2.locks = LockHandler(CHAR2)
CHAR2.ndb.return_string = None
sess2 = FakeSession()
sess2.connectionMade()
sess2.session_login(CHAR2.player)
# A non-player-controlled character
CHAR3 = create.create_object(settings.BASE_CHARACTER_TYPECLASS, key="TestChar3", location=ROOM1)
# create some objects
OBJ1 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj1", location=ROOM1)
OBJ2 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj2", location=ROOM1)
EXIT1 = create.create_object(settings.BASE_EXIT_TYPECLASS, key="exit1", location=ROOM1)
EXIT2 = create.create_object(settings.BASE_EXIT_TYPECLASS, key="exit2", location=ROOM2)
def setUp(self):
"sets up the testing environment"
#ServerConfig.objects.conf("default_home", 2)
self.addCleanup(cleanup)
self.room1 = self.ROOM1
self.room2 = self.ROOM2
self.char1 = self.CHAR1
self.char2 = self.CHAR2
self.char3 = self.CHAR3
self.obj1 = self.OBJ1
self.obj2 = self.OBJ2
self.exit1 = self.EXIT1
self.exit2 = self.EXIT2
self.room1 = create.create_object(settings.BASE_ROOM_TYPECLASS, key="room1")
self.room2 = create.create_object(settings.BASE_ROOM_TYPECLASS, key="room2")
# create a faux player/character for testing.
self.char1 = create.create_player("TestChar", "testplayer@test.com", "testpassword", character_location=self.room1)
self.char1.player.user.is_superuser = True
self.char1.lock_storage = ""
self.char1.locks = LockHandler(self.char1)
self.char1.ndb.return_string = None
sess = FakeSession()
sess.connectionMade()
sess.session_login(self.char1.player)
# create second player
self.char2 = create.create_player("TestChar2", "testplayer2@test.com", "testpassword2", character_location=self.room1)
self.char2.player.user.is_superuser = False
self.char2.lock_storage = ""
self.char2.locks = LockHandler(self.char2)
self.char2.ndb.return_string = None
sess2 = FakeSession()
sess2.connectionMade()
sess2.session_login(self.char2.player)
# A non-player-controlled character
self.char3 = create.create_object(settings.BASE_CHARACTER_TYPECLASS, key="TestChar3", location=self.room1)
# create some objects
self.obj1 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj1", location=self.room1)
self.obj2 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj2", location=self.room1)
self.exit1 = create.create_object(settings.BASE_EXIT_TYPECLASS, key="exit1", location=self.room1)
self.exit2 = create.create_object(settings.BASE_EXIT_TYPECLASS, key="exit2", location=self.room2)
def tearDown(self):
"Cleans up testing environment after test has run."
User.objects.all().delete()
PlayerDB.objects.all().delete()
ObjectDB.objects.all().delete()
Channel.objects.all().delete()
Msg.objects.all().delete()
PlayerChannelConnection.objects.all().delete()
ExternalChannelConnection.objects.all().delete()
ServerConfig.objects.all().delete()
#self.addCleanup(cleanup)
#self.room1 = create.create_object(settings.BASE_ROOM_TYPECLASS, key="room1")
#self.room2 = create.create_object(settings.BASE_ROOM_TYPECLASS, key="room2")
## create a faux player/character for testing.
#self.char1 = create.create_player("TestChar", "testplayer@test.com", "testpassword", character_location=self.room1)
#self.char1.player.user.is_superuser = True
#self.char1.lock_storage = ""
#self.char1.locks = LockHandler(self.char1)
#self.char1.ndb.return_string = None
#sess = FakeSession()
#sess.connectionMade()
#sess.session_login(self.char1.player)
## create second player
#self.char2 = create.create_player("TestChar2", "testplayer2@test.com", "testpassword2", character_location=self.room1)
#self.char2.player.user.is_superuser = False
#self.char2.lock_storage = ""
#self.char2.locks = LockHandler(self.char2)
#self.char2.ndb.return_string = None
#sess2 = FakeSession()
#sess2.connectionMade()
#sess2.session_login(self.char2.player)
## A non-player-controlled character
#self.char3 = create.create_object(settings.BASE_CHARACTER_TYPECLASS, key="TestChar3", location=self.room1)
## create some objects
#self.obj1 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj1", location=self.room1)
#self.obj2 = create.create_object(settings.BASE_OBJECT_TYPECLASS, key="obj2", location=self.room1)
#self.exit1 = create.create_object(settings.BASE_EXIT_TYPECLASS, key="exit1", location=self.room1)
#self.exit2 = create.create_object(settings.BASE_EXIT_TYPECLASS, key="exit2", location=self.room2)
def get_cmd(self, cmd_class, argument_string=""):
"""
@ -178,7 +206,7 @@ class CommandTest(TestCase):
This also mangles the input in various ways to test if the command
will be fooled.
"""
if not nomangle and not VERBOSE and not self.NOMANGLE:
if not nomangle and not VERBOSE and not NOMANGLE:
# only mangle if not VERBOSE, to make fewer return lines
test1 = re.sub(r'\s', '', raw_string) # remove all whitespace inside it
test2 = "%s/åäö öäö;-:$£@*~^' 'test" % raw_string # inserting weird characters in call
@ -202,7 +230,6 @@ class BuildTest(CommandTest):
NOMANGLE = True
#------------------------------------------------------------
# Default set Command testing
#------------------------------------------------------------
@ -352,7 +379,7 @@ class TestSet(BuildTest):
class TestCpAttr(BuildTest):
def test_call(self):
self.execute_cmd("@set obj1/test = value")
self.execute_cmd("@set me/test2 = value2")
self.execute_cmd("@set obj2/test2 = value2")
self.execute_cmd("@cpattr obj1/test = obj2/test")
self.execute_cmd("@cpattr test2 = obj2")
self.assertEqual(self.obj2.db.test, u"value")
@ -408,7 +435,7 @@ class TestCmdSets(BuildTest):
def test_call(self):
self.execute_cmd("@cmdsets")
self.execute_cmd("@cmdsets obj1")
class TestDesc(BuildTest):
class TestName(BuildTest):
def test_call(self):
self.execute_cmd("@name obj1 = Test object", "Object's name changed to 'Test object'.")
self.assertEqual(self.obj1.key, u"Test object")

View file

@ -203,7 +203,7 @@ class ObjectManager(TypedObjectManager):
@returns_typeclass_list
def object_search(self, ostring, caller=None,
global_search=False,
attribute_name=None, location=None):
attribute_name=None, location=None, single_result=False):
"""
Search as an object and return results. The result is always an Object.
If * is appended (player search, a Character controlled by this Player
@ -313,7 +313,7 @@ class ObjectManager(TypedObjectManager):
matches = [matches[match_number]]
except IndexError:
pass
# This is always a list.
# We always have a (possibly empty) list at this point.
return matches
#

View file

@ -28,7 +28,7 @@ from src.commands.cmdsethandler import CmdSetHandler
from src.commands import cmdhandler
from src.scripts.scripthandler import ScriptHandler
from src.utils import logger
from src.utils.utils import make_iter, to_unicode, variable_from_module
from src.utils.utils import make_iter, to_unicode, variable_from_module, inherits_from
#__all__ = ("ObjAttribute", "Alias", "ObjectNick", "ObjectDB")
@ -245,7 +245,7 @@ class ObjectDB(TypedObject):
#@player.setter
def __player_set(self, player):
"Setter. Allows for self.player = value"
if isinstance(player, TypeClass):
if inherits_from(player, TypeClass):
player = player.dbobj
_set_cache(self, "player", player)
#@player.deleter

View file

@ -4,7 +4,6 @@ The managers for the custom Player object and permissions.
import datetime
from functools import update_wrapper
from django.db import models
from django.contrib.auth.models import User
from src.typeclasses.managers import returns_typeclass_list, returns_typeclass, TypedObjectManager
from src.utils import logger
@ -181,6 +180,7 @@ class PlayerManager(TypedObjectManager):
return matches
return self.filter(user__username__iexact=ostring)
def swap_character(self, player, new_character, delete_old_character=False):
"""
This disconnects a player from the current character (if any) and connects
@ -201,9 +201,10 @@ class PlayerManager(TypedObjectManager):
new_character.player = player
except Exception:
# recover old setup
old_character.player = player
player.character = old_character
if old_character:
old_character.player = player
player.character = old_character
return False
if delete_old_character:
if old_character and delete_old_character:
old_character.delete()
return True

View file

@ -50,9 +50,11 @@ from src.typeclasses.models import _get_cache, _set_cache, _del_cache
from src.server.sessionhandler import SESSIONS
from src.players import manager
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
from src.utils import logger, utils
from src.typeclasses.typeclass import TypeClass
from src.commands.cmdsethandler import CmdSetHandler
from src.commands import cmdhandler
from src.utils import logger, utils
from src.utils.utils import inherits_from
__all__ = ("PlayerAttribute", "PlayerNick", "PlayerDB")
@ -217,9 +219,11 @@ class PlayerDB(TypedObject):
"Getter. Allows for value = self.character"
return _get_cache(self, "obj")
#@character.setter
def character_set(self, value):
def character_set(self, character):
"Setter. Allows for self.character = value"
_set_cache(self, "obj", value)
if inherits_from(character, TypeClass):
character = character.dbobj
_set_cache(self, "obj", character)
#@character.deleter
def character_del(self):
"Deleter. Allows for del self.character"
@ -382,25 +386,17 @@ class PlayerDB(TypedObject):
break
return cmdhandler.cmdhandler(self.typeclass, raw_string)
def search(self, ostring, global_search=False, attribute_name=None, use_nicks=False,
location=None, ignore_errors=False, player=False):
"""
A shell method mimicking the ObjectDB equivalent, for easy inclusion from
commands regardless of if the command is run by a Player or an Object.
def search(self, ostring, return_character=False):
"""
This is similar to the ObjectDB search method but will search for Players only. Errors
will be echoed, and None returned if no Player is found.
if self.character:
# run the normal search
return self.character.search(ostring, global_search=global_search, attribute_name=attribute_name,
use_nicks=use_nicks, location=location,
ignore_errors=ignore_errors, player=player)
if player:
# seach for players
matches = self.__class__.objects.player_search(ostring)
else:
# more limited player-only search. Still returns an Object.
ObjectDB = ContentType.objects.get(app_label="objects", model="objectdb").model_class()
matches = ObjectDB.objects.object_search(ostring, caller=self, global_search=global_search)
# deal with results
matches = _AT_SEARCH_RESULT(self, ostring, matches, global_search=global_search)
return_character - will try to return the character the player controls instead of
the Player object itself. If no Character exists (since Player is
OOC), None will be returned.
"""
matches = self.__class__.objects.player_search(ostring)
matches = _AT_SEARCH_RESULT(self, ostring, matches, global_search=True)
if matches and return_character and hasattr(matches, "character"):
return matches.character
return matches

View file

@ -129,16 +129,14 @@ class Player(TypeClass):
This return is not used at all by Evennia by default, but might be useful
for coders intending to implement some sort of nested command structure.
"""
self.dbobj.execute_cmd(raw_string)
return self.dbobj.execute_cmd(raw_string)
def search(self, ostring, global_search=False, attribute_name=None, use_nicks=False,
location=None, ignore_errors=False, player=False):
def search(self, ostring, return_character=False):
"""
This method mimicks object.search if self.character is set. Otherwise only
other Players can be searched with this method.
"""
self.dbobj.search(ostring, global_search=global_search, attribute_name=attribute_name, use_nicks=use_nicks,
location=location, ignore_errors=ignore_errors, player=player)
return self.dbobj.search(ostring, return_character=return_character)
def is_typeclass(self, typeclass, exact=False):
"""

View file

@ -6,11 +6,11 @@ from django.db import models, utils
import pickle
class Migration(SchemaMigration):
no_dry_run = True
no_dry_run = True
def forwards(self, orm):
try:
db.rename_table("config_configvalue", "server_serverconfig")
db.rename_table("config_configvalue", "server_serverconfig")
for conf in orm.ServerConfig.objects.all():
conf.db_value = pickle.dumps(conf.db_value)
conf.save()
@ -18,14 +18,14 @@ class Migration(SchemaMigration):
# this will happen if we start db from scratch (the config
# app will then already be gone and no data is to be transferred)
# So instead of renaming the old we instead have to manually create the new model.
# Adding model 'ServerConfig'
# Adding model 'ServerConfig'
db.create_table('server_serverconfig', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('db_key', self.gf('django.db.models.fields.CharField')(unique=True, max_length=64)),
('db_value', self.gf('django.db.models.fields.TextField')(blank=True)),
))
db.send_create_signal('server', ['ServerConfig'])
def backwards(self, orm):
raise RuntimeError("This migration cannot be reversed.")

View file

@ -15,7 +15,12 @@ from django.conf import settings
from src.utils.utils import make_iter, mod_import
from src.utils import logger
# custom functions
OOC_MODULE = mod_import(settings.OOB_FUNC_MODULE)
OOC_FUNCS = dict((key.upper(), var) for key, var in OOC_MODULE if not key.startswith('__') and callable(var))
# MSDP commands supported by Evennia
MSDP_COMMANDS = ("LIST", "REPORT", "RESET", "SEND", "UNREPORT")
# MSDP-relevant telnet cmd/opt-codes
MSDP = chr(69)
@ -99,46 +104,75 @@ class Msdp(object):
msdp_string = MSDP_VAR + cmdname + MSDP_VAL + data
return msdp_string
# MSDP commands supported by Evennia
MSDP_COMMANDS = {"LIST": "msdp_list",
"REPORT":"mspd_report",
"RESET":"mspd_reset",
"SEND":"mspd_send",
"UNREPORT":"mspd_unreport"}
def msdp_to_func(self, data):
"""
Handle a client's requested negotiation, converting
it into a function mapping.
it into a function mapping - either one of the MSDP
default functions (LIST, SEND etc) or a custom one
in OOC_FUNCS dictionary. command names are case-insensitive.
varname, var --> mapped to function varname(var)
arrayname, array --> mapped to function arrayname(*array)
tablename, table --> mapped to function tablename(**table)
Note: Combinations of args/kwargs to one function is not supported
in this implementation (it complicates the code for limited
gain - arrayname(*array) is usually as complex as anyone should
ever need to go anyway (I hope!).
This does not support receiving nested tables from the client
(and there is no real reason why it should).
"""
tables = {}
arrays = {}
variables = {}
for table in regex_table.findall(data):
tables[table[0]] = dict(regex_varval(table[1]))
tables[table[0].upper()] = dict(regex_varval(table[1]))
for array in regex_array.findall(data):
arrays[array[0]] = dict(regex_varval(array[1]))
variables = dict(regex_varval(regex_array.sub("", regex_table.sub("", data))))
ret = ""
if "LIST" in variables:
ret = self.msdp_cmd_list(variables["LIST"])
if "REPORT" in variables:
ret = self.msdp_cmd_report(*(variables["REPORT"],))
if "REPORT" in arrays:
ret = self.msdp_cmd_report(*arrays["REPORT"])
if "RESET" in variables:
ret = self.msdp_cmd_reset(*(variables["RESET"],))
if "RESET" in arrays:
ret = self.msdp_cmd_reset(*arrays["RESET"])
if "SEND" in variables:
ret = self.msdp_cmd_send((*variables["SEND"],))
if "SEND" in arrays:
ret = self.msdp_cmd_send(*arrays["SEND"])
arrays[array[0].upper()] = dict(regex_varval(array[1]))
variables = dict((key.upper(), val) for key, val in regex_varval(regex_array.sub("", regex_table.sub("", data))))
ret = ""
# default MSDP functions
if "LIST" in variables:
ret += self.func_to_msdp("LIST", self.msdp_cmd_list(variables["LIST"]))
del variables["LIST"]
if "REPORT" in variables:
ret += self.func_to_msdp("REPORT", self.msdp_cmd_report(*(variables["REPORT"],)))
del variables["REPORT"]
if "REPORT" in arrays:
ret += self.func_to_msdp("REPORT", self.msdp_cmd_report(*arrays["REPORT"]))
del arrays["REPORT"]
if "RESET" in variables:
ret += self.func_to_msdp("RESET", self.msdp_cmd_reset(*(variables["RESET"],)))
del variables["RESET"]
if "RESET" in arrays:
ret += self.func_to_msdp("RESET", self.msdp_cmd_reset(*arrays["RESET"]))
del arrays["RESET"]
if "SEND" in variables:
ret += self.func_to_msdp("SEND", self.msdp_cmd_send((*variables["SEND"],)))
del variables["SEND"]
if "SEND" in arrays:
ret += self.func_to_msdp("SEND",self.msdp_cmd_send(*arrays["SEND"]))
del arrays["SEND"]
# if there are anything left we look for a custom function
for varname, var in variables.items():
# a simple function + argument
ooc_func = OOC_FUNCS.get(varname.upper())
if ooc_func:
ret += self.func_to_msdp(varname, ooc_func(var))
for arrayname, array in arrays.items():
# we assume the array are multiple arguments to the function
ooc_func = OOC_FUNCS.get(arrayname.upper())
if ooc_func:
ret += self.func_to_msdp(arrayname, ooc_func(*array))
for tablename, table in tables.items():
# we assume tables are keyword arguments to the function
ooc_func = OOC_FUNCS.get(arrayname.upper())
if ooc_func:
ret += self.func_to_msdp(tablename, ooc_func(**table))
return ret
# MSDP Commands
# Some given MSDP (varname, value) pairs can also be treated as command + argument.
@ -150,10 +184,9 @@ class Msdp(object):
The List command allows for retrieving various info about the server/client
"""
if arg == 'COMMANDS':
return self.func_to_msdp(arg, self.MSDP_COMMANDS.keys())
return self.func_to_msdp(arg, MSDP_COMMANDS))
elif arg == 'LISTS':
return self.func_to_msdp(arg, ("COMMANDS", "LISTS",
"CONFIGURABLE_VARIABLES",
return self.func_to_msdp(arg, ("COMMANDS", "LISTS", "CONFIGURABLE_VARIABLES",
"REPORTED_VARIABLES", "SENDABLE_VARIABLES"))
elif arg == 'CONFIGURABLE_VARIABLES':
return self.func_to_msdp(arg, ("CLIENT_NAME", "CLIENT_VERSION", "PLUGIN_ID"))
@ -210,7 +243,6 @@ class Msdp(object):
return ret
# MSDP_MAP is a standard suggestions for making it easy to create generic guis.
# this maps MSDP command names to Evennia commands found in OOB_FUNC_MODULE. It
# is up to these commands to return data on proper form.

View file

@ -28,6 +28,13 @@ TELNET_ENABLED = True
TELNET_PORTS = [4000]
# Interface addresses to listen to. If 0.0.0.0, listen to all.
TELNET_INTERFACES = ['0.0.0.0']
# OOB (out-of-band) telnet communication allows Evennia to communicate
# special commands and data with enabled Telnet clients. This is used
# to create custom client interfaces over a telnet connection. To make
# full use of OOB, you need to prepare functions to handle the data
# server-side (see OOB_FUNC_MODULE). TELNET_ENABLED is required for this
# to work.
TELNET_OOB_ENABLED = False # OBS - currently not fully implemented - do not use!
# Start the evennia django+twisted webserver so you can
# browse the evennia website and the admin interface
# (Obs - further web configuration can be found below
@ -108,6 +115,7 @@ AMP_PORT = 5000
# memory. So every now and then Evennia checks the size of this cache and resets
# it if it's too big. This variable sets the maximum size (in MB).
ATTRIBUTE_CACHE_MAXSIZE = 100
# OOB (Out-of-band
######################################################################
# Evennia Database config
@ -146,7 +154,8 @@ DATABASE_PORT = ''
# Evennia pluggable modules
######################################################################
# An alternate command parser module to use
# The command parser module to use. See the default module for which
# functions it must implement.
COMMAND_PARSER = "src.commands.cmdparser.cmdparser"
# The handler that outputs errors when searching
# objects using object.search().
@ -159,29 +168,34 @@ SEARCH_AT_MULTIMATCH_INPUT = "src.commands.cmdparser.at_multimatch_input"
# This module should contain one or more variables
# with strings defining the look of the screen.
CONNECTION_SCREEN_MODULE = "src.commands.connection_screen"
# An option al module that, if existing, must hold a function
# An optional module that, if existing, must hold a function
# named at_initial_setup(). This hook method can be used to customize
# the server's initial setup sequence (the very first startup of the system).
# The check will fail quietly if module doesn't exist or fails to load.
AT_INITIAL_SETUP_HOOK_MODULE = ""
# Module holding at_server_start(), at_server_reload() and
# Module containing your custom at_server_start(), at_server_reload() and
# at_server_stop() methods. These methods will be called every time
# the server starts, reloads and resets/stops.
# the server starts, reloads and resets/stops respectively.
AT_SERVER_STARTSTOP_MODULE = ""
# Module holding server-side functions for out-of-band protocols to call.
OOB_FUNC_MODULE = ""
# Module holding MSSP meta data
# Module holding MSSP meta data. This is used by MUD-crawlers to determine
# what type of game you are running, how many players you have etc.
MSSP_META_MODULE = ""
# Module holding server-side custom functions for out-of-band protocols to call.
# Note that OOB_ENABLED must be True for this to be used.
OOB_FUNC_MODULE = "" # Not yet available in Evennia - do not use!
######################################################################
# Default command sets
######################################################################
# Note that with the exception of the unloggedin set (which is not
# stored anywhere), changing these paths will only affect NEW created
# characters, not those already in play. So if you plan to change
# this, it's recommended you do it on a pristine setup only. To
# dynamically add new commands to a running server, extend/overload
# these existing sets instead.
# stored anywhere in the databse), changing these paths will only affect NEW created
# characters/objects, not those already in play. So if you plan to change
# this, it's recommended you do it before having created a lot of objects
# (or simply reset the database after the change for simplicity). Remember
# that you should never edit things in src/. Instead copy out the examples
# in game/gamesrc/commands/examples up one level and re-point these settings
# to point to these copies instead - these you can then change as you please
# (or copy/paste from the default modules in src/ if you prefer).
# Command set used before player has logged in
CMDSET_UNLOGGEDIN = "src.commands.default.cmdset_unloggedin.UnloggedinCmdSet"