## Adds `/eval` command `/eval` takes lua code as argument and executes it. It will echo your command and show it's output and returned value. Each player gets their own "global" environment so they can't interfere with other user's envs by accident (exposed as `cmd_eval.e[player_name]`). ## Some nice features: ### Expression/statement agnostic This command: ``` /eval 1+2 ``` Outputs this: ``` > 1+2 | 3 ``` This also just works: ``` > x = 2*2 > x | 4 ``` Multiple values also work: ``` > return 1,nil,3 | 1, | nil, | 3 ``` ### Backtrace and error output Outputs both the error and clean backtrace (stack related only to provided code) ### Print function No need to use `core.chat_send_player()`, just use `print()` - it will do the right thing. ``` > print(here) < (-98.0, 15.5, 33.4) ``` ``` > objs = core.get_objects_inside_radius(here, 10) > for i,o in ipairs(objs) do print(i, (o:get_luaentity() or {}).name, o:get_pos()) end < 1 nil (-98.0, 15.5, 33.4) < 2 mobs_animal:kitten (-101.0, 16.5, 30.0) < 3 mobs_animal:chicken (-92.0, 15.5, 34.2) ``` ### "Magic" variables Some special variables are provided: - `here` - position where you executed the command - `me` - your player object - `point` - point in the world you're pointing at with your crosshair - `this_obj` - entity you're pointing at (can be `nil`) Do `/eval help` to get a quick reminder of these vars and functions. ### Better output for arrays and some `userdata` objects ``` > me | # ``` Show indices for easier manual access: ``` > core.get_objects_inside_radius(here, 10) | { | [1] = #, | [2] = #, | [3] = #, | } ``` ### Keeping result of last /eval in `_` variable ``` > core.get_objects_inside_radius(here, 10) | { | [1] = #, | [2] = #, | } > _[2] | # > pos = _:get_pos() > pos | { | x = 123.5, | y = 15.0, | z = 68.4 | } ``` ### Accessing and changing global variables You can save some keypresses by not typing `local` in front of every variable. Assigning to globals won't clobber them, instead using your personal environment. But you can still read globals as usual. ``` > print(myvar) * Accessing undeclared variable: "myvar" < nil > myvar = 1 | Done. > print(myvar) < 1 | Done. ``` If you want to create a new global or actually overwrite existing one, you can access global environment through usual `_G` or `global` variables. Using them will print a message telling you if global var already existed. ``` > cmd_eval = nil | Done. > cmd_eval -- accesses real global { e = { ... }, ... } > global.cmd_eval = nil * Overwriting global: "cmd_eval" | Done. > cmd_eval | nil -- wiped for real ``` ### Other shortcuts #### `dir()` and `keys()` List keys of the table (useful for exploring data structures, without flooding your chat). #### `get_objects_inside_radius()` shortcuts: `goir()` and `oir()` `goir(radius)` returns a list of objects around you `oir(radius)` returns an iterator of objects around you ``` > goir(100) -- return a list of objects within 100 units around you > for v in oir(100) do print((v:get_luaentity() or {}).name) end ``` ### Coroutine support You can call `yield(...)` inside the code you're evaluating. The yielded value will be displayed, same as normal returned value, but you will also be able to resume the computation by typing `/eval_resume`: ``` > for i=1,3 do yield(i) end | 1 * coroutine suspended, type /eval_resume to continue /eval_resume * resuming... | 2 * coroutine suspended, type /eval_resume to continue /eval_resume * resuming... | 3 * coroutine suspended, type /eval_resume to continue /eval_resume | Done. /eval_resume * resuming... * Nothing to resume ``` This can allow you for some shortcuts, for example, visiting all players: ``` /eval for p in players do me:move_to(p:get_pos()); yield() end ``` type `/eval_resume` to visit next one. Keep in mind that while the coroutine is paused, it's enviroment can change (tables can be modified, some object refs can become invalid etc.) ### Forspec output/input #### `fsdump(value)` Evaluate `fsdump(value)` to show the value in a formspec instead of chat window. This will allow you to select and copy the dumped text, and also keep your chat history from getting spammed. You can call this multiple times, inside a loop, etc. The computation will be paused (see "coroutine support"). If you close the dump window with ESC or `x` button, the computation will remain paused, and can be resumed by typing `/eval_resume`. If you push `resume` formspec button, it will be resumed normally. #### `fsinput(label, text)` Evaluate t`fsinput()` (arguments are optional) to open a formspec where you can input some text. The text you enter will be passed back to the coroutine as a return value of the `fsinput()` call. For example: `/eval core.get_meta(under):set_string('infotext',fsinput())` Will open a window that will let you to edit the `infotext` meta field of the node you're pointing at. Or, same thing, but fancier, showing existing infotext in a formspec: `/eval local m = core.get_meta(under); m:set_string('infotext',fsinput('infotext', m:get_string('infotext')))` If you close `fsinput()` formspec without pusing `send` button, the computation _will not_ be resumed. You can still resume it by typing `/eval_resume ` - the argument text will be passed instead of the context of text area of the formspec.