Merged. Still need to update some migrations.
This commit is contained in:
commit
c676c9965f
29 changed files with 821 additions and 401 deletions
|
|
@ -139,14 +139,25 @@ def get_and_merge_cmdsets(caller):
|
|||
|
||||
cmdsets = yield [caller_cmdset] + [player_cmdset] + [channel_cmdset] + local_objects_cmdsets
|
||||
# weed out all non-found sets
|
||||
cmdsets = yield [cmdset for cmdset in cmdsets if cmdset]
|
||||
cmdsets = yield [cmdset for cmdset in cmdsets if cmdset and cmdset.key!="Empty"]
|
||||
# report cmdset errors to user (these should already have been logged)
|
||||
yield [caller.msg(cmdset.message) for cmdset in cmdsets if cmdset.key == "_CMDSET_ERROR"]
|
||||
# sort cmdsets after reverse priority (highest prio are merged in last)
|
||||
yield cmdsets.sort(key=lambda x: x.priority)
|
||||
#cmdsets = yield sorted(cmdsets, key=lambda x: x.priority)
|
||||
yield [caller.msg(cmdset.errmessage) for cmdset in cmdsets if cmdset.key == "_CMDSET_ERROR"]
|
||||
|
||||
if cmdsets:
|
||||
# we group and merge all same-prio cmdsets separately (this avoids order-dependent
|
||||
# clashes in certain cases, such as when duplicates=True)
|
||||
tempmergers = {}
|
||||
for cmdset in cmdsets:
|
||||
prio = cmdset.priority
|
||||
if prio in tempmergers:
|
||||
# merge same-prio cmdset together separately
|
||||
tempmergers[prio] = yield cmdset + tempmergers[prio]
|
||||
else:
|
||||
tempmergers[prio] = cmdset
|
||||
|
||||
# sort cmdsets after reverse priority (highest prio are merged in last)
|
||||
cmdsets = yield sorted(tempmergers.values(), key=lambda x: x.priority)
|
||||
|
||||
# Merge all command sets into one, beginning with the lowest-prio one
|
||||
cmdset = cmdsets.pop(0)
|
||||
for merging_cmdset in cmdsets:
|
||||
|
|
|
|||
|
|
@ -128,9 +128,10 @@ class CmdSet(object):
|
|||
no_objs = False
|
||||
no_channels = False
|
||||
permanent = False
|
||||
errmessage = ""
|
||||
# pre-store properties to duplicate straight off
|
||||
to_duplicate = ("key", "cmdsetobj", "no_exits", "no_objs", "no_channels", "permanent",
|
||||
"mergetype", "priority", "duplicates")
|
||||
"mergetype", "priority", "duplicates", "errmessage")
|
||||
|
||||
def __init__(self, cmdsetobj=None, key=None):
|
||||
"""
|
||||
|
|
@ -152,21 +153,21 @@ class CmdSet(object):
|
|||
|
||||
# Priority-sensitive merge operations for cmdsets
|
||||
|
||||
def _union(self, cmdset_a, cmdset_b, duplicates=False):
|
||||
def _union(self, cmdset_a, cmdset_b):
|
||||
"C = A U B. CmdSet A is assumed to have higher priority"
|
||||
cmdset_c = cmdset_a._duplicate()
|
||||
# we make copies, not refs by use of [:]
|
||||
cmdset_c.commands = cmdset_a.commands[:]
|
||||
if duplicates and cmdset_a.priority == cmdset_b.priority:
|
||||
if cmdset_a.duplicates and cmdset_a.priority == cmdset_b.priority:
|
||||
cmdset_c.commands.extend(cmdset_b.commands)
|
||||
else:
|
||||
cmdset_c.commands.extend([cmd for cmd in cmdset_b if not cmd in cmdset_a])
|
||||
return cmdset_c
|
||||
|
||||
def _intersect(self, cmdset_a, cmdset_b, duplicates=False):
|
||||
def _intersect(self, cmdset_a, cmdset_b):
|
||||
"C = A (intersect) B. A is assumed higher priority"
|
||||
cmdset_c = cmdset_a._duplicate()
|
||||
if duplicates and cmdset_a.priority == cmdset_b.priority:
|
||||
if cmdset_a.duplicates and cmdset_a.priority == cmdset_b.priority:
|
||||
for cmd in [cmd for cmd in cmdset_a if cmd in cmdset_b]:
|
||||
cmdset_c.add(cmd)
|
||||
cmdset_c.add(cmdset_b.get(cmd))
|
||||
|
|
@ -174,13 +175,13 @@ class CmdSet(object):
|
|||
cmdset_c.commands = [cmd for cmd in cmdset_a if cmd in cmdset_b]
|
||||
return cmdset_c
|
||||
|
||||
def _replace(self, cmdset_a, cmdset_b, cmdset_c):
|
||||
def _replace(self, cmdset_a, cmdset_b):
|
||||
"C = A + B where the result is A."
|
||||
cmdset_c = cmdset_a._duplicate()
|
||||
cmdset_c.commands = cmdset_a.commands[:]
|
||||
return cmdset_c
|
||||
|
||||
def _remove(self, cmdset_a, cmdset_b, cmdset_c):
|
||||
def _remove(self, cmdset_a, cmdset_b):
|
||||
"C = A + B, where B is filtered by A"
|
||||
cmdset_c = cmdset_a._duplicate()
|
||||
cmdset_c.commands = [cmd for cmd in cmdset_b if not cmd in cmdset_a]
|
||||
|
|
@ -267,13 +268,13 @@ class CmdSet(object):
|
|||
|
||||
mergetype = self.key_mergetypes.get(cmdset_b.key, self.mergetype)
|
||||
if mergetype == "Intersect":
|
||||
cmdset_c = self._intersect(self, cmdset_b, cmdset_b.duplicates)
|
||||
cmdset_c = self._intersect(self, cmdset_b)
|
||||
elif mergetype == "Replace":
|
||||
cmdset_c = self._replace(self, cmdset_b, cmdset_b.duplicates)
|
||||
cmdset_c = self._replace(self, cmdset_b)
|
||||
elif mergetype == "Remove":
|
||||
cmdset_c = self._remove(self, cmdset_b, cmdset_b.duplicates)
|
||||
cmdset_c = self._remove(self, cmdset_b)
|
||||
else: # Union
|
||||
cmdset_c = self._union(self, cmdset_b, cmdset_b.duplicates)
|
||||
cmdset_c = self._union(self, cmdset_b)
|
||||
cmdset_c.no_channels = self.no_channels
|
||||
cmdset_c.no_exits = self.no_exits
|
||||
cmdset_c.no_objs = self.no_objs
|
||||
|
|
@ -286,13 +287,13 @@ class CmdSet(object):
|
|||
|
||||
mergetype = cmdset_b.key_mergetypes.get(self.key, cmdset_b.mergetype)
|
||||
if mergetype == "Intersect":
|
||||
cmdset_c = self._intersect(cmdset_b, self, self.duplicates)
|
||||
cmdset_c = self._intersect(cmdset_b, self)
|
||||
elif mergetype == "Replace":
|
||||
cmdset_c = self._replace(cmdset_b, self, self.duplicates)
|
||||
cmdset_c = self._replace(cmdset_b, self)
|
||||
elif mergetype == "Remove":
|
||||
cmdset_c = self._remove(self, cmdset_b, self.duplicates)
|
||||
cmdset_c = self._remove(self, cmdset_b)
|
||||
else: # Union
|
||||
cmdset_c = self._union(cmdset_b, self, self.duplicates)
|
||||
cmdset_c = self._union(cmdset_b, self)
|
||||
cmdset_c.no_channels = cmdset_b.no_channels
|
||||
cmdset_c.no_exits = cmdset_b.no_exits
|
||||
cmdset_c.no_objs = cmdset_b.no_objs
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ _CACHED_CMDSETS = {}
|
|||
class _ErrorCmdSet(CmdSet):
|
||||
"This is a special cmdset used to report errors"
|
||||
key = "_CMDSET_ERROR"
|
||||
message = "Error when loading cmdset."
|
||||
errmessage = "Error when loading cmdset."
|
||||
|
||||
def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False):
|
||||
"""
|
||||
|
|
@ -130,7 +130,7 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False):
|
|||
if emit_to_obj and not ServerConfig.objects.conf("server_starting_mode"):
|
||||
object.__getattribute__(emit_to_obj, "msg")(errstring)
|
||||
err_cmdset = _ErrorCmdSet()
|
||||
err_cmdset.message = errstring
|
||||
err_cmdset.errmessage = errstring
|
||||
return err_cmdset
|
||||
|
||||
# classes
|
||||
|
|
@ -283,7 +283,7 @@ class CmdSetHandler(object):
|
|||
elif isinstance(cmdset, basestring):
|
||||
# this is (maybe) a python path. Try to import from cache.
|
||||
cmdset = self._import_cmdset(cmdset)
|
||||
if cmdset:
|
||||
if cmdset and cmdset.key != '_CMDSET_ERROR':
|
||||
if permanent and cmdset.key != '_CMDSET_ERROR':
|
||||
# store the path permanently
|
||||
cmdset.permanent = True
|
||||
|
|
@ -315,7 +315,7 @@ class CmdSetHandler(object):
|
|||
elif isinstance(cmdset, basestring):
|
||||
# this is (maybe) a python path. Try to import from cache.
|
||||
cmdset = self._import_cmdset(cmdset)
|
||||
if cmdset:
|
||||
if cmdset and cmdset.key != '_CMDSET_ERROR':
|
||||
if self.cmdset_stack:
|
||||
self.cmdset_stack[0] = cmdset
|
||||
self.mergetype_stack[0] = cmdset.mergetype
|
||||
|
|
|
|||
|
|
@ -9,58 +9,72 @@ import re
|
|||
from src.locks.lockhandler import LockHandler
|
||||
from src.utils.utils import is_iter, fill
|
||||
|
||||
def _init_command(mcs, **kwargs):
|
||||
"""
|
||||
Helper command.
|
||||
Makes sure all data are stored as lowercase and
|
||||
do checking on all properties that should be in list form.
|
||||
Sets up locks to be more forgiving. This is used both by the metaclass
|
||||
and (optionally) at instantiation time.
|
||||
|
||||
If kwargs are given, these are set as instance-specific properties on the command.
|
||||
"""
|
||||
for i in range(len(kwargs)):
|
||||
# used for dynamic creation of commands
|
||||
key, value = kwargs.popitem()
|
||||
setattr(mcs, key, value)
|
||||
|
||||
mcs.key = mcs.key.lower()
|
||||
if mcs.aliases and not is_iter(mcs.aliases):
|
||||
try:
|
||||
mcs.aliases = [str(alias).strip().lower() for alias in mcs.aliases.split(',')]
|
||||
except Exception:
|
||||
mcs.aliases = []
|
||||
mcs.aliases = list(set(alias for alias in mcs.aliases if alias != mcs.key))
|
||||
|
||||
# optimization - a set is much faster to match against than a list
|
||||
mcs._matchset = set([mcs.key] + mcs.aliases)
|
||||
# optimization for looping over keys+aliases
|
||||
mcs._keyaliases = tuple(mcs._matchset)
|
||||
|
||||
# by default we don't save the command between runs
|
||||
if not hasattr(mcs, "save_for_next"):
|
||||
mcs.save_for_next = False
|
||||
|
||||
# pre-process locks as defined in class definition
|
||||
temp = []
|
||||
if hasattr(mcs, 'permissions'):
|
||||
mcs.locks = mcs.permissions
|
||||
if not hasattr(mcs, 'locks'):
|
||||
# default if one forgets to define completely
|
||||
mcs.locks = "cmd:all()"
|
||||
if not "cmd:" in mcs.locks:
|
||||
mcs.locks = "cmd:all();" + mcs.locks
|
||||
for lockstring in mcs.locks.split(';'):
|
||||
if lockstring and not ':' in lockstring:
|
||||
lockstring = "cmd:%s" % lockstring
|
||||
temp.append(lockstring)
|
||||
mcs.lock_storage = ";".join(temp)
|
||||
|
||||
if hasattr(mcs, 'arg_regex') and isinstance(mcs.arg_regex, basestring):
|
||||
mcs.arg_regex = re.compile(r"%s" % mcs.arg_regex, re.I)
|
||||
else:
|
||||
mcs.arg_regex = None
|
||||
if not hasattr(mcs, "auto_help"):
|
||||
mcs.auto_help = True
|
||||
if not hasattr(mcs, 'is_exit'):
|
||||
mcs.is_exit = False
|
||||
if not hasattr(mcs, "help_category"):
|
||||
mcs.help_category = "general"
|
||||
mcs.help_category = mcs.help_category.lower()
|
||||
|
||||
|
||||
class CommandMeta(type):
|
||||
"""
|
||||
This metaclass makes some minor on-the-fly convenience fixes to the command
|
||||
class in case the admin forgets to put things in lowercase etc.
|
||||
The metaclass cleans up all properties on the class
|
||||
"""
|
||||
def __init__(mcs, *args, **kwargs):
|
||||
"""
|
||||
Simply make sure all data are stored as lowercase and
|
||||
do checking on all properties that should be in list form.
|
||||
Sets up locks to be more forgiving.
|
||||
"""
|
||||
mcs.key = mcs.key.lower()
|
||||
if mcs.aliases and not is_iter(mcs.aliases):
|
||||
try:
|
||||
mcs.aliases = [str(alias).strip().lower() for alias in mcs.aliases.split(',')]
|
||||
except Exception:
|
||||
mcs.aliases = []
|
||||
mcs.aliases = list(set(alias for alias in mcs.aliases if alias != mcs.key))
|
||||
|
||||
# optimization - a set is much faster to match against than a list
|
||||
mcs._matchset = set([mcs.key] + mcs.aliases)
|
||||
# optimization for looping over keys+aliases
|
||||
mcs._keyaliases = tuple(mcs._matchset)
|
||||
|
||||
# by default we don't save the command between runs
|
||||
if not hasattr(mcs, "save_for_next"):
|
||||
mcs.save_for_next = False
|
||||
|
||||
# pre-process locks as defined in class definition
|
||||
temp = []
|
||||
if hasattr(mcs, 'permissions'):
|
||||
mcs.locks = mcs.permissions
|
||||
if not hasattr(mcs, 'locks'):
|
||||
# default if one forgets to define completely
|
||||
mcs.locks = "cmd:all()"
|
||||
for lockstring in mcs.locks.split(';'):
|
||||
if lockstring and not ':' in lockstring:
|
||||
lockstring = "cmd:%s" % lockstring
|
||||
temp.append(lockstring)
|
||||
mcs.lock_storage = ";".join(temp)
|
||||
|
||||
if hasattr(mcs, 'arg_regex') and isinstance(mcs.arg_regex, basestring):
|
||||
mcs.arg_regex = re.compile(r"%s" % mcs.arg_regex, re.I)
|
||||
else:
|
||||
mcs.arg_regex = None
|
||||
if not hasattr(mcs, "auto_help"):
|
||||
mcs.auto_help = True
|
||||
if not hasattr(mcs, 'is_exit'):
|
||||
mcs.is_exit = False
|
||||
if not hasattr(mcs, "help_category"):
|
||||
mcs.help_category = "general"
|
||||
mcs.help_category = mcs.help_category.lower()
|
||||
_init_command(mcs, **kwargs)
|
||||
super(CommandMeta, mcs).__init__(*args, **kwargs)
|
||||
|
||||
# The Command class is the basic unit of an Evennia command; when
|
||||
|
|
@ -125,8 +139,12 @@ class Command(object):
|
|||
# sessid - which session-id (if any) is responsible for triggering this command
|
||||
#
|
||||
|
||||
def __init__(self):
|
||||
"the lockhandler works the same as for objects."
|
||||
def __init__(self, **kwargs):
|
||||
"""the lockhandler works the same as for objects.
|
||||
optional kwargs will be set as properties on the Command at runtime,
|
||||
overloading evential same-named class properties."""
|
||||
if kwargs:
|
||||
_init_command(self, **kwargs)
|
||||
self.lockhandler = LockHandler(self)
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
|||
|
|
@ -606,9 +606,6 @@ class CmdQuell(MuxPlayerCommand):
|
|||
Hierarchical permission quelling only work downwards, thus a Player cannot
|
||||
use a higher-permission Character to escalate their permission level.
|
||||
Use the unquell command to revert back to normal operation.
|
||||
|
||||
Note that the superuser character cannot be quelled. Use a separate
|
||||
admin account for testing.
|
||||
"""
|
||||
|
||||
key = "@quell"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ Commands that are available from the connect screen.
|
|||
import re
|
||||
import traceback
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from src.players.models import PlayerDB
|
||||
from src.objects.models import ObjectDB
|
||||
from src.server.models import ServerConfig
|
||||
|
|
@ -68,7 +67,7 @@ class CmdUnconnectedConnect(MuxCommand):
|
|||
player = PlayerDB.objects.get_player_from_name(playername)
|
||||
pswd = None
|
||||
if player:
|
||||
pswd = player.user.check_password(password)
|
||||
pswd = player.check_password(password)
|
||||
|
||||
if not (player and pswd):
|
||||
# No playername or password match
|
||||
|
|
@ -142,7 +141,7 @@ class CmdUnconnectedCreate(MuxCommand):
|
|||
return
|
||||
# strip excessive spaces in playername
|
||||
playername = re.sub(r"\s+", " ", playername).strip()
|
||||
if PlayerDB.objects.filter(user__username__iexact=playername) or User.objects.filter(username__iexact=playername):
|
||||
if PlayerDB.objects.filter(username__iexact=playername):
|
||||
# player already exists (we also ignore capitalization here)
|
||||
session.msg("Sorry, there is already a player with the name '%s'." % playername)
|
||||
return
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue