2020-04-07 23:13:24 +02:00
|
|
|
# Locks
|
|
|
|
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
For most games it is a good idea to restrict what people can do. In Evennia such restrictions are
|
2021-10-21 21:04:14 +02:00
|
|
|
applied and checked by something called *locks*. All Evennia entities ([Commands](./Commands.md),
|
|
|
|
|
[Objects](./Objects.md), [Scripts](./Scripts.md), [Accounts](./Accounts.md), [Help System](./Help-System.md),
|
|
|
|
|
[messages](./Msg.md) and [channels](./Channels.md)) are accessed through locks.
|
2020-06-16 16:53:35 +02:00
|
|
|
|
|
|
|
|
A lock can be thought of as an "access rule" restricting a particular use of an Evennia entity.
|
|
|
|
|
Whenever another entity wants that kind of access the lock will analyze that entity in different
|
|
|
|
|
ways to determine if access should be granted or not. Evennia implements a "lockdown" philosophy -
|
|
|
|
|
all entities are inaccessible unless you explicitly define a lock that allows some or full access.
|
|
|
|
|
|
|
|
|
|
Let's take an example: An object has a lock on itself that restricts how people may "delete" that
|
|
|
|
|
object. Apart from knowing that it restricts deletion, the lock also knows that only players with
|
|
|
|
|
the specific ID of, say, `34` are allowed to delete it. So whenever a player tries to run `delete`
|
|
|
|
|
on the object, the `delete` command makes sure to check if this player is really allowed to do so.
|
|
|
|
|
It calls the lock, which in turn checks if the player's id is `34`. Only then will it allow `delete`
|
|
|
|
|
to go on with its job.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
## Setting and checking a lock
|
|
|
|
|
|
|
|
|
|
The in-game command for setting locks on objects is `lock`:
|
|
|
|
|
|
|
|
|
|
> lock obj = <lockstring>
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
The `<lockstring>` is a string of a certain form that defines the behaviour of the lock. We will go
|
|
|
|
|
into more detail on how `<lockstring>` should look in the next section.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
Code-wise, Evennia handles locks through what is usually called `locks` on all relevant entities.
|
|
|
|
|
This is a handler that allows you to add, delete and check locks.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
myobj.locks.add(<lockstring>)
|
|
|
|
|
```
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
One can call `locks.check()` to perform a lock check, but to hide the underlying implementation all
|
|
|
|
|
objects also have a convenience function called `access`. This should preferably be used. In the
|
|
|
|
|
example below, `accessing_obj` is the object requesting the 'delete' access whereas `obj` is the
|
|
|
|
|
object that might get deleted. This is how it would look (and does look) from inside the `delete`
|
|
|
|
|
command:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
if not obj.access(accessing_obj, 'delete'):
|
|
|
|
|
accessing_obj.msg("Sorry, you may not delete that.")
|
2021-05-23 17:00:02 +02:00
|
|
|
return
|
2020-04-07 23:13:24 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Defining locks
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
Defining a lock (i.e. an access restriction) in Evennia is done by adding simple strings of lock
|
|
|
|
|
definitions to the object's `locks` property using `obj.locks.add()`.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-05-23 17:00:02 +02:00
|
|
|
Here are some examples of lock strings (not including the quotes):
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
delete:id(34) # only allow obj #34 to delete
|
2021-05-23 17:00:02 +02:00
|
|
|
edit:all() # let everyone edit
|
2020-04-07 23:13:24 +02:00
|
|
|
# only those who are not "very_weak" or are Admins may pick this up
|
2021-05-23 17:00:02 +02:00
|
|
|
get: not attr(very_weak) or perm(Admin)
|
2020-04-07 23:13:24 +02:00
|
|
|
```
|
|
|
|
|
|
2021-05-23 17:00:02 +02:00
|
|
|
Formally, a lockstring has the following syntax:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
access_type: [NOT] lockfunc1([arg1,..]) [AND|OR] [NOT] lockfunc2([arg1,...]) [...]
|
|
|
|
|
```
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
where `[]` marks optional parts. `AND`, `OR` and `NOT` are not case sensitive and excess spaces are
|
|
|
|
|
ignored. `lockfunc1, lockfunc2` etc are special _lock functions_ available to the lock system.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
So, a lockstring consists of the type of restriction (the `access_type`), a colon (`:`) and then an
|
|
|
|
|
expression involving function calls that determine what is needed to pass the lock. Each function
|
|
|
|
|
returns either `True` or `False`. `AND`, `OR` and `NOT` work as they do normally in Python. If the
|
|
|
|
|
total result is `True`, the lock is passed.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
You can create several lock types one after the other by separating them with a semicolon (`;`) in
|
|
|
|
|
the lockstring. The string below yields the same result as the previous example:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-05-23 17:00:02 +02:00
|
|
|
delete:id(34);edit:all();get: not attr(very_weak) or perm(Admin)
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
### Valid access_types
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
An `access_type`, the first part of a lockstring, defines what kind of capability a lock controls,
|
|
|
|
|
such as "delete" or "edit". You may in principle name your `access_type` anything as long as it is
|
|
|
|
|
unique for the particular object. The name of the access types is not case-sensitive.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
If you want to make sure the lock is used however, you should pick `access_type` names that you (or
|
|
|
|
|
the default command set) actually checks for, as in the example of `delete` above that uses the
|
|
|
|
|
'delete' `access_type`.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
Below are the access_types checked by the default commandset.
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
- [Commands](./Commands.md)
|
2020-04-07 23:13:24 +02:00
|
|
|
- `cmd` - this defines who may call this command at all.
|
2021-10-21 21:04:14 +02:00
|
|
|
- [Objects](./Objects.md):
|
2020-06-16 16:53:35 +02:00
|
|
|
- `control` - who is the "owner" of the object. Can set locks, delete it etc. Defaults to the
|
|
|
|
|
creator of the object.
|
|
|
|
|
- `call` - who may call Object-commands stored on this Object except for the Object itself. By
|
|
|
|
|
default, Objects share their Commands with anyone in the same location (e.g. so you can 'press' a
|
|
|
|
|
`Button` object in the room). For Characters and Mobs (who likely only use those Commands for
|
|
|
|
|
themselves and don't want to share them) this should usually be turned off completely, using
|
|
|
|
|
something like `call:false()`.
|
2020-04-07 23:13:24 +02:00
|
|
|
- `examine` - who may examine this object's properties.
|
|
|
|
|
- `delete` - who may delete the object.
|
|
|
|
|
- `edit` - who may edit properties and attributes of the object.
|
|
|
|
|
- `view` - if the `look` command will display/list this object
|
|
|
|
|
- `get`- who may pick up the object and carry it around.
|
|
|
|
|
- `puppet` - who may "become" this object and control it as their "character".
|
|
|
|
|
- `attrcreate` - who may create new attributes on the object (default True)
|
2021-10-21 21:04:14 +02:00
|
|
|
- [Characters](./Objects.md#characters):
|
2021-05-23 17:00:02 +02:00
|
|
|
- Same as for Objects
|
2021-10-21 21:04:14 +02:00
|
|
|
- [Exits](./Objects.md#exits):
|
2020-04-07 23:13:24 +02:00
|
|
|
- Same as for Objects
|
|
|
|
|
- `traverse` - who may pass the exit.
|
2021-10-21 21:04:14 +02:00
|
|
|
- [Accounts](./Accounts.md):
|
2020-04-07 23:13:24 +02:00
|
|
|
- `examine` - who may examine the account's properties.
|
|
|
|
|
- `delete` - who may delete the account.
|
|
|
|
|
- `edit` - who may edit the account's attributes and properties.
|
|
|
|
|
- `msg` - who may send messages to the account.
|
|
|
|
|
- `boot` - who may boot the account.
|
2021-10-21 21:04:14 +02:00
|
|
|
- [Attributes](./Attributes.md): (only checked by `obj.secure_attr`)
|
2020-04-07 23:13:24 +02:00
|
|
|
- `attrread` - see/access attribute
|
|
|
|
|
- `attredit` - change/delete attribute
|
2021-10-21 21:04:14 +02:00
|
|
|
- [Channels](./Channels.md):
|
2020-06-16 16:53:35 +02:00
|
|
|
- `control` - who is administrating the channel. This means the ability to delete the channel,
|
|
|
|
|
boot listeners etc.
|
2020-04-07 23:13:24 +02:00
|
|
|
- `send` - who may send to the channel.
|
|
|
|
|
- `listen` - who may subscribe and listen to the channel.
|
2021-10-21 21:04:14 +02:00
|
|
|
- [HelpEntry](./Help-System.md):
|
2020-04-07 23:13:24 +02:00
|
|
|
- `examine` - who may view this help entry (usually everyone)
|
|
|
|
|
- `edit` - who may edit this help entry.
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
So to take an example, whenever an exit is to be traversed, a lock of the type *traverse* will be
|
|
|
|
|
checked. Defining a suitable lock type for an exit object would thus involve a lockstring `traverse:
|
|
|
|
|
<lock functions>`.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
### Custom access_types
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
As stated above, the `access_type` part of the lock is simply the 'name' or 'type' of the lock. The
|
|
|
|
|
text is an arbitrary string that must be unique for an object. If adding a lock with the same
|
|
|
|
|
`access_type` as one that already exists on the object, the new one override the old one.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
For example, if you wanted to create a bulletin board system and wanted to restrict who can either
|
|
|
|
|
read a board or post to a board. You could then define locks such as:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
obj.locks.add("read:perm(Player);post:perm(Admin)")
|
2021-05-23 17:00:02 +02:00
|
|
|
```
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
This will create a 'read' access type for Characters having the `Player` permission or above and a
|
|
|
|
|
'post' access type for those with `Admin` permissions or above (see below how the `perm()` lock
|
|
|
|
|
function works). When it comes time to test these permissions, simply check like this (in this
|
|
|
|
|
example, the `obj` may be a board on the bulletin board system and `accessing_obj` is the player
|
|
|
|
|
trying to read the board):
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
if not obj.access(accessing_obj, 'read'):
|
|
|
|
|
accessing_obj.msg("Sorry, you may not read that.")
|
2021-05-23 17:00:02 +02:00
|
|
|
return
|
2020-04-07 23:13:24 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Lock functions
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
A lock function is a normal Python function put in a place Evennia looks for such functions. The
|
|
|
|
|
modules Evennia looks at is the list `settings.LOCK_FUNC_MODULES`. *All functions* in any of those
|
|
|
|
|
modules will automatically be considered a valid lock function. The default ones are found in
|
|
|
|
|
`evennia/locks/lockfuncs.py` and you can start adding your own in `mygame/server/conf/lockfuncs.py`.
|
|
|
|
|
You can append the setting to add more module paths. To replace a default lock function, just add
|
|
|
|
|
your own with the same name.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
A lock function must always accept at least two arguments - the *accessing object* (this is the
|
|
|
|
|
object wanting to get access) and the *accessed object* (this is the object with the lock). Those
|
|
|
|
|
two are fed automatically as the first two arguments to the function when the lock is checked. Any
|
|
|
|
|
arguments explicitly given in the lock definition will appear as extra arguments.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# A simple example lock function. Called with e.g. `id(34)`. This is
|
|
|
|
|
# defined in, say mygame/server/conf/lockfuncs.py
|
2021-05-23 17:00:02 +02:00
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
def id(accessing_obj, accessed_obj, *args, **kwargs):
|
|
|
|
|
if args:
|
|
|
|
|
wanted_id = args[0]
|
|
|
|
|
return accessing_obj.id == wanted_id
|
2021-05-23 17:00:02 +02:00
|
|
|
return False
|
2020-04-07 23:13:24 +02:00
|
|
|
```
|
|
|
|
|
|
2021-05-23 17:00:02 +02:00
|
|
|
The above could for example be used in a lock function like this:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# we have `obj` and `owner_object` from before
|
2021-10-12 12:13:42 -06:00
|
|
|
obj.locks.add(f"edit: id({owner_object.id})")
|
2020-04-07 23:13:24 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
We could check if the "edit" lock is passed with something like this:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# as part of a Command's func() method, for example
|
|
|
|
|
if not obj.access(caller, "edit"):
|
|
|
|
|
caller.msg("You don't have access to edit this!")
|
|
|
|
|
return
|
|
|
|
|
```
|
|
|
|
|
|
2021-05-23 17:00:02 +02:00
|
|
|
In this example, everyone except the `caller` with the right `id` will get the error.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
> (Using the `*` and `**` syntax causes Python to magically put all extra arguments into a list
|
|
|
|
|
`args` and all keyword arguments into a dictionary `kwargs` respectively. If you are unfamiliar with
|
|
|
|
|
how `*args` and `**kwargs` work, see the Python manuals).
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
Some useful default lockfuncs (see `src/locks/lockfuncs.py` for more):
|
|
|
|
|
|
|
|
|
|
- `true()/all()` - give access to everyone
|
2020-06-16 16:53:35 +02:00
|
|
|
- `false()/none()/superuser()` - give access to none. Superusers bypass the check entirely and are
|
|
|
|
|
thus the only ones who will pass this check.
|
|
|
|
|
- `perm(perm)` - this tries to match a given `permission` property, on an Account firsthand, on a
|
2021-10-21 21:04:14 +02:00
|
|
|
Character second. See [below](./Permissions.md).
|
2020-04-07 23:13:24 +02:00
|
|
|
- `perm_above(perm)` - like `perm` but requires a "higher" permission level than the one given.
|
|
|
|
|
- `id(num)/dbref(num)` - checks so the access_object has a certain dbref/id.
|
2021-10-21 21:04:14 +02:00
|
|
|
- `attr(attrname)` - checks if a certain [Attribute](./Attributes.md) exists on accessing_object.
|
2020-06-16 16:53:35 +02:00
|
|
|
- `attr(attrname, value)` - checks so an attribute exists on accessing_object *and* has the given
|
|
|
|
|
value.
|
|
|
|
|
- `attr_gt(attrname, value)` - checks so accessing_object has a value larger (`>`) than the given
|
|
|
|
|
value.
|
2020-04-07 23:13:24 +02:00
|
|
|
- `attr_ge, attr_lt, attr_le, attr_ne` - corresponding for `>=`, `<`, `<=` and `!=`.
|
|
|
|
|
- `holds(objid)` - checks so the accessing objects contains an object of given name or dbref.
|
2020-06-16 16:53:35 +02:00
|
|
|
- `inside()` - checks so the accessing object is inside the accessed object (the inverse of
|
|
|
|
|
`holds()`).
|
|
|
|
|
- `pperm(perm)`, `pid(num)/pdbref(num)` - same as `perm`, `id/dbref` but always looks for
|
|
|
|
|
permissions and dbrefs of *Accounts*, not on Characters.
|
|
|
|
|
- `serversetting(settingname, value)` - Only returns True if Evennia has a given setting or a
|
|
|
|
|
setting set to a given value.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
## Checking simple strings
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
Sometimes you don't really need to look up a certain lock, you just want to check a lockstring. A
|
|
|
|
|
common use is inside Commands, in order to check if a user has a certain permission. The lockhandler
|
|
|
|
|
has a method `check_lockstring(accessing_obj, lockstring, bypass_superuser=False)` that allows this.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# inside command definition
|
|
|
|
|
if not self.caller.locks.check_lockstring(self.caller, "dummy:perm(Admin)"):
|
|
|
|
|
self.caller.msg("You must be an Admin or higher to do this!")
|
|
|
|
|
return
|
|
|
|
|
```
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
Note here that the `access_type` can be left to a dummy value since this method does not actually do
|
|
|
|
|
a Lock lookup.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
## Default locks
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
Evennia sets up a few basic locks on all new objects and accounts (if we didn't, noone would have
|
2021-10-21 21:04:14 +02:00
|
|
|
any access to anything from the start). This is all defined in the root [Typeclasses](./Typeclasses.md)
|
2020-06-16 16:53:35 +02:00
|
|
|
of the respective entity, in the hook method `basetype_setup()` (which you usually don't want to
|
|
|
|
|
edit unless you want to change how basic stuff like rooms and exits store their internal variables).
|
|
|
|
|
This is called once, before `at_object_creation`, so just put them in the latter method on your
|
|
|
|
|
child object to change the default. Also creation commands like `create` changes the locks of
|
|
|
|
|
objects you create - for example it sets the `control` lock_type so as to allow you, its creator, to
|
|
|
|
|
control and delete the object.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
## More Lock definition examples
|
|
|
|
|
|
|
|
|
|
examine: attr(eyesight, excellent) or perm(Builders)
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
You are only allowed to do *examine* on this object if you have 'excellent' eyesight (that is, has
|
|
|
|
|
an Attribute `eyesight` with the value `excellent` defined on yourself) or if you have the
|
|
|
|
|
"Builders" permission string assigned to you.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-05-23 17:00:02 +02:00
|
|
|
open: holds('the green key') or perm(Builder)
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
This could be called by the `open` command on a "door" object. The check is passed if you are a
|
|
|
|
|
Builder or has the right key in your inventory.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
cmd: perm(Builders)
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
Evennia's command handler looks for a lock of type `cmd` to determine if a user is allowed to even
|
|
|
|
|
call upon a particular command or not. When you define a command, this is the kind of lock you must
|
|
|
|
|
set. See the default command set for lots of examples. If a character/account don't pass the `cmd`
|
|
|
|
|
lock type the command will not even appear in their `help` list.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
cmd: not perm(no_tell)
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
"Permissions" can also be used to block users or implement highly specific bans. The above example
|
|
|
|
|
would be be added as a lock string to the `tell` command. This will allow everyone *not* having the
|
|
|
|
|
"permission" `no_tell` to use the `tell` command. You could easily give an account the "permission"
|
|
|
|
|
`no_tell` to disable their use of this particular command henceforth.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
dbref = caller.id
|
2020-06-16 16:53:35 +02:00
|
|
|
lockstring = "control:id(%s);examine:perm(Builders);delete:id(%s) or perm(Admin);get:all()" %
|
|
|
|
|
(dbref, dbref)
|
2020-04-07 23:13:24 +02:00
|
|
|
new_obj.locks.add(lockstring)
|
|
|
|
|
```
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
This is how the `create` command sets up new objects. In sequence, this permission string sets the
|
|
|
|
|
owner of this object be the creator (the one running `create`). Builders may examine the object
|
|
|
|
|
whereas only Admins and the creator may delete it. Everyone can pick it up.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
## A complete example of setting locks on an object
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
Assume we have two objects - one is ourselves (not superuser) and the other is an [Object](./Objects.md)
|
2020-06-16 16:53:35 +02:00
|
|
|
called `box`.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
> create/drop box
|
|
|
|
|
> desc box = "This is a very big and heavy box."
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
We want to limit which objects can pick up this heavy box. Let's say that to do that we require the
|
|
|
|
|
would-be lifter to to have an attribute *strength* on themselves, with a value greater than 50. We
|
|
|
|
|
assign it to ourselves to begin with.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
> set self/strength = 45
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
Ok, so for testing we made ourselves strong, but not strong enough. Now we need to look at what
|
|
|
|
|
happens when someone tries to pick up the the box - they use the `get` command (in the default set).
|
|
|
|
|
This is defined in `evennia/commands/default/general.py`. In its code we find this snippet:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
if not obj.access(caller, 'get'):
|
|
|
|
|
if obj.db.get_err_msg:
|
|
|
|
|
caller.msg(obj.db.get_err_msg)
|
|
|
|
|
else:
|
|
|
|
|
caller.msg("You can't get that.")
|
|
|
|
|
return
|
|
|
|
|
```
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
So the `get` command looks for a lock with the type *get* (not so surprising). It also looks for an
|
2021-10-21 21:04:14 +02:00
|
|
|
[Attribute](./Attributes.md) on the checked object called _get_err_msg_ in order to return a customized
|
2020-06-16 16:53:35 +02:00
|
|
|
error message. Sounds good! Let's start by setting that on the box:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
> set box/get_err_msg = You are not strong enough to lift this box.
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
Next we need to craft a Lock of type *get* on our box. We want it to only be passed if the accessing
|
|
|
|
|
object has the attribute *strength* of the right value. For this we would need to create a lock
|
|
|
|
|
function that checks if attributes have a value greater than a given value. Luckily there is already
|
|
|
|
|
such a one included in evennia (see `evennia/locks/lockfuncs.py`), called `attr_gt`.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
2021-05-23 17:00:02 +02:00
|
|
|
So the lock string will look like this: `get:attr_gt(strength, 50)`. We put this on the box now:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
lock box = get:attr_gt(strength, 50)
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
Try to `get` the object and you should get the message that we are not strong enough. Increase your
|
|
|
|
|
strength above 50 however and you'll pick it up no problem. Done! A very heavy box!
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
If you wanted to set this up in python code, it would look something like this:
|
|
|
|
|
|
|
|
|
|
```python
|
2021-05-23 17:00:02 +02:00
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
from evennia import create_object
|
2021-05-23 17:00:02 +02:00
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
# create, then set the lock
|
|
|
|
|
box = create_object(None, key="box")
|
|
|
|
|
box.locks.add("get:attr_gt(strength, 50)")
|
2021-05-23 17:00:02 +02:00
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
# or we can assign locks in one go right away
|
|
|
|
|
box = create_object(None, key="box", locks="get:attr_gt(strength, 50)")
|
2021-05-23 17:00:02 +02:00
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
# set the attributes
|
|
|
|
|
box.db.desc = "This is a very big and heavy box."
|
|
|
|
|
box.db.get_err_msg = "You are not strong enough to lift this box."
|
2021-05-23 17:00:02 +02:00
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
# one heavy box, ready to withstand all but the strongest...
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## On Django's permission system
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
Django also implements a comprehensive permission/security system of its own. The reason we don't
|
|
|
|
|
use that is because it is app-centric (app in the Django sense). Its permission strings are of the
|
|
|
|
|
form `appname.permstring` and it automatically adds three of them for each database model in the app
|
|
|
|
|
- for the app evennia/object this would be for example 'object.create', 'object.admin' and
|
|
|
|
|
'object.edit'. This makes a lot of sense for a web application, not so much for a MUD, especially
|
|
|
|
|
when we try to hide away as much of the underlying architecture as possible.
|
|
|
|
|
|
|
|
|
|
The django permissions are not completely gone however. We use it for validating passwords during
|
|
|
|
|
login. It is also used exclusively for managing Evennia's web-based admin site, which is a graphical
|
|
|
|
|
front-end for the database of Evennia. You edit and assign such permissions directly from the web
|
2021-05-23 17:00:02 +02:00
|
|
|
interface. It's stand-alone from the permissions described above.
|