mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 05:46:31 +01:00
| .. | ||
| __init__.py | ||
| command.py | ||
| evlang.py | ||
| examples.py | ||
| objects.py | ||
| README | ||
EVLANG
EXPERIMENTAL IMPLEMENTATION
Evennia contribution - Griatch 2012
"Evlang" is a heavily restricted version of Python intended to be used
by regular players to code simple functionality on supporting objects.
It's referred to as "evlang" or "evlang scripts" in order to
differentiate from Evennia's normal (and unrelated) "Scripts".
WARNING:
Restricted python execution is a tricky art, and this module -is-
partly based on blacklisting techniques, which might be vulnerable to
new venues of attack opening up in the future (or existing ones we've
missed). Whereas I/we know of no obvious exploits to this, it is no
guarantee. If you are paranoid about security, consider also using
secondary defences on the OS level such as a jail and highly
restricted execution abilities for the twisted process. So in short,
this should work fine, but use it at your own risk. You have been
warned.
An Evennia server with Evlang will, once set up, minimally consist of
the following components:
- The evlang parser (bottom of evlang.py). This combines
regular removal of dangerous modules/builtins with AST-traversal.
it implements a limited_exec() function.
- The Evlang handler (top of evlang.py). This handler is the Evennia
entry point. It should be added to objects that should support
evlang-scripting.
- A custom object typeclass. This must set up the Evlang handler
and store a few critical Attributes on itself for book-keeping.
The object will probably also overload some of its hooks to
call the correct evlang script at the proper time
- Command(s) for adding code to supporting objects
- Optional expanded "safe" methods/objects to include in the
execution environment. These are defined in settings (see
header of evlang.py for more info).
You can set this up easily to try things out by using the included
examples:
Quick Example Install
---------------------
This is a quick test-setup using the example objects and commands.
1) If you haven't already, make sure you are able to overload the
default cmdset: Copy game/gamesrc/commands/examples/cmdset.py up
one level, then change settings.CMDSET_DEFAULT to point to
DefaultCmdSet in your newly copied module. Restart the server and
check so the default commands still work.
2) Import and add
contrib.evlang.command.CmdCode
and
contrib.evlang.examples.CmdCraftScriptable
to your default command set. Reload server.
That's it, really. You should now have two new commands available,
@craftscriptable and @code. The first one is a simple "crafting-like"
command that will create an object of type
contrib.evlang.examples.CraftedScriptableObject while setting it up
with some basic scripting slots.
Try it now:
@craftscriptable crate
You create a simple "crate" object in your current location. You can
use @code to see which "code types" it will accept.
@code crate
You should see a list with "drop", "get" and "look", each without
anything assigned to them. If you look at how CraftedScriptableObject
is defined you will find that these "command types" (you can think of
them as slots where custom code can be put) are tied to the at_get,
at_drop and at_desc hooks respecively - this means Evlang scripts put
in the respective slots will ttrigger at the appropriate time.
There are a few "safe" objects made available out of the box.
self - reference to object the Evlang handler is defined on
here - shortcut for self.location
caller - reference back to the one triggering the script
scripter - reference to the one creating the script (set by @code)
There is also the 'evl' object that defines "safe" methods to use:
evl.msg(string, obj=None) # default is the send to caller
evl.msg_contents(string, obj=None) # default is to send to all except caller
evl.msg_home(string, obj=None) # default is to send to self.location
delay(delay, function, *args, **kwargs)
attr(obj, attrname=None, attrvalue=None, delete=False) # lock-checking attribute accesser
list() # display all available methods on evl, with docstrings (including your custom additions)
These all return True after successful execution, which makes
especially the msg* functions easier to use in a conditional. Let's
try it.
@code crate/look = caller.key=='Superman' and evl.msg("Your gaze burns a small hole.") or evl.msg("Looks robust!")
Now look at the crate. :)
You can (in evlang) use evl.list() to get a list of all methods
currently stored on the evl object. For testing, let's use the same
look slot on the crate again. But this time we'll use the /debug mode
of @code, which means the script will be auto-run immediately and we
don't have to look at the create to get a result when developing.
@code/debug crate/look = evl.msg(evl.list())