Re-organization of the command handler for the sake of efficiency and cleanliness.

This commit is contained in:
Greg Taylor 2006-12-03 00:40:19 +00:00
parent 703fddcb7f
commit 8352c939ff
5 changed files with 256 additions and 265 deletions

View file

@ -1,76 +1,68 @@
from commands_staff import StaffCommands import commands_staff
from commands_general import GenCommands import commands_general
from commands_unloggedin import UnLoggedInCommands import commands_unloggedin
""" """
This is the command processing module. It is instanced once in the main This is the command processing module. It is instanced once in the main
server module and the handle() function is hit every time a player sends server module and the handle() function is hit every time a player sends
something. something.
""" """
# We'll use this for our getattr() in the Handler class.
gencommands = GenCommands()
staffcommands = StaffCommands()
unloggedincommands = UnLoggedInCommands()
class UnknownCommand(Exception): class UnknownCommand(Exception):
""" """
Throw this when a user enters an an invalid command. Throw this when a user enters an an invalid command.
""" """
class Handler: def handle(cdat):
def handle(self, cdat): """
""" Use the spliced (list) uinput variable to retrieve the correct
Use the spliced (list) uinput variable to retrieve the correct command, or return an invalid command error.
command, or return an invalid command error.
We're basically grabbing the player's command by tacking We're basically grabbing the player's command by tacking
their input on to 'do_' and looking it up in the GenCommands their input on to 'do_' and looking it up in the GenCommands
class. class.
""" """
session = cdat['session'] session = cdat['session']
server = cdat['server'] server = cdat['server']
try:
# TODO: Protect against non-standard characters.
if cdat['uinput'] == '':
raise UnknownCommand
uinput = cdat['uinput'].split()
parsed_input = {}
try: # First we split the input up by spaces.
# TODO: Protect against non-standard characters. parsed_input['splitted'] = uinput
if cdat['uinput'] == '': # Now we find the root command chunk (with switches attached).
raise UnknownCommand parsed_input['root_chunk'] = parsed_input['splitted'][0].split('/')
# And now for the actual root command. It's the first entry in root_chunk.
uinput = cdat['uinput'].split() parsed_input['root_cmd'] = parsed_input['root_chunk'][0].lower()
parsed_input = {}
# Now we'll see if the user is using an alias. We do a dictionary lookup,
# First we split the input up by spaces. # if the key (the player's root command) doesn't exist on the dict, we
parsed_input['splitted'] = uinput # don't replace the existing root_cmd. If the key exists, its value
# Now we find the root command chunk (with switches attached). # replaces the previously splitted root_cmd. For example, sa -> say.
parsed_input['root_chunk'] = parsed_input['splitted'][0].split('/') alias_list = server.cmd_alias_list
# And now for the actual root command. It's the first entry in root_chunk. parsed_input['root_cmd'] = alias_list.get(parsed_input['root_cmd'],parsed_input['root_cmd'])
parsed_input['root_cmd'] = parsed_input['root_chunk'][0].lower()
# Now we'll see if the user is using an alias. We do a dictionary lookup,
# if the key (the player's root command) doesn't exist on the dict, we
# don't replace the existing root_cmd. If the key exists, its value
# replaces the previously splitted root_cmd. For example, sa -> say.
alias_list = server.cmd_alias_list
parsed_input['root_cmd'] = alias_list.get(parsed_input['root_cmd'],parsed_input['root_cmd'])
if session.logged_in: if session.logged_in:
# If it's prefixed by an '@', it's a staff command. # If it's prefixed by an '@', it's a staff command.
if parsed_input['root_cmd'][0] != '@': if parsed_input['root_cmd'][0] != '@':
cmdtable = gencommands cmd = getattr(commands_general, 'do_%s' % (parsed_input['root_cmd'],), None )
else:
parsed_input['root_cmd'] = parsed_input['root_cmd'][1:]
cmdtable = staffcommands
else: else:
cmdtable = unloggedincommands parsed_input['root_cmd'] = parsed_input['root_cmd'][1:]
cmd = getattr(commands_staff, 'do_%s' % (parsed_input['root_cmd'],), None )
# cmdtable now equals the command table we need to use. Do a command else:
# lookup for a particular function based on the user's input. cmd = getattr(commands_unloggedin, 'do_%s' % (parsed_input['root_cmd'],), None )
cmd = getattr(cmdtable, 'do_%s' % (parsed_input['root_cmd'],), None )
if callable(cmd):
cdat['uinput'] = parsed_input
cmd(cdat)
else:
raise UnknownCommand
except UnknownCommand:
session.msg("Unknown command.")
if callable(cmd):
cdat['uinput'] = parsed_input
cmd(cdat)
else:
raise UnknownCommand
except UnknownCommand:
session.msg("Unknown command.")

View file

@ -1,72 +1,72 @@
import settings import settings
from ansi import * from ansi import *
class GenCommands: """
Generic command module. Pretty much every command should go here for
now.
"""
def do_look(cdat):
""" """
Generic command class. Pretty much every command should go here for Handle looking at objects.
now. """
""" session = cdat['session']
def do_look(self, cdat): server = cdat['server']
""" player_loc = session.player_loc
Handle looking at objects. player_loc_obj = server.object_list[player_loc]
"""
session = cdat['session']
server = cdat['server']
player_loc = session.player_loc
player_loc_obj = server.object_list[player_loc]
retval = "%s%s%s%s\n\r%s" % (
ansi["normal"],
ansi["hilite"],
player_loc_obj.name,
ansi["normal"],
player_loc_obj.description,
)
session.msg(retval)
def do_quit(self, cdat):
"""
Gracefully disconnect the user as per his own request.
"""
session = cdat['session']
session.msg("Quitting!")
session.handle_close()
def do_who(self, cdat):
"""
Generic WHO command.
"""
session_list = cdat['server'].session_list
session = cdat['session']
retval = "Player Name\n\r"
for player in session_list:
retval += '%s\n\r' % (player,)
retval += '%d Players logged in.' % (len(session_list),)
session.msg(retval)
def do_say(self, cdat): retval = "%s%s%s%s\n\r%s" % (
""" ansi["normal"],
Room-based speech command. ansi["hilite"],
""" player_loc_obj.name,
session_list = cdat['server'].session_list ansi["normal"],
session = cdat['session'] player_loc_obj.description,
speech = cdat['uinput']['splitted'][1:] )
players_present = [player for player in session_list if player.player_loc == session.player_loc and player != session] session.msg(retval)
retval = "You say, '%s'" % (''.join(speech),) def do_quit(cdat):
for player in players_present: """
player.msg("%s says, '%s'" % (session.name, speech,)) Gracefully disconnect the user as per his own request.
"""
session.msg(retval) session = cdat['session']
session.msg("Quitting!")
def do_version(self, cdat): session.handle_close()
"""
Version info command. def do_who(cdat):
""" """
session = cdat['session'] Generic WHO command.
retval = "-"*50 +"\n\r" """
retval += "Evennia %s\n\r" % (settings.EVENNIA_VERSION,) session_list = cdat['server'].session_list
retval += "-"*50 session = cdat['session']
session.msg(retval)
retval = "Player Name\n\r"
for player in session_list:
retval += '%s\n\r' % (player,)
retval += '%d Players logged in.' % (len(session_list),)
session.msg(retval)
def do_say(cdat):
"""
Room-based speech command.
"""
session_list = cdat['server'].session_list
session = cdat['session']
speech = cdat['uinput']['splitted'][1:]
players_present = [player for player in session_list if player.player_loc == session.player_loc and player != session]
retval = "You say, '%s'" % (''.join(speech),)
for player in players_present:
player.msg("%s says, '%s'" % (session.name, speech,))
session.msg(retval)
def do_version(cdat):
"""
Version info command.
"""
session = cdat['session']
retval = "-"*50 +"\n\r"
retval += "Evennia %s\n\r" % (settings.EVENNIA_VERSION,)
retval += "-"*50
session.msg(retval)

View file

@ -1,95 +1,96 @@
from apps.objects.models import Object from apps.objects.models import Object
import functions_db import functions_db
import commands_general
class StaffCommands: """
Restricted staff commands.
"""
def do_dig(cdat):
""" """
Restricted staff commands. Digs a new room out.
""" """
def do_dig(self, cdat): session = cdat['session']
""" uinput= cdat['uinput']
Digs a new room out. roomname = ''.join(uinput[1:])
"""
session = cdat['session'] if roomname == '':
uinput= cdat['uinput'] session.msg("You must supply a room name!")
roomname = ''.join(uinput[1:]) else:
newroom = Object()
newroom.name = roomname
newroom.type = "Room"
if roomname == '': def do_nextfree(cdat):
session.msg("You must supply a room name!") """
Returns the next free object number.
"""
session = cdat['session']
server = cdat['server']
nextfree = server.get_nextfree_dbnum()
retval = "Next free object number: %s" % (nextfree,)
session.msg(retval)
def do_teleport(cdat):
"""
Teleports an object somewhere.
"""
session = cdat['session']
pobject = session.pobject
server = cdat['server']
args = cdat['uinput']['splitted'][1:]
if len(args) == 0:
session.msg("Teleport where/what?")
return
eq_args = args[0].split('=')
# If we have more than one entry in our '=' delimited argument list,
# then we're doing a @tel <victim>=<location>. If not, we're doing
# a direct teleport, @tel <destination>.
if len(eq_args) > 1:
session.msg("Equal sign present.")
else:
session.msg("No equal sign, direct tport.")
results = functions_db.local_and_global_search(pobject, ''.join(args))
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s(#%s)" % (result.name, result.id,))
elif len(results) == 0:
session.msg("I don't see that here.")
else: else:
newroom = Object() session.msg("Teleported.")
newroom.name = roomname pobject.move_to(results[0])
newroom.type = "Room" commands_general.do_look(cdat)
def do_nextfree(self, cdat): #session.msg("Args: %s\n\rEqargs: %s" % (args, eq_args,))
"""
Returns the next free object number. def do_find(cdat):
""" """
session = cdat['session'] Searches for an object of a particular name.
server = cdat['server'] """
session = cdat['session']
nextfree = server.get_nextfree_dbnum() server = cdat['server']
retval = "Next free object number: %s" % (nextfree,) searchstring = ''.join(cdat['uinput']['splitted'][1:])
session.msg(retval) if searchstring == '':
session.msg("No search pattern given.")
def do_teleport(self, cdat): return
"""
Teleports an object somewhere. memory_based = True
"""
session = cdat['session'] if memory_based:
pobject = session.pobject results = functions_db.list_search_object_namestr(server.object_list.values(), searchstring)
server = cdat['server']
args = cdat['uinput']['splitted'][1:] if len(results) > 0:
session.msg("Name matches for: %s" % (searchstring,))
if len(args) == 0: for result in results:
session.msg("Teleport where/what?") session.msg(" %s(#%s)" % (result.name, result.id,))
return session.msg("%d matches returned." % (len(results),))
eq_args = args[0].split('=')
# If we have more than one entry in our '=' delimited argument list,
# then we're doing a @tel <victim>=<location>. If not, we're doing
# a direct teleport, @tel <destination>.
if len(eq_args) > 1:
session.msg("Equal sign present.")
else: else:
session.msg("No equal sign, direct tport.") session.msg("No name matches found for: %s" % (searchstring,))
results = functions_db.local_and_global_search(pobject, ''.join(args))
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
for result in results:
session.msg(" %s(#%s)" % (result.name, result.id,))
elif len(results) == 0:
session.msg("I don't see that here.")
else:
session.msg("Teleported.")
pobject.move_to(results[0])
#GenCommands.do_look(cdat)
#session.msg("Args: %s\n\rEqargs: %s" % (args, eq_args,))
def do_find(self, cdat):
"""
Searches for an object of a particular name.
"""
session = cdat['session']
server = cdat['server']
searchstring = ''.join(cdat['uinput']['splitted'][1:])
if searchstring == '':
session.msg("No search pattern given.")
return
memory_based = True
if memory_based:
results = functions_db.list_search_object_namestr(server.object_list.values(), searchstring)
if len(results) > 0:
session.msg("Name matches for: %s" % (searchstring,))
for result in results:
session.msg(" %s(#%s)" % (result.name, result.id,))
session.msg("%d matches returned." % (len(results),))
else:
session.msg("No name matches found for: %s" % (searchstring,))

View file

@ -1,54 +1,54 @@
from django.contrib.auth.models import User from django.contrib.auth.models import User
class UnLoggedInCommands: """
Commands that are available from the connect screen.
"""
def do_connect(cdat):
""" """
Commands that are available from the connect screen. This is the connect command at the connection screen. Fairly simple,
uses the Django database API and User model to make it extremely simple.
""" """
def do_connect(self, cdat): session = cdat['session']
""" uname = cdat['uinput']['splitted'][1]
This is the connect command at the connection screen. Fairly simple, password = cdat['uinput']['splitted'][2]
uses the Django database API and User model to make it extremely simple.
""" account = User.objects.filter(username=uname)
session = cdat['session'] user = account[0]
uname = cdat['uinput']['splitted'][1]
password = cdat['uinput']['splitted'][2] autherror = "Invalid username or password!"
if account.count() == 0:
session.msg(autherror)
if not user.check_password(password):
session.msg(autherror)
else:
uname = user.username
session.login(user)
account = User.objects.filter(username=uname) def do_create(cdat):
user = account[0] """
Handle the creation of new accounts.
"""
session = cdat['session']
server = cdat['server']
uname = cdat['uinput']['splitted'][1]
email = cdat['uinput']['splitted'][2]
password = cdat['uinput']['splitted'][3]
account = User.objects.filter(username=uname)
if not account.count() == 0:
session.msg("There is already a player with that name!")
elif len(password) < 3:
session.msg("Your password must be 3 characters or longer.")
else:
server.create_user(session, uname, email, password)
autherror = "Invalid username or password!" def do_quit(cdat):
if account.count() == 0: """
session.msg(autherror) We're going to maintain a different version of the quit command
if not user.check_password(password): here for unconnected users for the sake of simplicity. The logged in
session.msg(autherror) version will be a bit more complicated.
else: """
uname = user.username session = cdat['session']
session.login(user) session.msg("Disconnecting...")
session.handle_close()
def do_create(self, cdat):
"""
Handle the creation of new accounts.
"""
session = cdat['session']
server = cdat['server']
uname = cdat['uinput']['splitted'][1]
email = cdat['uinput']['splitted'][2]
password = cdat['uinput']['splitted'][3]
account = User.objects.filter(username=uname)
if not account.count() == 0:
session.msg("There is already a player with that name!")
elif len(password) < 3:
session.msg("Your password must be 3 characters or longer.")
else:
server.create_user(session, uname, email, password)
def do_quit(self, cdat):
"""
We're going to maintain a different version of the quit command
here for unconnected users for the sake of simplicity. The logged in
version will be a bit more complicated.
"""
session = cdat['session']
session.msg("Disconnecting...")
session.handle_close()

View file

@ -1,12 +1,10 @@
from asyncore import dispatcher from asyncore import dispatcher
from asynchat import async_chat from asynchat import async_chat
import socket, asyncore, time, sys import socket, asyncore, time, sys
from cmdhandler import * import cmdhandler
from apps.objects.models import Object from apps.objects.models import Object
from django.contrib.auth.models import User from django.contrib.auth.models import User
chandler = Handler()
class PlayerSession(async_chat): class PlayerSession(async_chat):
""" """
This class represents a player's sesssion. From here we branch down into This class represents a player's sesssion. From here we branch down into
@ -53,7 +51,7 @@ class PlayerSession(async_chat):
self.cmd_last = time.time() self.cmd_last = time.time()
# Stuff anything we need to pass in this dictionary. # Stuff anything we need to pass in this dictionary.
cdat = {"server": self.server, "uinput": uinput, "session": self} cdat = {"server": self.server, "uinput": uinput, "session": self}
chandler.handle(cdat) cmdhandler.handle(cdat)
def handle_close(self): def handle_close(self):
""" """