mirror of
https://github.com/evennia/evennia.git
synced 2026-03-19 06:16:31 +01:00
114 lines
4.7 KiB
Text
114 lines
4.7 KiB
Text
|
|
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())
|
|
|