Added a new 'contrib' folder for optional code snippets not suitable for the server core. Added contrib/menusystem for implementing a multi-choice menu system. Added contrib/lineeditor - a powerful line editor with commands mimicking VI. Also added an example NPC class using the menu system to allow for a conversation. As part of creating these contributions, lots of bugs were found and fixed. A new and more powerful cmdparser was intruduced as a result - this one is much easier to understand than the old one, while being more efficient and versatile. All testsuites were updated. Also: Resolves issue 165.

This commit is contained in:
Griatch 2011-05-12 21:51:11 +00:00
parent 2c47d6a66b
commit b9c1921a0b
16 changed files with 1426 additions and 354 deletions

View file

@ -92,7 +92,7 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False):
cmdsetclass = CACHED_CMDSETS.get(wanted_cache_key, None)
errstring = ""
if not cmdsetclass:
#print "cmdset %s not in cache. Reloading." % wanted_cache_key
#print "cmdset '%s' not in cache. Reloading %s on %s." % (wanted_cache_key, python_path, cmdsetobj)
# Not in cache. Reload from disk.
modulepath, classname = python_path.rsplit('.', 1)
module = __import__(modulepath, fromlist=[True])
@ -120,8 +120,8 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False):
print errstring
logger.log_trace()
if emit_to_obj and not ServerConfig.objects.conf("server_starting_mode"):
object.__getattribute__(emit_to_obj, "msg")(errstring)
raise # have to raise, or we will not see any errors in some situations!
object.__getattribute__(emit_to_obj, "msg")(errstring)
#raise # have to raise, or we will not see any errors in some situations!
# classes
@ -201,17 +201,19 @@ class CmdSetHandler(object):
"""
if init_mode:
# reimport all permanent cmdsets
self.permanent_paths = self.obj.cmdset_storage
if self.permanent_paths:
storage = self.obj.cmdset_storage
#print "cmdset_storage:", self.obj.cmdset_storage
if storage:
self.cmdset_stack = []
for pos, path in enumerate(self.permanent_paths):
for pos, path in enumerate(storage):
if pos == 0 and not path:
self.cmdset_stack = [CmdSet(cmdsetobj=self.obj, key="Empty")]
else:
cmdset = self.import_cmdset(path)
elif path:
cmdset = self.import_cmdset(path)
if cmdset:
cmdset.permanent = True
self.cmdset_stack.append(cmdset)
# merge the stack into a new merged cmdset
new_current = None
self.mergetype_stack = []
@ -226,6 +228,7 @@ class CmdSetHandler(object):
def import_cmdset(self, cmdset_path, emit_to_obj=None):
"""
Method wrapper for import_cmdset.
load a cmdset from a module.
cmdset_path - the python path to an cmdset object.
emit_to_obj - object to send error messages to
@ -243,8 +246,7 @@ class CmdSetHandler(object):
cmdset - can be a cmdset object or the python path to
such an object.
emit_to_obj - an object to receive error messages.
permanent - create a script to automatically add the cmdset
every time the server starts/the object logins.
permanent - this cmdset will remain across a server reboot
Note: An interesting feature of this method is if you were to
send it an *already instantiated cmdset* (i.e. not a class),
@ -260,16 +262,17 @@ class CmdSetHandler(object):
cmdset = cmdset(self.obj)
elif isinstance(cmdset, basestring):
# this is (maybe) a python path. Try to import from cache.
cmdset = self.import_cmdset(cmdset)#, emit_to_obj)
cmdset = self.import_cmdset(cmdset)
if cmdset:
self.cmdset_stack.append(cmdset)
if permanent:
# store the path permanently
self.permanent_paths.append(cmdset.path)
self.obj.cmdset_storage = self.permanent_paths
cmdset.permanent = True
storage = self.obj.cmdset_storage
storage.append(cmdset.path)
self.obj.cmdset_storage = storage
else:
# store an empty entry and don't save (this makes it easy to delete).
self.permanent_paths.append("")
cmdset.permanent = False
self.cmdset_stack.append(cmdset)
self.update()
def add_default(self, cmdset, emit_to_obj=None, permanent=True):
@ -298,16 +301,15 @@ class CmdSetHandler(object):
self.mergetype_stack = [cmdset.mergetype]
if permanent:
if self.permanent_paths:
self.permanent_paths[0] = cmdset.path
cmdset.permanent = True
storage = self.obj.cmdset_storage
if storage:
storage[0] = cmdset.path
else:
self.permanent_paths = [cmdset.path]
self.obj.cmdset_storage = self.permanent_paths
storage = [cmdset.path]
self.obj.cmdset_storage = storage
else:
if self.permanent_paths:
self.permanent_paths[0] = ""
else:
self.permanent_paths = [""]
cmdset.permanent = False
self.update()
def delete(self, cmdset=None):
@ -328,34 +330,53 @@ class CmdSetHandler(object):
return
if not cmdset:
# remove the last one in the stack (except the default position)
self.cmdset_stack.pop()
self.permanent_paths.pop()
# remove the last one in the stack
cmdset = self.cmdset_stack.pop()
if cmdset.permanent:
storage = self.obj.cmdset_storage
storage.pop()
self.obj.cmdset_storage = storage
else:
# try it as a callable
if callable(cmdset) and hasattr(cmdset, 'path'):
indices = [i+1 for i, cset in enumerate(self.cmdset_stack[1:]) if cset.path == cmdset.path]
delcmdsets = [cset for cset in self.cmdset_stack[1:] if cset.path == cmdset.path]
else:
# try it as a path or key
indices = [i+1 for i, cset in enumerate(self.cmdset_stack[1:]) if cset.path == cmdset or cset.key == cmdset]
for i in indices:
del self.cmdset_stack[i]
del self.permanent_paths[i]
self.obj.cmdset_storage = self.permanent_paths
delcmdsets = [cset for cset in self.cmdset_stack[1:] if cset.path == cmdset or cset.key == cmdset]
storage = []
if any(cset.permanent for cset in delcmdsets):
# only hit database if there's need to
storage = self.obj.cmdset_storage
for cset in delcmdsets:
if cset.permanent:
try:
storage.remove(cset.path)
except ValueError:
pass
for cset in delcmdsets:
# clean the in-memory stack
try:
self.cmdset_stack.remove(cset)
except ValueError:
pass
# re-sync the cmdsethandler.
self.update()
def delete_default(self):
"This explicitly deletes the default cmdset. It's the only command that can."
if self.cmdset_stack:
cmdset = self.cmdet_stack[0]
if cmdset.permanent:
storage = self.obj.cmdset_storage
if storage:
storage[0] = ""
else:
storage = [""]
self.cmdset_storage = storage
self.cmdset_stack[0] = CmdSet(cmdsetobj=self.obj, key="Empty")
self.permanent_paths[0] = ""
else:
else:
self.cmdset_stack = [CmdSet(cmdsetobj=self.obj, key="Empty")]
self.permanent_paths = [""]
self.obj.cmdset_storage = self.permanent_paths
self.update()
def all(self):
@ -371,8 +392,10 @@ class CmdSetHandler(object):
"""
self.cmdset_stack = [self.cmdset_stack[0]]
self.mergetype_stack = [self.cmdset_stack[0].mergetype]
self.permanent_paths = [self.permanent_paths[0]]
self.obj.cmdset_storage = self.permanent_paths
storage = self.obj.cmdset_storage
if storage:
storage = storage[0]
self.obj.cmdset_storage = storage
self.update()
def all(self):