Implemented locks.
The main command to use is @lock, which accept three types of locks at the moment, and three types of keys: Locks: DefaultLock, UseLock, EnterLock Keys: ObjectIDs, Groups, Permissions This offers the most useful functionality - stopping people from picking up things, blocking exits and stopping anyone from using an object. If the attributes lock_msg, use_lock_msg and enter_lock_msg are defined on the locked object, these will be used as error messages instead of a standard one (so "the door is locked" instead of "you cannot traverse that exit"). Behind the scenes, there is a new module, src/locks.py that defines Keys and Locks. A Locks object is a collection of Lock types. This is stored in the LOCKS attribute on objects. Each Lock contains a set of Keys that might be of mixed type and which the player must match in order to pass the lock. /Griatch
This commit is contained in:
parent
7f7306a6e4
commit
66095a0b16
7 changed files with 491 additions and 26 deletions
|
|
@ -278,7 +278,11 @@ def match_exits(command,test=False):
|
||||||
if targ_exit.get_home():
|
if targ_exit.get_home():
|
||||||
# SCRIPT: See if the player can traverse the exit
|
# SCRIPT: See if the player can traverse the exit
|
||||||
if not targ_exit.scriptlink.default_lock(source_object):
|
if not targ_exit.scriptlink.default_lock(source_object):
|
||||||
source_object.emit_to("You can't traverse that exit.")
|
lock_msg = targ_exit.get_attribute_value("lock_msg")
|
||||||
|
if lock_msg:
|
||||||
|
source_object.emit_to(lock_msg)
|
||||||
|
else:
|
||||||
|
source_object.emit_to("You can't traverse that exit.")
|
||||||
else:
|
else:
|
||||||
source_object.move_to(targ_exit.get_home())
|
source_object.move_to(targ_exit.get_home())
|
||||||
else:
|
else:
|
||||||
|
|
@ -287,22 +291,33 @@ def match_exits(command,test=False):
|
||||||
raise ExitCommandHandler
|
raise ExitCommandHandler
|
||||||
|
|
||||||
|
|
||||||
def command_table_lookup(command, command_table, eval_perms=True,test=False):
|
def command_table_lookup(command, command_table, eval_perms=True,test=False,neighbor=None):
|
||||||
"""
|
"""
|
||||||
Performs a command table lookup on the specified command table. Also
|
Performs a command table lookup on the specified command table. Also
|
||||||
evaluates the permissions tuple.
|
evaluates the permissions tuple.
|
||||||
The test flag only checks without manipulating the command
|
The test flag only checks without manipulating the command
|
||||||
|
neighbor (object) If this is supplied, we are looking at a object table and
|
||||||
|
must check for locks.
|
||||||
"""
|
"""
|
||||||
# Get the command's function reference (Or False)
|
# Get the command's function reference (Or False)
|
||||||
cmdtuple = command_table.get_command_tuple(command.command_string)
|
cmdtuple = command_table.get_command_tuple(command.command_string)
|
||||||
if cmdtuple:
|
if cmdtuple:
|
||||||
|
# Check if this is just a test.
|
||||||
if test:
|
if test:
|
||||||
return True
|
return True
|
||||||
|
# Check locks
|
||||||
|
if neighbor and not neighbor.scriptlink.use_lock(command.source_object):
|
||||||
|
# send an locked error message only if lock_desc is defined
|
||||||
|
lock_msg = neighbor.get_attribute_value("use_lock_msg")
|
||||||
|
if lock_msg:
|
||||||
|
command.source_object.emit_to(lock_msg)
|
||||||
|
raise ExitCommandHandler
|
||||||
|
return False
|
||||||
# If there is a permissions element to the entry, check perms.
|
# If there is a permissions element to the entry, check perms.
|
||||||
if eval_perms and cmdtuple[1]:
|
if eval_perms and cmdtuple[1]:
|
||||||
if not command.source_object.has_perm_list(cmdtuple[1]):
|
if not command.source_object.has_perm_list(cmdtuple[1]):
|
||||||
command.source_object.emit_to(defines_global.NOPERMS_MSG)
|
command.source_object.emit_to(defines_global.NOPERMS_MSG)
|
||||||
raise ExitCommandHandler
|
raise ExitCommandHandler
|
||||||
# If flow reaches this point, user has perms and command is ready.
|
# If flow reaches this point, user has perms and command is ready.
|
||||||
command.command_function = cmdtuple[0]
|
command.command_function = cmdtuple[0]
|
||||||
command.extra_vars = cmdtuple[2]
|
command.extra_vars = cmdtuple[2]
|
||||||
|
|
@ -321,7 +336,9 @@ def match_neighbor_ctables(command,test=False):
|
||||||
neighbors = source_object.location.get_contents()
|
neighbors = source_object.location.get_contents()
|
||||||
for neighbor in neighbors:
|
for neighbor in neighbors:
|
||||||
if command_table_lookup(command,
|
if command_table_lookup(command,
|
||||||
neighbor.scriptlink.command_table, test=test):
|
neighbor.scriptlink.command_table,
|
||||||
|
test=test, neighbor=neighbor):
|
||||||
|
# test for a use-lock
|
||||||
# If there was a command match, set the scripted_obj attribute
|
# If there was a command match, set the scripted_obj attribute
|
||||||
# for the script parent to pick up.
|
# for the script parent to pick up.
|
||||||
if test:
|
if test:
|
||||||
|
|
|
||||||
|
|
@ -167,13 +167,22 @@ def cmd_get(command):
|
||||||
return
|
return
|
||||||
|
|
||||||
if not obj_is_staff and (target_obj.is_player() or target_obj.is_exit()):
|
if not obj_is_staff and (target_obj.is_player() or target_obj.is_exit()):
|
||||||
|
|
||||||
source_object.emit_to("You can't get that.")
|
source_object.emit_to("You can't get that.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if target_obj.is_room() or target_obj.is_garbage() or target_obj.is_going():
|
if target_obj.is_room() or target_obj.is_garbage() or target_obj.is_going():
|
||||||
source_object.emit_to("You can't get that.")
|
source_object.emit_to("You can't get that.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if not target_obj.scriptlink.default_lock(source_object):
|
||||||
|
lock_msg = target_obj.get_attribute_value("lock_msg")
|
||||||
|
if lock_msg:
|
||||||
|
source_object.emit_to(lock_msg)
|
||||||
|
else:
|
||||||
|
source_object.emit_to("You can't get that.")
|
||||||
|
return
|
||||||
|
|
||||||
target_obj.move_to(source_object, quiet=True)
|
target_obj.move_to(source_object, quiet=True)
|
||||||
source_object.emit_to("You pick up %s." % (target_obj.get_name(show_dbref=False),))
|
source_object.emit_to("You pick up %s." % (target_obj.get_name(show_dbref=False),))
|
||||||
source_object.get_location().emit_to_contents("%s picks up %s." %
|
source_object.get_location().emit_to_contents("%s picks up %s." %
|
||||||
|
|
@ -282,11 +291,14 @@ def cmd_examine(command):
|
||||||
|
|
||||||
s += str(target_obj.get_name(fullname=True)) + newl
|
s += str(target_obj.get_name(fullname=True)) + newl
|
||||||
s += str("Type: %s Flags: %s" % (target_obj.get_type(),
|
s += str("Type: %s Flags: %s" % (target_obj.get_type(),
|
||||||
target_obj.get_flags())) + newl
|
target_obj.get_flags())) + newl
|
||||||
#s += str("Desc: %s" % target_obj.get_attribute_value('desc')) + newl
|
|
||||||
s += str("Owner: %s " % target_obj.get_owner()) + newl
|
s += str("Owner: %s " % target_obj.get_owner()) + newl
|
||||||
s += str("Zone: %s" % target_obj.get_zone()) + newl
|
s += str("Zone: %s" % target_obj.get_zone()) + newl
|
||||||
s += str("Parent: %s " % target_obj.get_script_parent()) + newl
|
s += str("Parent: %s " % target_obj.get_script_parent()) + newl
|
||||||
|
|
||||||
|
locks = target_obj.get_attribute_value("LOCKS")
|
||||||
|
if locks and "%s" % locks:
|
||||||
|
s += str("Locks: %s" % locks) + newl
|
||||||
|
|
||||||
# Contents container lists for sorting by type.
|
# Contents container lists for sorting by type.
|
||||||
con_players = []
|
con_players = []
|
||||||
|
|
@ -313,6 +325,7 @@ def cmd_examine(command):
|
||||||
# This obviously isn't valid for rooms.
|
# This obviously isn't valid for rooms.
|
||||||
s += str("Location: %s" % target_obj.get_location()) + newl
|
s += str("Location: %s" % target_obj.get_location()) + newl
|
||||||
|
|
||||||
|
# Render other attributes
|
||||||
for attribute in target_obj.get_all_attributes():
|
for attribute in target_obj.get_all_attributes():
|
||||||
s += str(attribute.get_attrline()) + newl
|
s += str(attribute.get_attrline()) + newl
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
"""
|
"""
|
||||||
These commands typically are to do with building or modifying Objects.
|
These commands typically are to do with building or modifying Objects.
|
||||||
"""
|
"""
|
||||||
|
from django.contrib.auth.models import Permission, Group
|
||||||
from src.objects.models import Object, Attribute
|
from src.objects.models import Object, Attribute
|
||||||
# We'll import this as the full path to avoid local variable clashes.
|
# We'll import this as the full path to avoid local variable clashes.
|
||||||
import src.flags
|
import src.flags
|
||||||
|
from src import locks
|
||||||
from src import ansi
|
from src import ansi
|
||||||
from src.cmdtable import GLOBAL_CMD_TABLE
|
from src.cmdtable import GLOBAL_CMD_TABLE
|
||||||
from src import defines_global
|
from src import defines_global
|
||||||
|
|
@ -445,7 +447,7 @@ def cmd_create(command):
|
||||||
return
|
return
|
||||||
|
|
||||||
eq_args = command.command_argument.split(':', 1)
|
eq_args = command.command_argument.split(':', 1)
|
||||||
target_name = eq_args[0]
|
target_name = eq_args[0].strip()
|
||||||
|
|
||||||
#check if we want to set a custom parent
|
#check if we want to set a custom parent
|
||||||
script_parent = None
|
script_parent = None
|
||||||
|
|
@ -814,7 +816,7 @@ def cmd_dig(command):
|
||||||
where you are.
|
where you are.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@dig[/switches] roomname [:parent] [= exitthere [: parent][;alias]] [, exithere [: parent][;alias]]
|
@dig[/switches] roomname [:parent] [= exit_to_there [: parent][;alias]] [, exit_to_here [: parent][;alias]]
|
||||||
|
|
||||||
switches:
|
switches:
|
||||||
teleport - move yourself to the new room
|
teleport - move yourself to the new room
|
||||||
|
|
@ -829,7 +831,7 @@ def cmd_dig(command):
|
||||||
switches = command.command_switches
|
switches = command.command_switches
|
||||||
|
|
||||||
if not args:
|
if not args:
|
||||||
source_object.emit_to("Usage[/teleport]: @dig roomname [:parent][= exitthere [:parent] [;alias]] [, exithere [:parent] [;alias]]")
|
source_object.emit_to("Usage: @dig[/teleport] roomname [:parent][= exit_to_there [:parent] [;alias]] [, exit_to_here [:parent] [;alias]]")
|
||||||
return
|
return
|
||||||
|
|
||||||
room_name = None
|
room_name = None
|
||||||
|
|
@ -1158,3 +1160,148 @@ def cmd_destroy(command):
|
||||||
|
|
||||||
GLOBAL_CMD_TABLE.add_command("@destroy", cmd_destroy,
|
GLOBAL_CMD_TABLE.add_command("@destroy", cmd_destroy,
|
||||||
priv_tuple=("objects.create",),auto_help=True,staff_help=True)
|
priv_tuple=("objects.create",),auto_help=True,staff_help=True)
|
||||||
|
|
||||||
|
def cmd_lock(command):
|
||||||
|
"""@lock
|
||||||
|
Usage:
|
||||||
|
@lock[/switch] <obj> [:type] [= <key>[,key2,key3,...]]
|
||||||
|
|
||||||
|
switches:
|
||||||
|
add - add a lock (default) from object
|
||||||
|
del - remove a lock from object
|
||||||
|
list - view all locks on object (default)
|
||||||
|
type:
|
||||||
|
DefaultLock - the default lock type (default)
|
||||||
|
|
||||||
|
Locks an object for everyone except those matching the keys.
|
||||||
|
The keys can be of the following types (and searched in this order):
|
||||||
|
- a user #dbref (#2, #45 etc)
|
||||||
|
- a Group name (Builder, Immortal etc, case sensitive)
|
||||||
|
- a Permission string (genperms.get, etc)
|
||||||
|
If no keys are given, the object is locked for everyone.
|
||||||
|
|
||||||
|
When the lock blocks a user, you may customize which error is given by
|
||||||
|
storing error messages in an attribute. For DefaultLocks, UseLocks and
|
||||||
|
EnterLocks, these attributes are called lock_msg, use_lock_msg and
|
||||||
|
enter_lock_msg respectively.
|
||||||
|
<<TOPIC:lock types>>
|
||||||
|
Lock types:
|
||||||
|
|
||||||
|
Name: Affects: Effect:
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
DefaultLock: Exits: controls who may traverse the exit to
|
||||||
|
its destination.
|
||||||
|
Rooms: controls whether the player sees a failure
|
||||||
|
message after the room description when
|
||||||
|
looking at the room.
|
||||||
|
Players/Things: controls who may 'get' the object.
|
||||||
|
|
||||||
|
UseLock: All but Exits: controls who may use commands defined on
|
||||||
|
the locked object.
|
||||||
|
|
||||||
|
EnterLock: Players/Things: controls who may enter/teleport into
|
||||||
|
the object.
|
||||||
|
|
||||||
|
Fail messages echoed to the player are stored in the attributes 'lock_msg',
|
||||||
|
'use_lock_msg' and 'enter_lock_msg' on the locked object in question. If no
|
||||||
|
such message is stored, a default will be used (or none at all in some cases).
|
||||||
|
"""
|
||||||
|
|
||||||
|
source_object = command.source_object
|
||||||
|
arg = command.command_argument
|
||||||
|
switches = command.command_switches
|
||||||
|
|
||||||
|
if not arg:
|
||||||
|
source_object.emit_to("Usage: @lock[/switch] <obj> [:type] [= <key>[,key2,key3,...]]")
|
||||||
|
return
|
||||||
|
keys = ""
|
||||||
|
#deal with all possible arguments.
|
||||||
|
try:
|
||||||
|
lside, keys = arg.split("=",1)
|
||||||
|
except ValueError:
|
||||||
|
lside = arg
|
||||||
|
lside, keys = lside.strip(), keys.strip()
|
||||||
|
try:
|
||||||
|
obj_name, ltype = lside.split(":",1)
|
||||||
|
except:
|
||||||
|
obj_name = lside
|
||||||
|
ltype = "DefaultLock"
|
||||||
|
obj_name, ltype = obj_name.strip(), ltype.strip()
|
||||||
|
|
||||||
|
if ltype not in ["DefaultLock","UseLock","EnterLock"]:
|
||||||
|
source_object.emit_to("Lock type '%s' not recognized." % ltype)
|
||||||
|
return
|
||||||
|
|
||||||
|
obj = source_object.search_for_object(obj_name)
|
||||||
|
if not obj:
|
||||||
|
return
|
||||||
|
|
||||||
|
obj_locks = obj.get_attribute_value("LOCKS")
|
||||||
|
|
||||||
|
if "list" in switches or not switches:
|
||||||
|
if not obj_locks:
|
||||||
|
s = "There are no locks on %s." % obj.get_name()
|
||||||
|
else:
|
||||||
|
s = "Locks on %s:" % obj.get_name()
|
||||||
|
s += obj_locks.show()
|
||||||
|
source_object.emit_to(s)
|
||||||
|
return
|
||||||
|
|
||||||
|
# we are trying to change things. Check permissions.
|
||||||
|
if not source_object.controls_other(obj):
|
||||||
|
source_object.emit_to(defines_global.NOCONTROL_MSG)
|
||||||
|
return
|
||||||
|
|
||||||
|
if "del" in switches:
|
||||||
|
# clear a lock
|
||||||
|
if obj_locks:
|
||||||
|
if not obj_locks.has_type(ltype):
|
||||||
|
source_object.emit_to("No %s set on this object." % ltype)
|
||||||
|
else:
|
||||||
|
obj_locks.del_type(ltype)
|
||||||
|
obj.set_attribute("LOCKS", obj_locks)
|
||||||
|
source_object.emit_to("Cleared lock %s on %s." % (ltype, obj.get_name()))
|
||||||
|
else:
|
||||||
|
source_object.emit_to("No %s set on this object." % ltype)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
#try to add a lock
|
||||||
|
if not obj_locks:
|
||||||
|
obj_locks = locks.Locks()
|
||||||
|
if not keys:
|
||||||
|
#add an impassable lock
|
||||||
|
obj_locks.add_type(ltype, locks.Key())
|
||||||
|
source_object.emit_to("Added impassable '%s' lock to %s." % (ltype, obj.get_name()))
|
||||||
|
else:
|
||||||
|
keys = [k.strip() for k in keys.split(",")]
|
||||||
|
okeys, gkeys, pkeys = [], [], []
|
||||||
|
allgroups = [g.name for g in Group.objects.all()]
|
||||||
|
allperms = ["%s.%s" % (p.content_type.app_label, p.codename) for p in Permission.objects.all()]
|
||||||
|
for key in keys:
|
||||||
|
#differentiate different type of keys
|
||||||
|
if Object.objects.is_dbref(key):
|
||||||
|
okeys.append(key)
|
||||||
|
elif key in allgroups:
|
||||||
|
gkeys.append(key)
|
||||||
|
elif key in allperms:
|
||||||
|
pkeys.append(key)
|
||||||
|
else:
|
||||||
|
source_object.emit_to("Key '%s' is not recognized as a valid dbref, group or permission." % key)
|
||||||
|
return
|
||||||
|
# Create actual key objects from the respective lists
|
||||||
|
keys = []
|
||||||
|
if okeys:
|
||||||
|
keys.append(locks.ObjKey(okeys))
|
||||||
|
if gkeys:
|
||||||
|
keys.append(locks.GroupKey(gkeys))
|
||||||
|
if pkeys:
|
||||||
|
keys.append(locks.PermKey(pkeys))
|
||||||
|
#store the keys in the lock
|
||||||
|
obj_locks.add_type(ltype, keys)
|
||||||
|
kstring = ""
|
||||||
|
for key in keys:
|
||||||
|
kstring += " %s" % key
|
||||||
|
source_object.emit_to("Added lock '%s' to %s with keys%s." % (ltype, obj.get_name(), kstring))
|
||||||
|
|
||||||
|
obj.set_attribute("LOCKS",obj_locks)
|
||||||
|
GLOBAL_CMD_TABLE.add_command("@lock", cmd_lock, priv_tuple=("objects.create",),auto_help=True, staff_help=True)
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,10 @@ OBJECT_TYPES = (
|
||||||
|
|
||||||
# These attribute names can't be modified by players.
|
# These attribute names can't be modified by players.
|
||||||
NOSET_ATTRIBS = ["MONEY", "ALIAS", "LASTPAGED", "__CHANLIST", "LAST",
|
NOSET_ATTRIBS = ["MONEY", "ALIAS", "LASTPAGED", "__CHANLIST", "LAST",
|
||||||
"__PARENT", "LASTSITE"]
|
"__PARENT", "LASTSITE", "LOCKS"]
|
||||||
|
|
||||||
# These attributes don't show up on objects when examined.
|
# These attributes don't show up on objects when examined.
|
||||||
HIDDEN_ATTRIBS = ["__CHANLIST", "__PARENT"]
|
HIDDEN_ATTRIBS = ["__CHANLIST", "__PARENT", "LOCKS"]
|
||||||
|
|
||||||
# Server version number.
|
# Server version number.
|
||||||
REVISION = os.popen('svnversion .', 'r').readline().strip()
|
REVISION = os.popen('svnversion .', 'r').readline().strip()
|
||||||
|
|
|
||||||
246
src/locks.py
Normal file
246
src/locks.py
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
"""
|
||||||
|
This module handles all in-game locks.
|
||||||
|
|
||||||
|
A lock object contains a set of criteria (keys). When queried, the
|
||||||
|
lock tries the tested object/player against these criteria and returns
|
||||||
|
a True/False result.
|
||||||
|
"""
|
||||||
|
import traceback
|
||||||
|
from src.objects.models import Object
|
||||||
|
from src import logger
|
||||||
|
|
||||||
|
class Key(object):
|
||||||
|
"""
|
||||||
|
This implements a lock key.
|
||||||
|
|
||||||
|
Normally the Key is of OR type; if an object matches any criterion in the key,
|
||||||
|
the entire key is considered a match. With the 'exact' criterion, all criteria
|
||||||
|
contained in the key (except the list of object dbrefs) must also exist in the
|
||||||
|
object.
|
||||||
|
With the NOT flag the key is inversed, that is, only objects which do not
|
||||||
|
match the criterias (exact or not) will be considered to have access.
|
||||||
|
|
||||||
|
Supplying no criteria will make the lock impassable (NOT flag results in an alvays open lock)
|
||||||
|
"""
|
||||||
|
def __init__(self, criteria=[], extra=[], NOT=False, exact=False):
|
||||||
|
"""
|
||||||
|
Defines the basic permission laws
|
||||||
|
permlist (list of strings) - permission definitions
|
||||||
|
grouplist (list of strings) - group names
|
||||||
|
objlist (list of obj or dbrefs) - match individual objects to the lock
|
||||||
|
NOT (bool) - invert the lock
|
||||||
|
exact (bool) - objects must match all criteria. Default is OR operation.
|
||||||
|
"""
|
||||||
|
self.criteria = criteria
|
||||||
|
self.extra = extra
|
||||||
|
|
||||||
|
#set the boolean operators
|
||||||
|
self.NOT = not NOT
|
||||||
|
self.exact = exact
|
||||||
|
|
||||||
|
# if we have no criteria, this is an impassable lock (or always open if NOT given).
|
||||||
|
self.impassable = not(criteria)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = ""
|
||||||
|
if not self.criteria:
|
||||||
|
s += " <Impassable>"
|
||||||
|
for crit in self.criteria:
|
||||||
|
s += " <%s>" % crit
|
||||||
|
return s.strip()
|
||||||
|
|
||||||
|
def _result(self, result):
|
||||||
|
if self.exact:
|
||||||
|
result = result == len(self.criteria)
|
||||||
|
if result:
|
||||||
|
return self.NOT
|
||||||
|
else:
|
||||||
|
return not self.NOT
|
||||||
|
|
||||||
|
def check(self, object):
|
||||||
|
"""
|
||||||
|
Compare the object to see if the key matches.
|
||||||
|
"""
|
||||||
|
if self.NOT:
|
||||||
|
return not self.impassable
|
||||||
|
return self.impassable
|
||||||
|
|
||||||
|
class ObjKey(Key):
|
||||||
|
"""
|
||||||
|
This implements a Key matching against object id
|
||||||
|
"""
|
||||||
|
def check(self, object):
|
||||||
|
|
||||||
|
if self.impassable:
|
||||||
|
return self.NOT
|
||||||
|
if object.dbref() in self.criteria:
|
||||||
|
return self.NOT
|
||||||
|
else:
|
||||||
|
return not self.NOT
|
||||||
|
|
||||||
|
class GroupKey(Key):
|
||||||
|
"""
|
||||||
|
This key matches against group membership
|
||||||
|
"""
|
||||||
|
def check(self, object):
|
||||||
|
if self.impassable: return self.NOT
|
||||||
|
user = object.get_user_account()
|
||||||
|
if not user: return False
|
||||||
|
return self._result(len([g for g in user.groups.all() if str(g) in self.criteria]))
|
||||||
|
|
||||||
|
class PermKey(Key):
|
||||||
|
"""
|
||||||
|
This key matches against permissions
|
||||||
|
"""
|
||||||
|
def check(self, object):
|
||||||
|
if self.impassable: return self.NOT
|
||||||
|
user = object.get_user_account()
|
||||||
|
if not user: return False
|
||||||
|
return self._result(len([p for p in self.criteria if object.has_perm(p)]))
|
||||||
|
|
||||||
|
class FlagKey(Key):
|
||||||
|
"""
|
||||||
|
This key use a set of object flagss to define access.
|
||||||
|
"""
|
||||||
|
def check(self, object):
|
||||||
|
if self.impassable: return self.NOT
|
||||||
|
return self._result(len([f for f in self.criteria if object.has_flag(f)]))
|
||||||
|
|
||||||
|
class AttrKey(Key):
|
||||||
|
"""
|
||||||
|
This key use a list of arbitrary attributes to define access.
|
||||||
|
|
||||||
|
The attribute names are in the usual criteria. If there is a matching
|
||||||
|
list of values in the self.extra list we compare the values directly,
|
||||||
|
otherwise we just check for the existence of the attribute.
|
||||||
|
"""
|
||||||
|
def check(self, object):
|
||||||
|
if self.impassable: return self.NOT
|
||||||
|
val_list = self.extra
|
||||||
|
attr_list = self.criteria
|
||||||
|
if len(val_list) == len(attr_list):
|
||||||
|
return self._result(len([i for i in range(attr_list)
|
||||||
|
if object.get_attribute_value(attr_list[i])==val_list[i]]))
|
||||||
|
else:
|
||||||
|
return _result(len([a for a in attr_list if object.get_attribute_value(a)]))
|
||||||
|
|
||||||
|
class Locks(object):
|
||||||
|
"""
|
||||||
|
The Locks object defines an overall grouping of Locks based after type. Each lock
|
||||||
|
contains a set of keys to limit access to a certain action.
|
||||||
|
The Lock object is stored in the attribute LOCKS on the object in question and the
|
||||||
|
engine queries it during the relevant situations.
|
||||||
|
|
||||||
|
Below is a list copied from MUX. Currently Evennia only use 3 lock types:
|
||||||
|
Default, Use and Enter; it's not clear if any more are really needed.
|
||||||
|
|
||||||
|
Name: Affects: Effect:
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
DefaultLock: Exits: controls who may traverse the exit to
|
||||||
|
its destination.
|
||||||
|
Rooms: controls whether the player sees the SUCC
|
||||||
|
or FAIL message for the room following the
|
||||||
|
room description when looking at the room.
|
||||||
|
Players/Things: controls who may GET the object.
|
||||||
|
EnterLock: Players/Things: controls who may ENTER the object if the
|
||||||
|
object is ENTER_OK. Also, the enter lock
|
||||||
|
of an object being used as a Zone Master
|
||||||
|
Object determines control of that zone.
|
||||||
|
GetFromLock: All but Exits: controls who may gets things from a given
|
||||||
|
location.
|
||||||
|
GiveLock: Players/Things: controls who may give the object.
|
||||||
|
LeaveLock: Players/Things: controls who may LEAVE the object.
|
||||||
|
LinkLock: All but Exits: controls who may link to the location if the
|
||||||
|
location is LINK_OK (for linking exits or
|
||||||
|
setting drop-tos) or ABODE (for setting
|
||||||
|
homes)
|
||||||
|
MailLock: Players: controls who may @mail the player.
|
||||||
|
OpenLock: All but Exits: controls who may open an exit.
|
||||||
|
PageLock: Players: controls who may page the player.
|
||||||
|
ParentLock: All: controls who may make @parent links to the
|
||||||
|
object.
|
||||||
|
ReceiveLock: Players/Things: controls who may give things to the object.
|
||||||
|
SpeechLock: All but Exits: controls who may speak in that location
|
||||||
|
(only checked if AUDITORIUM flag is set
|
||||||
|
on that location)
|
||||||
|
TeloutLock: All but Exits: controls who may teleport out of the
|
||||||
|
location.
|
||||||
|
TportLock: Rooms/Things: controls who may teleport there if the
|
||||||
|
location is JUMP_OK.
|
||||||
|
UseLock: All but Exits: controls who may USE the object, GIVE the
|
||||||
|
object money and have the PAY attributes
|
||||||
|
run, have their messages heard and possibly
|
||||||
|
acted on by LISTEN and AxHEAR, and invoke
|
||||||
|
$-commands stored on the object.
|
||||||
|
DropLock: All but rooms: controls who may drop that object.
|
||||||
|
UserLock: All: Not used by MUX, is intended to be used
|
||||||
|
in MUX programming where a user-defined
|
||||||
|
lock is needed.
|
||||||
|
VisibleLock: All: Controls object visibility when the object
|
||||||
|
is not dark and the looker passes the lock.
|
||||||
|
In DARK locations, the object must also be
|
||||||
|
set LIGHT and the viewer must pass the
|
||||||
|
VisibleLock.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
|
||||||
|
The Lock logic is strictly OR. If you want to make access restricted,
|
||||||
|
make it so in the respective Key.
|
||||||
|
"""
|
||||||
|
self.locks = {}
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = ""
|
||||||
|
for lock in self.locks.keys():
|
||||||
|
s += " %s" % lock
|
||||||
|
return s.strip()
|
||||||
|
|
||||||
|
def add_type(self, ltype, keys=[]):
|
||||||
|
"""
|
||||||
|
type (string) : the type pf lock, like DefaultLock, UseLock etc.
|
||||||
|
keylist = list of Key objects defining who have access.
|
||||||
|
"""
|
||||||
|
if type(keys) != type(list()):
|
||||||
|
keys = [keys]
|
||||||
|
self.locks[ltype] = keys
|
||||||
|
|
||||||
|
def del_type(self,ltype):
|
||||||
|
"""
|
||||||
|
Clears a lock.
|
||||||
|
"""
|
||||||
|
if self.has_type(ltype):
|
||||||
|
del self.locks[ltype]
|
||||||
|
|
||||||
|
def has_type(self,ltype):
|
||||||
|
return self.locks.has_key(ltype)
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
if not self.locks:
|
||||||
|
return "No locks."
|
||||||
|
s = ""
|
||||||
|
for lock, keys in self.locks.items():
|
||||||
|
s += "\n %s\n " % lock
|
||||||
|
for key in keys:
|
||||||
|
s += " %s" % key
|
||||||
|
return s
|
||||||
|
|
||||||
|
def check(self, ltype, object):
|
||||||
|
"""
|
||||||
|
This is called by the engine. It checks if this lock is of the right type,
|
||||||
|
and if so if there is access. If the type does not exist, there is no
|
||||||
|
lock for it and thus we return True.
|
||||||
|
"""
|
||||||
|
if not self.has_type(ltype):
|
||||||
|
return True
|
||||||
|
result = False
|
||||||
|
for key in self.locks[ltype]:
|
||||||
|
try:
|
||||||
|
result = result or key.check(object)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
if not result and object.is_superuser():
|
||||||
|
object.emit_to("Lock '%s' - Superuser override." % ltype)
|
||||||
|
return True
|
||||||
|
return result
|
||||||
|
|
@ -338,6 +338,22 @@ class Object(models.Model):
|
||||||
# Fall through to failure
|
# Fall through to failure
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def has_group(self, group):
|
||||||
|
"""
|
||||||
|
Checks if a user is member of a particular user group.
|
||||||
|
"""
|
||||||
|
if not self.is_player():
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.is_superuser():
|
||||||
|
return True
|
||||||
|
|
||||||
|
if group in [g.name for g in self.get_user_account().groups.all()]:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def owns_other(self, other_obj):
|
def owns_other(self, other_obj):
|
||||||
"""
|
"""
|
||||||
See if the envoked object owns another object.
|
See if the envoked object owns another object.
|
||||||
|
|
@ -367,7 +383,7 @@ class Object(models.Model):
|
||||||
|
|
||||||
# When builder_override is enabled, a builder permission means
|
# When builder_override is enabled, a builder permission means
|
||||||
# the object controls the other.
|
# the object controls the other.
|
||||||
if builder_override and not other_obj.is_player() and self.has_perm('genperms.builder'):
|
if builder_override and not other_obj.is_player() and self.has_group('Builders'):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# They've failed to meet any of the above conditions.
|
# They've failed to meet any of the above conditions.
|
||||||
|
|
@ -883,9 +899,18 @@ class Object(models.Model):
|
||||||
quiet: (bool) If true, don't emit left/arrived messages.
|
quiet: (bool) If true, don't emit left/arrived messages.
|
||||||
force_look: (bool) If true and self is a player, make them 'look'.
|
force_look: (bool) If true and self is a player, make them 'look'.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
#first, check if we can enter that location at all.
|
||||||
|
if not target.scriptlink.enter_lock(self):
|
||||||
|
lock_desc = self.get_attribute_value("enter_lock_msg")
|
||||||
|
if lock_desc:
|
||||||
|
self.emit_to(lock_desc)
|
||||||
|
else:
|
||||||
|
self.emit_to("That destination is blocked from you.")
|
||||||
|
return
|
||||||
|
|
||||||
#before the move, call eventual pre-commands.
|
#before the move, call eventual pre-commands.
|
||||||
if self.scriptlink.at_before_move(target) != None:
|
if self.scriptlink.at_before_move(target) != None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not quiet:
|
if not quiet:
|
||||||
|
|
|
||||||
|
|
@ -135,16 +135,24 @@ class EvenniaBasicObject(object):
|
||||||
# This is the object being looked at.
|
# This is the object being looked at.
|
||||||
target_obj = self.scripted_obj
|
target_obj = self.scripted_obj
|
||||||
# See if the envoker sees dbref numbers.
|
# See if the envoker sees dbref numbers.
|
||||||
|
lock_msg = ""
|
||||||
if pobject:
|
if pobject:
|
||||||
show_dbrefs = pobject.sees_dbrefs()
|
show_dbrefs = pobject.sees_dbrefs()
|
||||||
|
|
||||||
|
#check for the defaultlock, this shows a lock message after the normal desc, if one is defined.
|
||||||
|
if target_obj.is_room() and \
|
||||||
|
not target_obj.scriptlink.default_lock(pobject):
|
||||||
|
temp = target_obj.get_attribute_value("lock_msg")
|
||||||
|
if temp:
|
||||||
|
lock_msg = "\n%s" % temp
|
||||||
else:
|
else:
|
||||||
show_dbrefs = False
|
show_dbrefs = False
|
||||||
|
|
||||||
description = target_obj.get_attribute_value('desc')
|
description = target_obj.get_attribute_value('desc')
|
||||||
if description is not None:
|
if description is not None:
|
||||||
retval = "%s\r\n%s" % (
|
retval = "%s\r\n%s%s" % (
|
||||||
target_obj.get_name(show_dbref=show_dbrefs),
|
target_obj.get_name(show_dbref=show_dbrefs),
|
||||||
target_obj.get_attribute_value('desc'),
|
target_obj.get_attribute_value('desc'), lock_msg
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
retval = "%s" % (
|
retval = "%s" % (
|
||||||
|
|
@ -192,8 +200,11 @@ class EvenniaBasicObject(object):
|
||||||
values:
|
values:
|
||||||
* pobject: (Object) The object requesting the action.
|
* pobject: (Object) The object requesting the action.
|
||||||
"""
|
"""
|
||||||
# Assume everyone passes the default lock by default.
|
locks = self.scripted_obj.get_attribute_value("LOCKS")
|
||||||
return True
|
if locks:
|
||||||
|
return locks.check("DefaultLock", pobject)
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
def use_lock(self, pobject):
|
def use_lock(self, pobject):
|
||||||
"""
|
"""
|
||||||
|
|
@ -204,8 +215,11 @@ class EvenniaBasicObject(object):
|
||||||
values:
|
values:
|
||||||
* pobject: (Object) The object requesting the action.
|
* pobject: (Object) The object requesting the action.
|
||||||
"""
|
"""
|
||||||
# Assume everyone passes the use lock by default.
|
locks = self.scripted_obj.get_attribute_value("LOCKS")
|
||||||
return True
|
if locks:
|
||||||
|
return locks.check("UseLock", pobject)
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
def enter_lock(self, pobject):
|
def enter_lock(self, pobject):
|
||||||
"""
|
"""
|
||||||
|
|
@ -216,5 +230,8 @@ class EvenniaBasicObject(object):
|
||||||
values:
|
values:
|
||||||
* pobject: (Object) The object requesting the action.
|
* pobject: (Object) The object requesting the action.
|
||||||
"""
|
"""
|
||||||
# Assume everyone passes the enter lock by default.
|
locks = self.scripted_obj.get_attribute_value("LOCKS")
|
||||||
return True
|
if locks:
|
||||||
|
return locks.check("EnterLock", pobject)
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue