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")