From 60e5b299af564f250af8304b5146f79693c314ff Mon Sep 17 00:00:00 2001 From: MarkuBu Date: Tue, 7 Feb 2017 16:28:02 -0800 Subject: [PATCH] Leafdecay: Node timer based implementation, API This implements a node-timer based leafdecay mechanism, and exposes an API to use it in mods. The API is documented in game_api.txt. `default.register_leafdecay(leafdecaydef)` `leafdecaydef` is a table, with following members: { trunks = { "default:tree"}, -- nodes considered trunks leaves = { "default:leaves", "default:apple"}, -- nodes considered leaves radius = 3, -- activates leafdecay this far from the trunk } The algorithm will drop `leaves` items in the area if no `trunks` are found in the `trunk_radius` sized area around the position of the leaf. If a node listed in `leaves` has a group `leafdecay_drop > 0`, then the item is dropped, otherwise the item is removed but not dropped. The algorithm also implements a value `default.leafdecay_speed` (default 15) which can be modified to increase or decrease of the leaf decay. The algorithm will vary the actual speed a bit to introduce randomness. Leaf decay is randomized by 0.1 seconds to reduce the chance that decay happens many times on the same second interval. This requires nodetimer_interval to be set to values lower than 1.0 to have an effect. The leaves will decay between 2 and 10 seconds after digging the trunk, and happen at non-integer second intervals. -- The API was added by sofar. --- game_api.txt | 36 +++++++++++----- mods/default/functions.lua | 87 +++++++++++++++++++++++--------------- mods/default/nodes.lua | 54 +++++++++++++++++++++++ 3 files changed, 132 insertions(+), 45 deletions(-) diff --git a/game_api.txt b/game_api.txt index 0d518f1..fa6225a 100644 --- a/game_api.txt +++ b/game_api.txt @@ -658,20 +658,36 @@ default.player_get_animation(player) Leafdecay --------- -To enable leaf decay for a node, add it to the `leafdecay` group. +To enable leaf decay for leaves when a tree is cut down by a player, +register the tree with the default.register_leafdecay(leafdecaydef) +function. -The rating of the group determines how far from a node in the group `tree` -the node can be without decaying. +If `param2` of any registered node is ~= 0, the node will always be +preserved. Thus, if the player places a node of that kind, you will +want to set `param2 = 1` or so. -If `param2` of the node is ~= 0, the node will always be preserved. Thus, if -the player places a node of that kind, you will want to set `param2 = 1` or so. +The function `default.after_place_leaves` can be set as +`after_place_node of a node` to set param2 to 1 if the player places +the node (should not be used for nodes that use param2 otherwise +(e.g. facedir)). -The function `default.after_place_leaves` can be set as `after_place_node of a node` -to set param2 to 1 if the player places the node (should not be used for nodes -that use param2 otherwise (e.g. facedir)). +If the node is in the `leafdecay_drop` group then it will always be +dropped as an item. + +`default.register_leafdecay(leafdecaydef)` + +`leafdecaydef` is a table, with following members: + { + trunks = {"default:tree"}, -- nodes considered trunks + leaves = {"default:leaves", "default:apple"}, + -- nodes considered for removal + radius = 3, -- radius to consider for searching + } + +Note: all the listed nodes in `trunks` have their `on_after_destruct` +callback overridden. All the nodes listed in `leaves` have their +`on_timer` callback overridden. -If the node is in the `leafdecay_drop` group then it will always be dropped as an -item. Dyes ---- diff --git a/mods/default/functions.lua b/mods/default/functions.lua index b927520..0361109 100644 --- a/mods/default/functions.lua +++ b/mods/default/functions.lua @@ -325,47 +325,64 @@ default.after_place_leaves = function(pos, placer, itemstack, pointed_thing) end end --- Leafdecay ABM - -minetest.register_abm({ - label = "Leaf decay", - nodenames = {"group:leafdecay"}, - neighbors = {"air"}, - interval = 2, - chance = 10, - catch_up = false, - - action = function(pos, node, _, _) - -- Check if leaf is placed - if node.param2 ~= 0 then - return +-- Leafdecay +local function leafdecay_after_destruct(pos, oldnode, def) + for _, v in pairs(minetest.find_nodes_in_area(vector.subtract(pos, def.radius), + vector.add(pos, def.radius), def.leaves)) do + local node = minetest.get_node(v) + if node.param2 == 0 then + minetest.get_node_timer(v):start(math.random(20, 120) / 10) end + end +end - local rad = minetest.registered_nodes[node.name].groups.leafdecay - -- Assume ignore is a trunk, to make this - -- work at the border of a loaded area - if minetest.find_node_near(pos, rad, {"ignore", "group:tree"}) then - return - end - -- Drop stuff - local itemstacks = minetest.get_node_drops(node.name) - for _, itemname in ipairs(itemstacks) do - if itemname ~= node.name or - minetest.get_item_group(node.name, "leafdecay_drop") ~= 0 then - local p_drop = { - x = pos.x - 0.5 + math.random(), - y = pos.y - 0.5 + math.random(), - z = pos.z - 0.5 + math.random(), - } - minetest.add_item(p_drop, itemname) +local function leafdecay_on_timer(pos, def) + if minetest.find_node_near(pos, def.radius, def.trunks) then + return false + end + + local node = minetest.get_node(pos) + local drops = minetest.get_node_drops(node.name) + for _, item in ipairs(drops) do + local is_leaf + for _, v in pairs(def.leaves) do + if v == item then + is_leaf = true end end - -- Remove node - minetest.remove_node(pos) - minetest.check_for_falling(pos) + if minetest.get_item_group(item, "leafdecay_drop") ~= 0 or + not is_leaf then + minetest.add_item({ + x = pos.x - 0.5 + math.random(), + y = pos.y - 0.5 + math.random(), + z = pos.z - 0.5 + math.random(), + }, item) + end end -}) + minetest.remove_node(pos) + minetest.check_for_falling(pos) +end + +function default.register_leafdecay(def) + assert(def.leaves) + assert(def.trunks) + assert(def.radius) + for _, v in pairs(def.trunks) do + minetest.override_item(v, { + after_destruct = function(pos, oldnode) + leafdecay_after_destruct(pos, oldnode, def) + end, + }) + end + for _, v in pairs(def.leaves) do + minetest.override_item(v, { + on_timer = function(pos) + leafdecay_on_timer(pos, def) + end, + }) + end +end -- -- Convert dirt to something that fits the environment diff --git a/mods/default/nodes.lua b/mods/default/nodes.lua index 0ce62a4..3d74b77 100644 --- a/mods/default/nodes.lua +++ b/mods/default/nodes.lua @@ -2072,3 +2072,57 @@ minetest.register_node("default:cloud", { sounds = default.node_sound_defaults(), groups = {not_in_creative_inventory = 1}, }) + +-- +-- register trees for leafdecay +-- + +if minetest.get_mapgen_setting("mg_name") == "v6" then + default.register_leafdecay({ + trunks = {"default:tree"}, + leaves = {"default:apple", "default:leaves"}, + radius = 2, + }) + + default.register_leafdecay({ + trunks = {"default:jungletree"}, + leaves = {"default:jungleleaves"}, + radius = 3, + }) + + default.register_leafdecay({ + trunks = {"default:pine_tree"}, + leaves = {"default:pine_needles"}, + radius = 3, + }) +else + default.register_leafdecay({ + trunks = {"default:tree"}, + leaves = {"default:apple", "default:leaves"}, + radius = 3, + }) + + default.register_leafdecay({ + trunks = {"default:jungletree"}, + leaves = {"default:jungleleaves"}, + radius = 2, + }) + + default.register_leafdecay({ + trunks = {"default:pine_tree"}, + leaves = {"default:pine_needles"}, + radius = 2, + }) +end + +default.register_leafdecay({ + trunks = {"default:acacia_tree"}, + leaves = {"default:acacia_leaves"}, + radius = 2, +}) + +default.register_leafdecay({ + trunks = {"default:aspen_tree"}, + leaves = {"default:aspen_leaves"}, + radius = 3, +})