master #2

Merged
AliasAlreadyTaken merged 7 commits from master into yl_stable 2025-03-25 16:49:07 +01:00
3 changed files with 131 additions and 5 deletions

View File

@ -59,6 +59,8 @@ Some special variables are provided:
- `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
@ -135,3 +137,20 @@ already existed.
> 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
```

View File

@ -119,4 +119,35 @@ local function repl_dump(o, indent, nested, level)
return "{"..table.concat(ret, ", ").."}"
end
return repl_dump
local function dump_dir(o)
-- dump only top-level key = value pairs
local t = type(o)
if t ~= "table" then
return basic_dump(o)
end
local ret = {}
local dumped_indexes = {}
for i, v in ipairs(o) do
ret[#ret + 1] = string.format("[%s] = %s", i, basic_dump(v))
dumped_indexes[i] = true
end
for k, v in pairs(o) do
if not dumped_indexes[k] then
if type(k) ~= "string" or not is_valid_identifier(k) then
k = "["..basic_dump(k).."]"
end
v = basic_dump(v)
ret[#ret + 1] = k.." = "..v
end
end
return "{\n "..table.concat(ret, ",\n ").."\n}"
end
local dump_funcs = {
repl_dump = repl_dump,
dump_dir = dump_dir,
}
return dump_funcs

View File

@ -2,7 +2,9 @@ local MODNAME = core.get_current_modname()
local MODPATH = core.get_modpath(MODNAME)
local util = dofile(MODPATH .. DIR_DELIM .. "util.lua")
local repl_dump = dofile(MODPATH .. DIR_DELIM .. "dump.lua")
local dump_funcs = dofile(MODPATH .. DIR_DELIM .. "dump.lua")
local repl_dump = dump_funcs.repl_dump
local dump_dir = dump_funcs.dump_dir
local api = {}
_G[MODNAME] = api
@ -55,6 +57,25 @@ local function create_shared_environment(player_name)
end
return vector.round(me:get_pos())
end,
help = function()
local msg = [[
# Variables:
me -- your player object
my_pos -- your position
here -- your position where command was executed at (does not change)
point -- the exact pos you're pointing with the crosshair
this_obj -- the obj you're pointing at with the crosshair or nil
this_node_pos -- the node position you're pointing at
global -- actual global environment (same as _G)
# Functions:
dir(t) -- print table key/values (returns nothing)
keys(t) -- print table keys (returns nothing)
goir(radius) -- return list of objects around you
oir(radius) -- return iterator for objects around you
]]
core.chat_send_player(player_name, msg)
end,
}
local g = {} -- "do not warn again" flags
@ -75,8 +96,12 @@ local function create_shared_environment(player_name)
local eval_env = setmetatable(
{
--global = _G, -- this works, but dumps whole global env if you just print `cmd_eval` value
_G = global_proxy, -- use our proxy to get warnings
global = global_proxy, -- just a different name for globals
my_name = player_name,
print = function(...)
-- print to chat, instead of console
local msg = '< '
for i = 1, select('#', ...) do
if i > 1 then msg = msg .. '\t' end
@ -84,10 +109,58 @@ local function create_shared_environment(player_name)
end
core.chat_send_player(player_name, msg)
end,
--global = _G, -- this works, but dumps whole global env if you just print `cmd_eval` value
_G = global_proxy, -- use our proxy to get warnings
global = global_proxy, -- just a different name for globals
dir = function(o)
core.chat_send_player(player_name, dump_dir(o))
end,
keys = function(o)
-- collect all keys of the table, no values
if type(o) == "table" then
local keys = {}
for k, _ in pairs(o) do
local key = k
local t = type(key)
if t == "string" then
key = '"' .. key .. '"'
elseif t == "number" then
key = '[' .. key .. ']'
else
key = '[' .. tostring(key) .. ']'
end
table.insert(keys, key)
end
table.sort(keys)
core.chat_send_player(player_name, table.concat(keys, ',\n'))
else
core.chat_send_player(player_name, string.format("Not a table: %s", dump(t)))
end
end,
--dump = repl_dump,
goir = function(radius)
local me = core.get_player_by_name(player_name)
if me then
local objs = core.get_objects_inside_radius(me:get_pos(), radius)
return objs
else
return {}
end
end,
oir = function(radius)
local me = core.get_player_by_name(player_name)
if me then
local objs = core.get_objects_inside_radius(me:get_pos(), radius)
local nextkey, v
--local i = 1
return function()
-- FIXME skip invalid objects here?
nextkey, v = next(objs, nextkey)
return v
-- i = i + 1
-- return objs[i]
end
else
return function() return nil end
end
end,
},
{
__index = function(self, key)
@ -123,6 +196,9 @@ local function create_command_environment(player_name)
local me = core.get_player_by_name(player_name)
local here = me:get_pos()
local cmd_env = {
-- This is a special _per-command_ environment.
-- The rationale is: each command should have it's own "here"
-- It may matter when we start long-running tasks or something.
here = here,
}
setmetatable(