mirror of
https://github.com/minetest/minetest.git
synced 2024-11-26 17:43:45 +01:00
Add Lua API function to resolve node/collision/selection boxes (#13964)
This commit is contained in:
parent
4859cf44ce
commit
f2b99332d9
@ -6183,6 +6183,17 @@ Environment access
|
||||
* increase level of leveled node by level, default `level` equals `1`
|
||||
* if `totallevel > maxlevel`, returns rest (`total-max`)
|
||||
* `level` must be between -127 and 127
|
||||
* `minetest.get_node_boxes(box_type, pos, [node])`
|
||||
* `box_type` must be `"node_box"`, `"collision_box"` or `"selection_box"`.
|
||||
* `pos` must be a node position.
|
||||
* `node` can be a table in the form `{name=string, param1=number, param2=number}`.
|
||||
If `node` is `nil`, the actual node at `pos` is used instead.
|
||||
* Resolves any facedir-rotated boxes, connected boxes and the like into
|
||||
actual boxes.
|
||||
* Returns a list of boxes in the form
|
||||
`{{x1, y1, z1, x2, y2, z2}, {x1, y1, z1, x2, y2, z2}, ...}`. Coordinates
|
||||
are relative to `pos`.
|
||||
* See also: [Node boxes](#node-boxes)
|
||||
* `minetest.fix_light(pos1, pos2)`: returns `true`/`false`
|
||||
* resets the light in a cuboid-shaped part of
|
||||
the map and removes lighting bugs.
|
||||
|
@ -6,6 +6,7 @@ testtools = {}
|
||||
dofile(minetest.get_modpath("testtools") .. "/light.lua")
|
||||
dofile(minetest.get_modpath("testtools") .. "/privatizer.lua")
|
||||
dofile(minetest.get_modpath("testtools") .. "/particles.lua")
|
||||
dofile(minetest.get_modpath("testtools") .. "/node_box_visualizer.lua")
|
||||
|
||||
local pointabilities_nodes = {
|
||||
nodes = {
|
||||
|
79
games/devtest/mods/testtools/node_box_visualizer.lua
Normal file
79
games/devtest/mods/testtools/node_box_visualizer.lua
Normal file
@ -0,0 +1,79 @@
|
||||
local S = minetest.get_translator("testtools")
|
||||
|
||||
minetest.register_entity("testtools:visual_box", {
|
||||
initial_properties = {
|
||||
visual = "cube",
|
||||
textures = {
|
||||
"blank.png", "blank.png", "blank.png",
|
||||
"blank.png", "blank.png", "blank.png",
|
||||
},
|
||||
use_texture_alpha = true,
|
||||
physical = false,
|
||||
pointable = false,
|
||||
static_save = false,
|
||||
},
|
||||
|
||||
on_activate = function(self)
|
||||
self.timestamp = minetest.get_us_time() + 5000000
|
||||
end,
|
||||
|
||||
on_step = function(self)
|
||||
if minetest.get_us_time() >= self.timestamp then
|
||||
self.object:remove()
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
local BOX_TYPES = {"node_box", "collision_box", "selection_box"}
|
||||
local DEFAULT_BOX_TYPE = "selection_box"
|
||||
|
||||
local function visualizer_on_use(itemstack, user, pointed_thing)
|
||||
if pointed_thing.type ~= "node" then
|
||||
return
|
||||
end
|
||||
|
||||
local meta = itemstack:get_meta()
|
||||
local box_type = meta:get("box_type") or DEFAULT_BOX_TYPE
|
||||
|
||||
local result = minetest.get_node_boxes(box_type, pointed_thing.under)
|
||||
local t = "testtools_visual_" .. box_type .. ".png"
|
||||
|
||||
for _, box in ipairs(result) do
|
||||
local box_min = pointed_thing.under + vector.new(box[1], box[2], box[3])
|
||||
local box_max = pointed_thing.under + vector.new(box[4], box[5], box[6])
|
||||
local box_center = (box_min + box_max) / 2
|
||||
local obj = minetest.add_entity(box_center, "testtools:visual_box")
|
||||
if not obj then
|
||||
break
|
||||
end
|
||||
obj:set_properties({
|
||||
textures = {t, t, t, t, t, t},
|
||||
-- Add a small offset to avoid Z-fighting.
|
||||
visual_size = vector.add(box_max - box_min, 0.01),
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local function visualizer_on_place(itemstack, placer, pointed_thing)
|
||||
local meta = itemstack:get_meta()
|
||||
local prev_value = meta:get("box_type") or DEFAULT_BOX_TYPE
|
||||
local prev_index = table.indexof(BOX_TYPES, prev_value)
|
||||
assert(prev_index ~= -1)
|
||||
|
||||
local new_value = BOX_TYPES[(prev_index % #BOX_TYPES) + 1]
|
||||
meta:set_string("box_type", new_value)
|
||||
minetest.chat_send_player(placer:get_player_name(), S("[Node Box Visualizer] box_type = @1", new_value))
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
minetest.register_tool("testtools:node_box_visualizer", {
|
||||
description = S("Node Box Visualizer") .. "\n" ..
|
||||
S("Punch: Show node/collision/selection boxes of the pointed node") .. "\n" ..
|
||||
S("Place: Change selected box type (default: selection box)"),
|
||||
inventory_image = "testtools_node_box_visualizer.png",
|
||||
groups = { testtool = 1, disable_repair = 1 },
|
||||
on_use = visualizer_on_use,
|
||||
on_place = visualizer_on_place,
|
||||
on_secondary_use = visualizer_on_place,
|
||||
})
|
Binary file not shown.
After Width: | Height: | Size: 108 B |
Binary file not shown.
After Width: | Height: | Size: 119 B |
Binary file not shown.
After Width: | Height: | Size: 124 B |
Binary file not shown.
After Width: | Height: | Size: 121 B |
@ -1110,7 +1110,7 @@ void push_nodebox(lua_State *L, const NodeBox &box)
|
||||
case NODEBOX_FIXED:
|
||||
lua_pushstring(L, "fixed");
|
||||
lua_setfield(L, -2, "type");
|
||||
push_box(L, box.fixed);
|
||||
push_aabb3f_vector(L, box.fixed);
|
||||
lua_setfield(L, -2, "fixed");
|
||||
break;
|
||||
case NODEBOX_WALLMOUNTED:
|
||||
@ -1127,17 +1127,17 @@ void push_nodebox(lua_State *L, const NodeBox &box)
|
||||
lua_pushstring(L, "connected");
|
||||
lua_setfield(L, -2, "type");
|
||||
const auto &c = box.getConnected();
|
||||
push_box(L, c.connect_top);
|
||||
push_aabb3f_vector(L, c.connect_top);
|
||||
lua_setfield(L, -2, "connect_top");
|
||||
push_box(L, c.connect_bottom);
|
||||
push_aabb3f_vector(L, c.connect_bottom);
|
||||
lua_setfield(L, -2, "connect_bottom");
|
||||
push_box(L, c.connect_front);
|
||||
push_aabb3f_vector(L, c.connect_front);
|
||||
lua_setfield(L, -2, "connect_front");
|
||||
push_box(L, c.connect_back);
|
||||
push_aabb3f_vector(L, c.connect_back);
|
||||
lua_setfield(L, -2, "connect_back");
|
||||
push_box(L, c.connect_left);
|
||||
push_aabb3f_vector(L, c.connect_left);
|
||||
lua_setfield(L, -2, "connect_left");
|
||||
push_box(L, c.connect_right);
|
||||
push_aabb3f_vector(L, c.connect_right);
|
||||
lua_setfield(L, -2, "connect_right");
|
||||
// half the boxes are missing here?
|
||||
break;
|
||||
@ -1148,16 +1148,6 @@ void push_nodebox(lua_State *L, const NodeBox &box)
|
||||
}
|
||||
}
|
||||
|
||||
void push_box(lua_State *L, const std::vector<aabb3f> &box)
|
||||
{
|
||||
lua_createtable(L, box.size(), 0);
|
||||
u8 i = 1;
|
||||
for (const aabb3f &it : box) {
|
||||
push_aabb3f(L, it);
|
||||
lua_rawseti(L, -2, i++);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void push_palette(lua_State *L, const std::vector<video::SColor> *palette)
|
||||
{
|
||||
|
@ -83,9 +83,6 @@ void push_content_features (lua_State *L,
|
||||
|
||||
void push_nodebox (lua_State *L,
|
||||
const NodeBox &box);
|
||||
void push_box (lua_State *L,
|
||||
const std::vector<aabb3f> &box);
|
||||
|
||||
void push_palette (lua_State *L,
|
||||
const std::vector<video::SColor> *palette);
|
||||
|
||||
|
@ -364,20 +364,20 @@ aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
|
||||
return box;
|
||||
}
|
||||
|
||||
void push_aabb3f(lua_State *L, aabb3f box)
|
||||
void push_aabb3f(lua_State *L, aabb3f box, f32 divisor)
|
||||
{
|
||||
lua_createtable(L, 6, 0);
|
||||
lua_pushnumber(L, box.MinEdge.X);
|
||||
lua_pushnumber(L, box.MinEdge.X / divisor);
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pushnumber(L, box.MinEdge.Y);
|
||||
lua_pushnumber(L, box.MinEdge.Y / divisor);
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_pushnumber(L, box.MinEdge.Z);
|
||||
lua_pushnumber(L, box.MinEdge.Z / divisor);
|
||||
lua_rawseti(L, -2, 3);
|
||||
lua_pushnumber(L, box.MaxEdge.X);
|
||||
lua_pushnumber(L, box.MaxEdge.X / divisor);
|
||||
lua_rawseti(L, -2, 4);
|
||||
lua_pushnumber(L, box.MaxEdge.Y);
|
||||
lua_pushnumber(L, box.MaxEdge.Y / divisor);
|
||||
lua_rawseti(L, -2, 5);
|
||||
lua_pushnumber(L, box.MaxEdge.Z);
|
||||
lua_pushnumber(L, box.MaxEdge.Z / divisor);
|
||||
lua_rawseti(L, -2, 6);
|
||||
}
|
||||
|
||||
@ -409,6 +409,16 @@ std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
|
||||
return boxes;
|
||||
}
|
||||
|
||||
void push_aabb3f_vector(lua_State *L, const std::vector<aabb3f> &boxes, f32 divisor)
|
||||
{
|
||||
lua_createtable(L, boxes.size(), 0);
|
||||
int i = 1;
|
||||
for (const aabb3f &box : boxes) {
|
||||
push_aabb3f(L, box, divisor);
|
||||
lua_rawseti(L, -2, i++);
|
||||
}
|
||||
}
|
||||
|
||||
size_t read_stringlist(lua_State *L, int index, std::vector<std::string> *result)
|
||||
{
|
||||
if (index < 0)
|
||||
|
@ -110,11 +110,13 @@ void push_v2s16 (lua_State *L, v2s16 p);
|
||||
void push_v2s32 (lua_State *L, v2s32 p);
|
||||
void push_v2u32 (lua_State *L, v2u32 p);
|
||||
void push_v3s16 (lua_State *L, v3s16 p);
|
||||
void push_aabb3f (lua_State *L, aabb3f box);
|
||||
void push_aabb3f (lua_State *L, aabb3f box, f32 divisor = 1.0f);
|
||||
void push_ARGB8 (lua_State *L, video::SColor color);
|
||||
void pushFloatPos (lua_State *L, v3f p);
|
||||
void push_v3f (lua_State *L, v3f p);
|
||||
void push_v2f (lua_State *L, v2f p);
|
||||
void push_aabb3f_vector (lua_State *L, const std::vector<aabb3f> &boxes,
|
||||
f32 divisor = 1.0f);
|
||||
|
||||
void warn_if_field_exists(lua_State *L, int table,
|
||||
const char *fieldname,
|
||||
|
@ -562,6 +562,40 @@ int ModApiEnv::l_add_node_level(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// get_node_boxes(box_type, pos, [node]) -> table
|
||||
// box_type = string
|
||||
// pos = {x=num, y=num, z=num}
|
||||
// node = {name=string, param1=num, param2=num} or nil
|
||||
int ModApiEnv::l_get_node_boxes(lua_State *L)
|
||||
{
|
||||
GET_ENV_PTR;
|
||||
|
||||
std::string box_type = luaL_checkstring(L, 1);
|
||||
v3s16 pos = read_v3s16(L, 2);
|
||||
MapNode n;
|
||||
if (lua_istable(L, 3))
|
||||
n = readnode(L, 3);
|
||||
else
|
||||
n = env->getMap().getNode(pos);
|
||||
|
||||
u8 neighbors = n.getNeighbors(pos, &env->getMap());
|
||||
const NodeDefManager *ndef = env->getGameDef()->ndef();
|
||||
|
||||
std::vector<aabb3f> boxes;
|
||||
if (box_type == "node_box")
|
||||
n.getNodeBoxes(ndef, &boxes, neighbors);
|
||||
else if (box_type == "collision_box")
|
||||
n.getCollisionBoxes(ndef, &boxes, neighbors);
|
||||
else if (box_type == "selection_box")
|
||||
n.getSelectionBoxes(ndef, &boxes, neighbors);
|
||||
else
|
||||
luaL_error(L, "get_node_boxes: box_type is invalid. Allowed values: \"node_box\", \"collision_box\", \"selection_box\"");
|
||||
|
||||
push_aabb3f_vector(L, boxes, BS);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// find_nodes_with_meta(pos1, pos2)
|
||||
int ModApiEnv::l_find_nodes_with_meta(lua_State *L)
|
||||
{
|
||||
@ -1456,6 +1490,7 @@ void ModApiEnv::Initialize(lua_State *L, int top)
|
||||
API_FCT(get_node_level);
|
||||
API_FCT(set_node_level);
|
||||
API_FCT(add_node_level);
|
||||
API_FCT(get_node_boxes);
|
||||
API_FCT(add_entity);
|
||||
API_FCT(find_nodes_with_meta);
|
||||
API_FCT(get_meta);
|
||||
|
@ -120,6 +120,12 @@ private:
|
||||
// pos = {x=num, y=num, z=num}
|
||||
static int l_add_node_level(lua_State *L);
|
||||
|
||||
// get_node_boxes(box_type, pos, [node]) -> table
|
||||
// box_type = string
|
||||
// pos = {x=num, y=num, z=num}
|
||||
// node = {name=string, param1=num, param2=num} or nil
|
||||
static int l_get_node_boxes(lua_State *L);
|
||||
|
||||
// find_nodes_with_meta(pos1, pos2)
|
||||
static int l_find_nodes_with_meta(lua_State *L);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user