mirror of
https://github.com/evennia/evennia.git
synced 2026-03-26 09:46:32 +01:00
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:
parent
96e95ca525
commit
8ad4f4a9fc
12 changed files with 253 additions and 168 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue