mirror of
https://github.com/pyrollo/display_modpack.git
synced 2024-11-14 14:20:31 +01:00
157 lines
4.7 KiB
Lua
157 lines
4.7 KiB
Lua
|
-- Display lib mod by P.Y. Rollo
|
||
|
--
|
||
|
-- License: WTFPL
|
||
|
|
||
|
display_lib = {}
|
||
|
|
||
|
-- Miscelaneous values depending on wallmounted param2
|
||
|
local wallmounted_values = {
|
||
|
[0]={dx=0, dz=0, lx=0, lz=0, yaw=0, rotate=0}, -- Should never be used
|
||
|
{dx=1, dz=0, lx=0, lz=0, yaw=0, rotate=1}, -- Should never be used
|
||
|
{dx=1, dz=0, lx=0, lz=-1, yaw=-math.pi/2, rotate=4},
|
||
|
{dx=-1, dz=0, lx=0, lz=1, yaw=math.pi/2, rotate=5},
|
||
|
{dx=0, dz=1, lx=1, lz=0, yaw=0, rotate=3},
|
||
|
{dx=0, dz=-1, lx=-1, lz=0, yaw=math.pi, rotate=2}
|
||
|
}
|
||
|
|
||
|
--- Gets the display entities attached with a node. Removes extra ones
|
||
|
local function get_entities(pos)
|
||
|
local objrefs = {}
|
||
|
local ndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||
|
if ndef and ndef.display_entities then
|
||
|
for _, objref in ipairs(minetest.get_objects_inside_radius(pos, 0.5)) do
|
||
|
local entity = objref:get_luaentity()
|
||
|
if entity and ndef.display_entities[entity.name] then
|
||
|
if objrefs[entity.name] then
|
||
|
objref:remove()
|
||
|
else
|
||
|
objrefs[entity.name] = objref
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
return objrefs
|
||
|
end
|
||
|
|
||
|
local function clip_pos_prop(posprop)
|
||
|
if posprop then
|
||
|
return math.max(-0.5, math.min(0.5, posprop))
|
||
|
else
|
||
|
return 0
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- (Create and) place display entities according to the node orientation
|
||
|
local function place_entities(pos)
|
||
|
local node = minetest.get_node(pos)
|
||
|
local ndef = minetest.registered_nodes[node.name]
|
||
|
local values = wallmounted_values[node.param2]
|
||
|
local objrefs = get_entities(pos)
|
||
|
|
||
|
if ndef and ndef.display_entities then
|
||
|
for entity_name, props in pairs(ndef.display_entities) do
|
||
|
local depth = clip_pos_prop(props.depth)
|
||
|
local top = clip_pos_prop(props.top)
|
||
|
local left = clip_pos_prop(props.left)
|
||
|
|
||
|
if not objrefs[entity_name] then
|
||
|
objrefs[entity_name] = minetest.add_entity(pos, entity_name)
|
||
|
end
|
||
|
|
||
|
objrefs[entity_name]:setpos({
|
||
|
x = pos.x - values.dx * depth + values.lx * left,
|
||
|
y = pos.y + top,
|
||
|
z = pos.z - values.dz * depth + values.lz * left})
|
||
|
|
||
|
objrefs[entity_name]:setyaw(values.yaw)
|
||
|
end
|
||
|
end
|
||
|
return objrefs
|
||
|
end
|
||
|
|
||
|
--- Call on_display_update callback of a node for one of its display entities
|
||
|
local function call_node_on_display_update(pos, objref)
|
||
|
local ndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||
|
local entity = objref:get_luaentity()
|
||
|
if ndef and ndef.display_entities and entity and ndef.display_entities[entity.name] then
|
||
|
ndef.display_entities[entity.name].on_display_update(pos, objref)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- Force entity update
|
||
|
function display_lib.update_entities(pos)
|
||
|
local objrefs = place_entities(pos)
|
||
|
for _, objref in pairs(objrefs) do
|
||
|
call_node_on_display_update(pos, objref)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- On_activate callback for display_lib entities. Calls on_display_update callbacks
|
||
|
--- of corresponding node for each entity.
|
||
|
function display_lib.on_activate(entity, staticdata)
|
||
|
if entity then
|
||
|
call_node_on_display_update(entity.object:getpos(), entity.object)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- On_place callback for display_lib items. Does nothing more than preventing item
|
||
|
--- from being placed on ceiling or ground
|
||
|
function display_lib.on_place(itemstack, placer, pointed_thing)
|
||
|
local above = pointed_thing.above
|
||
|
local under = pointed_thing.under
|
||
|
local dir = {x = under.x - above.x,
|
||
|
y = under.y - above.y,
|
||
|
z = under.z - above.z}
|
||
|
local wdir = minetest.dir_to_wallmounted(dir)
|
||
|
|
||
|
if wdir == 0 or wdir == 1 then
|
||
|
dir = placer:get_look_dir()
|
||
|
dir.y = 0
|
||
|
wdir = minetest.dir_to_wallmounted(dir)
|
||
|
end
|
||
|
return minetest.item_place(itemstack, placer, pointed_thing, wdir)
|
||
|
end
|
||
|
|
||
|
--- On_construct callback for display_lib items. Creates entities and update them.
|
||
|
function display_lib.on_construct(pos)
|
||
|
display_lib.update_entities(pos)
|
||
|
end
|
||
|
|
||
|
--- On_destruct callback for display_lib items. Removes entities.
|
||
|
function display_lib.on_destruct(pos)
|
||
|
local objrefs = get_entities(pos)
|
||
|
|
||
|
for _, objref in pairs(objrefs) do
|
||
|
objref:remove()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
-- On_rotate (screwdriver) callback for display_lib items. Prevents axis rotation and reorients entities.
|
||
|
function display_lib.on_rotate(pos, node, user, mode, new_param2)
|
||
|
if mode ~= screwdriver.ROTATE_FACE then return false end
|
||
|
|
||
|
if wallmounted_values[node.param2] then
|
||
|
minetest.swap_node(pos, {name = node.name, param1 = node.param1, param2 = wallmounted_values[node.param2].rotate})
|
||
|
place_entities(pos)
|
||
|
return true
|
||
|
else
|
||
|
return false
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--- Creates display entity with some fields and the on_activate callback
|
||
|
function display_lib.register_display_entity(entity_name)
|
||
|
if not minetest.registered_entity then
|
||
|
minetest.register_entity(':'..entity_name, {
|
||
|
collisionbox = { 0, 0, 0, 0, 0, 0 },
|
||
|
visual = "upright_sprite",
|
||
|
textures = {},
|
||
|
on_activate = display_lib.on_activate,
|
||
|
})
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
|