From 0ca85ac5c18f405df565d89dc92d572d18cbebc5 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Rollo Date: Thu, 14 Mar 2019 09:36:41 +0100 Subject: [PATCH] Detect rotation restriction (#29) Autodetect rotation restrictions if on MT<5.0 --- README.md | 9 +- display_api/API.md | 1 + display_api/README.md | 8 +- display_api/display.lua | 257 ++++++++++++++++++----------------- display_api/settingtypes.txt | 1 - signs_api/README.md | 4 + signs_api/init.lua | 9 +- 7 files changed, 152 insertions(+), 137 deletions(-) delete mode 100644 display_api/settingtypes.txt diff --git a/README.md b/README.md index 5839d10..c37a469 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Display Modpack -Version 1.3 - -**Important**: If using Minetest 5 and above, disable `display_rotation_restriction` in settings and enjoy rotation of display nodes in every direction! +Version 1.3.1 This modpack provides mods with dynamic display. Mods are : @@ -40,10 +38,13 @@ Following objects are deprecated, shows a warning in log when used: These objects will be removed in the future. ## Changelog +### 2019-03-14 (Version 1.3.1) +- __dispay_api__: Display API now detects automatically whenr rotation restrictions have to be applied. +- __sign_api__: Screwdriver behavior changed. Now, left click rotates and changes direction. ### 2019-03-09 (Version 1.3) - __display_api__: Display nodes can be rotated in every directions (if running Minetest 5 or above). -- __display_api__: New setting to restrict rotations to Minetest 0.4 abilities (**restriction enabled by default**). +- __display_api__: New setting to restrict rotations to Minetest 0.4 abilities (restriction enabled by default). - __sign_api__: Changed behavior of screwdriver if no rotation restriction. ### 2018-12-14 (Version 1.2.3) diff --git a/display_api/API.md b/display_api/API.md index e69ae60..acfd867 100644 --- a/display_api/API.md +++ b/display_api/API.md @@ -14,6 +14,7 @@ This method triggers entities update for the display node at pos. Actual entity This is a helper to register entities used for display. `entity_name`: Name of the entity to register. + ## Provided callback implementations ### on_place **display\_api.on\_place(itemstack, placer, pointed\_thing)** diff --git a/display_api/README.md b/display_api/README.md index a0f0f6e..73acdf9 100644 --- a/display_api/README.md +++ b/display_api/README.md @@ -2,9 +2,7 @@ This library's purpose is to ease creation of nodes with one or more displays on sides. For example, signs and clocks. Display can be dynamic and/or different for each node instance. -**Limitations**: This lib uses entities to draw display. This means display has to be vertical (and "upside up") on Minetest before version 5.0. This restriction can be set in settings. - -**Settings**: `display_rotation_restriction` should be set to false if using Minetest 5.0 and above, true otherwise. +**Limitations**: This lib uses entities to draw display. This means display has to be vertical (and "upside up") on Minetest before version 5.0. **Dependancies**:default @@ -25,10 +23,12 @@ Following objects are deprecated, shows a warning in log when used: These objects will be removed in the future. ## Change log +### 2019-03-14 +- __dispay_api__: Display API now detects automatically whenr rotation restrictions have to be applied. ### 2019-03-09 - __display_api__: Display nodes can be rotated in every directions (if running Minetest 5 or above). -- __display_api__: New setting to restrict rotations to Minetest 0.4 abilities (**restriction enabled by default**). +- __display_api__: New setting to restrict rotations to Minetest 0.4 abilities (restriction enabled by default). ### 2018-12-14 - __display_api__: New `yaw` attributes, entities can now have different angles with node. diff --git a/display_api/display.lua b/display_api/display.lua index 3ed1f02..2fed40f 100644 --- a/display_api/display.lua +++ b/display_api/display.lua @@ -22,51 +22,29 @@ -- variable as spacing between entity and node display_api.entity_spacing = 0.002 --- Settings -display_api.rotation_restriction = - minetest.settings:get_bool("display_rotation_restriction", true) - -if display_api.rotation_restriction then - minetest.log("action", "[display_api] Legacy rotation restriction in effect") -end - -- Maximum entity position relative to the node pos local max_entity_pos = 1.5 -local wallmounted_rotations, facedir_rotations +local wallmounted_rotations = { + [0]={x=1, y=0, z=0}, [1]={x=3, y=0, z=0}, + [2]={x=0, y=3, z=0}, [3]={x=0, y=1, z=0}, + [4]={x=0, y=0, z=0}, [5]={x=0, y=2, z=0}, +} -if display_api.rotation_restriction then - -- Legacy rotations (MT<5.0) - wallmounted_rotations = { - [2]={x=0, y=3, z=0}, [3]={x=0, y=1, z=0}, - [4]={x=0, y=0, z=0}, [5]={x=0, y=2, z=0}, - } - facedir_rotations = { - [0]={x=0, y=0, z=0}, [1]={x=0, y=3, z=0}, - [2]={x=0, y=2, z=0}, [3]={x=0, y=1, z=0}, - } -else - -- Full rotations (MT>=5.0) - wallmounted_rotations = { - [0]={x=1, y=0, z=0}, [1]={x=3, y=0, z=0}, - [2]={x=0, y=3, z=0}, [3]={x=0, y=1, z=0}, - [4]={x=0, y=0, z=0}, [5]={x=0, y=2, z=0}, - } - facedir_rotations = { - [ 0]={x=0, y=0, z=0}, [ 1]={x=0, y=3, z=0}, - [ 2]={x=0, y=2, z=0}, [ 3]={x=0, y=1, z=0}, - [ 4]={x=3, y=0, z=0}, [ 5]={x=0, y=3, z=3}, - [ 6]={x=1, y=0, z=2}, [ 7]={x=0, y=1, z=1}, - [ 8]={x=1, y=0, z=0}, [ 9]={x=0, y=3, z=1}, - [10]={x=3, y=0, z=2}, [11]={x=0, y=1, z=3}, - [12]={x=0, y=0, z=1}, [13]={x=3, y=0, z=1}, - [14]={x=2, y=0, z=1}, [15]={x=1, y=0, z=1}, - [16]={x=0, y=0, z=3}, [17]={x=1, y=0, z=3}, - [18]={x=2, y=0, z=3}, [19]={x=3, y=0, z=3}, - [20]={x=0, y=0, z=2}, [21]={x=0, y=1, z=2}, - [22]={x=0, y=2, z=2}, [23]={x=0, y=3, z=2}, - } -end +local facedir_rotations = { + [ 0]={x=0, y=0, z=0}, [ 1]={x=0, y=3, z=0}, + [ 2]={x=0, y=2, z=0}, [ 3]={x=0, y=1, z=0}, + [ 4]={x=3, y=0, z=0}, [ 5]={x=0, y=3, z=3}, + [ 6]={x=1, y=0, z=2}, [ 7]={x=0, y=1, z=1}, + [ 8]={x=1, y=0, z=0}, [ 9]={x=0, y=3, z=1}, + [10]={x=3, y=0, z=2}, [11]={x=0, y=1, z=3}, + [12]={x=0, y=0, z=1}, [13]={x=3, y=0, z=1}, + [14]={x=2, y=0, z=1}, [15]={x=1, y=0, z=1}, + [16]={x=0, y=0, z=3}, [17]={x=1, y=0, z=3}, + [18]={x=2, y=0, z=3}, [19]={x=3, y=0, z=3}, + [20]={x=0, y=0, z=2}, [21]={x=0, y=1, z=2}, + [22]={x=0, y=2, z=2}, [23]={x=0, y=3, z=2}, +} -- Compute other useful values depending on wallmounted and facedir param local wallmounted_values = {} @@ -86,7 +64,9 @@ local function compute_values(r) for _ = 1, r.x do d, w, h = rx(d), rx(w), rx(h) end for _ = 1, r.y do d, w, h = ry(d), ry(w), ry(h) end - return {rotation=r, depth=d, width=w, height=h} + return { + rotation=r, depth=d, width=w, height=h, + restricted=(r.x==0 and r.z==0) } end for i, r in pairs(facedir_rotations) do @@ -97,7 +77,38 @@ for i, r in pairs(wallmounted_rotations) do wallmounted_values[i] = compute_values(r) end -local function get_values(node) +-- Detect rotation restriction +local rotation_restricted = nil +minetest.register_entity('display_api:dummy_entity', { + collisionbox = { 0, 0, 0, 0, 0, 0 }, + visual = "upright_sprite", + textures = {} }) + +function display_api.is_rotation_restricted() + if rotation_restricted == nil then + local objref = minetest.add_entity( + {x=0, y=0, z=0}, 'display_api:dummy_entity') + if objref then + rotation_restricted = objref.set_rotation == nil + objref:remove() + end + end + return rotation_restricted +end + +-- Clip position property to maximum entity position + +local function clip_pos_prop(posprop) + if posprop then + return math.max(-max_entity_pos, math.min(max_entity_pos, posprop)) + else + return 0 + end +end + +-- Get values needed for orientation computation of node + +local function get_orientation_values(node) local ndef = minetest.registered_nodes[node.name] if ndef then @@ -106,12 +117,17 @@ local function get_values(node) return wallmounted_values[node.param2 % 8] elseif paramtype2 == "facedir" or paramtype2 == "colorfacedir" then return facedir_values[node.param2 % 32] + else + -- No orientation or unknown orientation type + return facedir_values[0] end end end ---- Gets the display entities attached with a node. Removes extra ones -local function get_entities(pos) +-- Gets the display entities attached with a node. +-- Add missing and remove duplicates + +local function get_display_objrefs(pos, create) local objrefs = {} local ndef = minetest.registered_nodes[minetest.get_node(pos).name] if ndef and ndef.display_entities then @@ -127,85 +143,57 @@ local function get_entities(pos) end end end - end - return objrefs -end - -local function clip_pos_prop(posprop) - if posprop then - return math.max(-max_entity_pos, math.min(max_entity_pos, 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 v = get_values(node) - local objrefs = get_entities(pos) - - if v and ndef and ndef.display_entities then - for entity_name, props in pairs(ndef.display_entities) do - local depth = clip_pos_prop(props.depth) - local right = clip_pos_prop(props.right) - local top = clip_pos_prop(props.top) - if not objrefs[entity_name] then - objrefs[entity_name] = minetest.add_entity(pos, entity_name, - minetest.serialize({ nodepos = pos })) - end - - objrefs[entity_name]:set_pos({ - x = pos.x + v.depth.x*depth + v.width.x*right - v.height.x*top, - y = pos.y + v.depth.y*depth + v.width.y*right - v.height.y*top, - z = pos.z + v.depth.z*depth + v.width.z*right - v.height.z*top, - }) - - if objrefs[entity_name].set_rotation then - objrefs[entity_name]:set_rotation({ - x = v.rotation.x*math.pi/2, - y = v.rotation.y*math.pi/2 + (props.yaw or 0), - z = v.rotation.z*math.pi/2, - }) - else -- For minetest < 5.0 -- TODO: To be removed in the future - objrefs[entity_name]:set_yaw(v.rotation.y*math.pi/2 + (props.yaw or 0)) + if create then + -- Add missing + for name, _ in pairs(ndef.display_entities) do + if not objrefs[name] then + objrefs[name] = minetest.add_entity(pos, name, + minetest.serialize({ nodepos = pos })) + end end end end return objrefs end ---- Entity update -function update_entity(entity) - if not entity then - return - end - - if not entity.nodepos then - entity.object:remove() -- Remove old/buggy entity - return - end - - local node = minetest.get_node(entity.nodepos) - local ndef = minetest.registered_nodes[node.name] - if ndef and ndef.display_entities and - ndef.display_entities[entity.name] and - ndef.display_entities[entity.name].on_display_update - then - -- Call on_display_update callback of a node for one of its display entities - ndef.display_entities[entity.name].on_display_update(entity.nodepos, - entity.object) - else - -- Display node has been removed, remove entity also - entity.object:remove() - end -end - ---- Force entity update +--- Force entity update : position and texture function display_api.update_entities(pos) - for _, objref in pairs(place_entities(pos)) do - update_entity(objref:get_luaentity()) + + local node = minetest.get_node(pos) + local ndef = minetest.registered_nodes[node.name] + local ov = get_orientation_values(node) + + for _, objref in pairs(get_display_objrefs(pos, true)) do + local edef = ndef.display_entities[objref:get_luaentity().name] + local depth = clip_pos_prop(edef.depth) + local right = clip_pos_prop(edef.right) + local top = clip_pos_prop(edef.top) + + objref:set_pos({ + x = pos.x + ov.depth.x*depth + ov.width.x*right - ov.height.x*top, + y = pos.y + ov.depth.y*depth + ov.width.y*right - ov.height.y*top, + z = pos.z + ov.depth.z*depth + ov.width.z*right - ov.height.z*top, + }) + + if objref.set_rotation then + objref:set_rotation({ + x = ov.rotation.x*math.pi/2, + y = ov.rotation.y*math.pi/2 + (edef.yaw or 0), + z = ov.rotation.z*math.pi/2, + }) + else + if ov.rotation.x ~=0 or ov.rotation.y ~= 0 then + minetest.log("warning", string.format( + "[display_api] unable to rotate correctly entity for node at %s without set_rotation method.", + minetest.pos_to_string(pos))) + end + objref:set_yaw(ov.rotation.y*math.pi/2 + (edef.yaw or 0)) + end + + -- Call on_display_update callback of a node for one of its display entities + if edef.on_display_update then + edef.on_display_update(pos, objref) + end end end @@ -220,7 +208,23 @@ function display_api.on_activate(entity, staticdata) end entity.object:set_armor_groups({immortal=1}) end - update_entity(entity) + + if entity.nodepos then + local node = minetest.get_node(entity.nodepos) + local ndef = minetest.registered_nodes[node.name] + if ndef and ndef.display_entities then + local edef = ndef.display_entities[entity.name] + if edef then + -- Call on_display_update callback of the entity to build texture + if edef.on_display_update then + edef.on_display_update(entity.nodepos, entity.object) + end + return + end + end + end + -- If we got here, this display entity is buggy and should be removed + entity.object:remove() end end @@ -235,7 +239,9 @@ function display_api.on_place(itemstack, placer, pointed_thing, override_param2) z = pointed_thing.under.z - pointed_thing.above.z, } - if display_api.rotation_restriction then + local rotation_restriction = display_api.is_rotation_restricted() + + if rotation_restriction then -- If item is not placed on a wall, use the player's view direction instead if dir.x == 0 and dir.z == 0 then dir = placer:get_look_dir() @@ -251,7 +257,7 @@ function display_api.on_place(itemstack, placer, pointed_thing, override_param2) elseif ndef.paramtype2 == "facedir" or ndef.paramtype2 == "colorfacedir" then - param2 = minetest.dir_to_facedir(dir, not display_api.rotation_restriction) + param2 = minetest.dir_to_facedir(dir, not rotation_restriction) end end return minetest.item_place(itemstack, placer, pointed_thing, @@ -267,17 +273,20 @@ end --- On_destruct callback for display_api items. -- Removes entities. function display_api.on_destruct(pos) - for _, objref in pairs(get_entities(pos)) do + for _, objref in pairs(get_display_objrefs(pos)) do objref:remove() end end --- On_rotate (screwdriver) callback for display_api items. Prevents invalid rotations and reorients entities. +-- On_rotate (screwdriver) callback for display_api items. Prevents invalid +-- rotations and reorients entities. function display_api.on_rotate(pos, node, user, _, new_param2) node.param2 = new_param2 - if get_values(node) then + local ov = get_orientation_values(node) + + if ov.restricted or not display_api.is_rotation_restricted() then minetest.swap_node(pos, node) - place_entities(pos) + display_api.update_entities(pos) return true else return false diff --git a/display_api/settingtypes.txt b/display_api/settingtypes.txt deleted file mode 100644 index 58a0108..0000000 --- a/display_api/settingtypes.txt +++ /dev/null @@ -1 +0,0 @@ -display_rotation_restriction(Legacy nodes rotation restriction MT<5.0) bool true diff --git a/signs_api/README.md b/signs_api/README.md index 99ff20a..38e8d96 100644 --- a/signs_api/README.md +++ b/signs_api/README.md @@ -27,3 +27,7 @@ Handles screwdriver rotation. Direction is affected for direction signs. ### `signs_api.register_sign(mod, name, model)` A method to quickly register signs. + +## Changelog +### 2019-03-14 +- __sign_api__: Screwdriver behavior changed. Now, left click rotates and changes direction. diff --git a/signs_api/init.lua b/signs_api/init.lua index 4b20486..1bd00d6 100644 --- a/signs_api/init.lua +++ b/signs_api/init.lua @@ -91,6 +91,7 @@ end function signs_api.on_place_direction(itemstack, placer, pointed_thing) local name = itemstack:get_name() local ndef = minetest.registered_nodes[name] + local restriction = display_api.is_rotation_restricted() local bdir = { x = pointed_thing.under.x - pointed_thing.above.x, @@ -103,12 +104,12 @@ function signs_api.on_place_direction(itemstack, placer, pointed_thing) if ndef.paramtype2 == "facedir" then -- If legacy mode, only accept upright nodes - if display_api.rotation_restriction and bdir.x == 0 and bdir.z == 0 then + if restriction and bdir.x == 0 and bdir.z == 0 then -- Ceiling or floor pointed (facedir chosen from player dir) ndir = minetest.dir_to_facedir({x=pdir.x, y=0, z=pdir.z}) else -- Wall pointed or no rotation restriction - ndir = minetest.dir_to_facedir(bdir, not display_api.rotation_restriction) + ndir = minetest.dir_to_facedir(bdir, not restriction) end test = { [0]=-pdir.x, pdir.z, pdir.x, -pdir.z, -pdir.x, [8]=pdir.x } @@ -117,7 +118,7 @@ function signs_api.on_place_direction(itemstack, placer, pointed_thing) if ndef.paramtype2 == "wallmounted" then ndir = minetest.dir_to_wallmounted(bdir) -- If legacy mode, only accept upright nodes - if display_api.rotation_restriction and (ndir == 0 or ndir == 1) then + if restriction and (ndir == 0 or ndir == 1) then ndir = minetest.dir_to_wallmounted({x=pdir.x, y=0, z=pdir.z}) end @@ -166,7 +167,7 @@ end -- Legacy mode with rotation restriction -- TODO:When MT < 5.0 no more in use, to be removed -if display_api.rotation_restriction then +if display_api.is_rotation_restricted() then signs_api.on_rotate = function(pos, node, player, mode, new_param2) -- If rotation mode is 2 and sign is directional, swap direction. -- Otherwise use display_api's on_rotate function.