mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-11-22 15:33:00 +00:00
Start implementing //forest, but it isn't finished yet
This commit is contained in:
parent
0abf9d095b
commit
0b285fa681
8 changed files with 291 additions and 63 deletions
|
@ -11,10 +11,13 @@ dofile(worldeditadditions.modpath.."/utils/vector.lua")
|
|||
dofile(worldeditadditions.modpath.."/utils/strings.lua")
|
||||
dofile(worldeditadditions.modpath.."/utils/numbers.lua")
|
||||
dofile(worldeditadditions.modpath.."/utils/nodes.lua")
|
||||
dofile(worldeditadditions.modpath.."/utils/node_identification.lua")
|
||||
dofile(worldeditadditions.modpath.."/utils/tables.lua")
|
||||
dofile(worldeditadditions.modpath.."/utils/terrain.lua")
|
||||
dofile(worldeditadditions.modpath.."/utils/raycast_adv.lua") -- For the farwand
|
||||
|
||||
dofile(worldeditadditions.modpath.."/lib/compat/saplingnames.lua")
|
||||
|
||||
dofile(worldeditadditions.modpath.."/lib/floodfill.lua")
|
||||
dofile(worldeditadditions.modpath.."/lib/overlay.lua")
|
||||
dofile(worldeditadditions.modpath.."/lib/layers.lua")
|
||||
|
@ -31,3 +34,4 @@ dofile(worldeditadditions.modpath.."/lib/erode/erode.lua")
|
|||
dofile(worldeditadditions.modpath.."/lib/count.lua")
|
||||
|
||||
dofile(worldeditadditions.modpath.."/lib/bonemeal.lua")
|
||||
dofile(worldeditadditions.modpath.."/lib/forest.lua")
|
||||
|
|
106
worldeditadditions/lib/compat/saplingnames.lua
Normal file
106
worldeditadditions/lib/compat/saplingnames.lua
Normal file
|
@ -0,0 +1,106 @@
|
|||
--[[
|
||||
This file contains sapling alias definitions for a number of different mods.
|
||||
If your mod is not listed here, please open a pull request to add it :-)
|
||||
|
||||
This mod's repository can be found here: https://github.com/sbrl/Minetest-WorldEditAdditions
|
||||
|
||||
Adding support for your mod is a 2 step process:
|
||||
|
||||
1. Update this file with your definitions
|
||||
2. Update depends.txt to add a soft dependency on your mod. Find that file here: https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/worldeditadditions/depends.txt - for example, add something line "my_awesome_mod?" (note the question mark at the end) on a new line(without quotes).
|
||||
|
||||
Alternatively, you can register support in your mod directly. Do that by adding a soft dependency on worldeditadditions, and then calling worldeditadditions.normalise_saplingname if worldeditadditions is loaded.
|
||||
]]--
|
||||
|
||||
-- worldeditadditions.register_sapling_alias("")
|
||||
|
||||
if minetest.get_modpath("default") then
|
||||
worldeditadditions.register_sapling_alias_many({
|
||||
{ "default:sapling", "oak" },
|
||||
{ "default:bush_sapling", "bush" },
|
||||
{ "default:pine_sapling", "pine" },
|
||||
{ "default:pine_bush_sapling", "pine_bush" },
|
||||
{ "default:aspen_sapling", "aspen" },
|
||||
{ "default:junglesapling", "jungle" },
|
||||
{ "default:emergent_jungle_sapling", "jungle_emergent" },
|
||||
{ "default:acacia_sapling", "acacia" },
|
||||
{ "default:acacia_bush_sapling", "acacia_bush" },
|
||||
{ "default:blueberry_bush_sapling", "blueberry_bush" }
|
||||
})
|
||||
end
|
||||
|
||||
if minetest.get_modpath("moretrees") then
|
||||
worldeditadditions.register_sapling_alias_many({
|
||||
{ "moretrees:spruce_sapling_ongen", "spruce" },
|
||||
{ "moretrees:rubber_tree_sapling_ongen", "rubbe" },
|
||||
{ "moretrees:beech_sapling_ongen", "beech" },
|
||||
{ "moretrees:jungletree_sapling_ongen", "jungle_moretrees" },
|
||||
{ "moretrees:fir_sapling_ongen", "fir" },
|
||||
{ "moretrees:willow_sapling_ongen", "willow" },
|
||||
{ "moretrees:poplar_sapling_ongen", "poplar" },
|
||||
{ "moretrees:poplar_small_sapling_ongen", "poplar_small" },
|
||||
{ "moretrees:apple_tree_sapling_ongen", "apple" },
|
||||
{ "moretrees:birch_sapling_ongen", "birch" },
|
||||
{ "moretrees:palm_sapling_ongen", "palm" },
|
||||
{ "moretrees:date_palm_sapling_ongen", "palm_date" },
|
||||
{ "moretrees:sequoia_sapling_ongen", "sequoia" },
|
||||
{ "moretrees:oak_sapling_ongen", "oak_moretrees" },
|
||||
{ "moretrees:cedar_sapling_ongen", "cedar" }
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
-- ██████ ██████ ██████ ██ ████████ ██████ ███████ ███████ ███████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██████ █████ █████ ███████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██████ ██████ ██████ ███████ ███████ ██ ██ ██ ███████ ███████ ███████
|
||||
|
||||
if minetest.get_modpath("lemontree") then
|
||||
worldeditadditions.register_sapling_alias("lemontree:sapling", "lemontree")
|
||||
end
|
||||
if minetest.get_modpath("pineapple") then
|
||||
worldeditadditions.register_sapling_alias("pineapple:sapling", "pineapple")
|
||||
end
|
||||
if minetest.get_modpath("baldcypress") then
|
||||
worldeditadditions.register_sapling_alias("baldcypress:sapling", "baldcypress")
|
||||
end
|
||||
if minetest.get_modpath("bamboo") then
|
||||
worldeditadditions.register_sapling_alias("bamboo:sapling", "bamboo")
|
||||
end
|
||||
if minetest.get_modpath("birch") then
|
||||
worldeditadditions.register_sapling_alias("birch:sapling", "birch")
|
||||
end
|
||||
if minetest.get_modpath("cherrytree") then
|
||||
worldeditadditions.register_sapling_alias("cherrytree:sapling", "cherrytree")
|
||||
end
|
||||
if minetest.get_modpath("clementinetree") then
|
||||
worldeditadditions.register_sapling_alias("clementinetree:sapling", "clementinetree")
|
||||
end
|
||||
if minetest.get_modpath("ebony") then
|
||||
worldeditadditions.register_sapling_alias("ebony:sapling", "ebony")
|
||||
end
|
||||
if minetest.get_modpath("jacaranda") then
|
||||
worldeditadditions.register_sapling_alias("jacaranda:sapling", "jacaranda")
|
||||
end
|
||||
if minetest.get_modpath("larch") then
|
||||
worldeditadditions.register_sapling_alias("larch:sapling", "larch")
|
||||
end
|
||||
if minetest.get_modpath("maple") then
|
||||
worldeditadditions.register_sapling_alias("maple:sapling", "maple")
|
||||
end
|
||||
if minetest.get_modpath("palm") then
|
||||
worldeditadditions.register_sapling_alias("palm:sapling", "palm")
|
||||
end
|
||||
if minetest.get_modpath("pomegranate") then
|
||||
worldeditadditions.register_sapling_alias("pomegranate:sapling", "pomegranate")
|
||||
end
|
||||
if minetest.get_modpath("willow") then
|
||||
worldeditadditions.register_sapling_alias("willow:sapling", "willow")
|
||||
end
|
||||
if minetest.get_modpath("mahogany") then
|
||||
worldeditadditions.register_sapling_alias("mahogany:sapling", "mahogany")
|
||||
end
|
||||
if minetest.get_modpath("chestnuttree") then
|
||||
worldeditadditions.register_sapling_alias("chestnuttree:sapling", "chestnuttree")
|
||||
end
|
94
worldeditadditions/utils/node_identification.lua
Normal file
94
worldeditadditions/utils/node_identification.lua
Normal file
|
@ -0,0 +1,94 @@
|
|||
local node_id_air = minetest.get_content_id("air")
|
||||
local node_id_ignore = minetest.get_content_id("ignore")
|
||||
|
||||
--- Determines whether the given node/content id is an airlike node or not.
|
||||
-- It is recommended that the result of this function be cached.
|
||||
-- @param id number The content/node id to check.
|
||||
-- @return bool Whether the given node/content id is an airlike node or not.
|
||||
function worldeditadditions.is_airlike(id)
|
||||
-- Do a fast check against air and ignore
|
||||
if id == node_id_air then
|
||||
return true
|
||||
elseif id == node_id_ignore then -- ignore = not loaded yet IIRC (so it could be anything)
|
||||
return false
|
||||
end
|
||||
|
||||
-- If the node isn't registered, then it might not be an air node
|
||||
if not minetest.registered_nodes[id] then return false end
|
||||
if minetest.registered_nodes[id].sunlight_propagates == true then
|
||||
return true
|
||||
end
|
||||
-- Check for membership of the airlike group
|
||||
local name = minetest.get_name_from_content_id(id)
|
||||
local airlike_value = minetest.get_item_group(name, "airlike")
|
||||
if airlike_value ~= nil and airlike_value > 0 then
|
||||
return true
|
||||
end
|
||||
-- Just in case
|
||||
if worldeditadditions.string_starts(this_node_name, "wielded_light") then
|
||||
return true
|
||||
end
|
||||
-- Just in case
|
||||
return false
|
||||
end
|
||||
|
||||
--- Determines whether the given node/content id is a liquid-ish node or not.
|
||||
-- It is recommended that the result of this function be cached.
|
||||
-- @param id number The content/node id to check.
|
||||
-- @return bool Whether the given node/content id is a liquid-ish node or not.
|
||||
function worldeditadditions.is_liquidlike(id)
|
||||
-- print("[is_liquidlike]")
|
||||
if id == node_id_ignore then return false end
|
||||
|
||||
local node_name = minetest.get_name_from_content_id(id)
|
||||
if node_name == nil or not minetest.registered_nodes[node_name] then return false end
|
||||
|
||||
local liquidtype = minetest.registered_nodes[node_name].liquidtype
|
||||
-- print("[is_liquidlike]", "id", id, "liquidtype", liquidtype)
|
||||
|
||||
if liquidtype == nil or liquidtype == "none" then return false end
|
||||
-- If it's not none, then it has to be a liquid as the only other values are source and flowing
|
||||
return true
|
||||
end
|
||||
|
||||
--- Determines whether the given node/content id is a sapling or not.
|
||||
-- Nodes with the "sapling" group are considered saplings.
|
||||
-- It is recommended that the result of this function be cached.
|
||||
-- @param id number The content/node id to check.
|
||||
-- @return bool Whther the given node/content id is a sapxling or not.
|
||||
function worldeditadditions.is_sapling(id)
|
||||
local node_name = minetest.get_name_from_content_id(data[i])
|
||||
return minetest.get_item_group(node_name, "sapling") ~= 0
|
||||
end
|
||||
|
||||
local sapling_aliases = {}
|
||||
function worldeditadditions.register_sapling_alias(sapling_node_name, alias)
|
||||
if sapling_aliases[sapling_node_name] then
|
||||
return false, "Error: An alias against the node name '"..sapling_node_name.."' already exists."
|
||||
end
|
||||
sapling_aliases[alias] = sapling_node_name
|
||||
return true
|
||||
end
|
||||
function worldeditadditions.register_sapling_alias_many(tbl)
|
||||
for i, next in ipairs(tbl) do
|
||||
local success, msg = worldeditadditions.register_sapling_alias(
|
||||
next[1],
|
||||
next[2]
|
||||
)
|
||||
if not success then return success, msg end
|
||||
end
|
||||
end
|
||||
--- Returns the current key ⇒ value table of sapling names and aliases.
|
||||
-- @return table
|
||||
function worldeditadditions.get_all_sapling_aliases()
|
||||
return sapling_aliases
|
||||
end
|
||||
|
||||
--- Attempts to normalise a sapling name using the currently registered aliases.
|
||||
-- @param in_name string The sapling name to normalise
|
||||
-- @param return_nil_on_failure bool Whether to return nil if we fail to resolve the sapling name with an alias, or return the original node name instead (default: false).
|
||||
function worldeditadditions.normalise_saplingname(in_name, return_nil_on_failure)
|
||||
if sapling_aliases[in_name] then return sapling_aliases[in_name]
|
||||
elseif return_nil_on_failure then return nil
|
||||
else return in_name end
|
||||
end
|
|
@ -28,65 +28,12 @@ function worldeditadditions.unwind_node_list(list)
|
|||
return result, #result
|
||||
end
|
||||
|
||||
local node_id_air = minetest.get_content_id("air")
|
||||
local node_id_ignore = minetest.get_content_id("ignore")
|
||||
|
||||
--- Determines whether the given node/content id is an airlike node or not.
|
||||
-- It is recommended that the result of this function be cached.
|
||||
-- @param id number The content/node id to check.
|
||||
-- @return bool Whether the given node/content id is an airlike node or not.
|
||||
function worldeditadditions.is_airlike(id)
|
||||
-- Do a fast check against air and ignore
|
||||
if id == node_id_air then
|
||||
return true
|
||||
elseif id == node_id_ignore then -- ignore = not loaded yet IIRC (so it could be anything)
|
||||
return false
|
||||
function worldeditadditions.registered_nodes_by_group(group)
|
||||
local result = {}
|
||||
for name, def in pairs(minetest.registered_nodes) do
|
||||
if def.groups[group] then
|
||||
result[#result+1] = name
|
||||
end
|
||||
end
|
||||
|
||||
-- If the node isn't registered, then it might not be an air node
|
||||
if not minetest.registered_nodes[id] then return false end
|
||||
if minetest.registered_nodes[id].sunlight_propagates == true then
|
||||
return true
|
||||
end
|
||||
-- Check for membership of the airlike group
|
||||
local name = minetest.get_name_from_content_id(id)
|
||||
local airlike_value = minetest.get_item_group(name, "airlike")
|
||||
if airlike_value ~= nil and airlike_value > 0 then
|
||||
return true
|
||||
end
|
||||
-- Just in case
|
||||
if worldeditadditions.string_starts(this_node_name, "wielded_light") then
|
||||
return true
|
||||
end
|
||||
-- Just in case
|
||||
return false
|
||||
end
|
||||
|
||||
--- Determines whether the given node/content id is a liquid-ish node or not.
|
||||
-- It is recommended that the result of this function be cached.
|
||||
-- @param id number The content/node id to check.
|
||||
-- @return bool Whether the given node/content id is a liquid-ish node or not.
|
||||
function worldeditadditions.is_liquidlike(id)
|
||||
-- print("[is_liquidlike]")
|
||||
if id == node_id_ignore then return false end
|
||||
|
||||
local node_name = minetest.get_name_from_content_id(id)
|
||||
if node_name == nil or not minetest.registered_nodes[node_name] then return false end
|
||||
|
||||
local liquidtype = minetest.registered_nodes[node_name].liquidtype
|
||||
-- print("[is_liquidlike]", "id", id, "liquidtype", liquidtype)
|
||||
|
||||
if liquidtype == nil or liquidtype == "none" then return false end
|
||||
-- If it's not none, then it has to be a liquid as the only other values are source and flowing
|
||||
return true
|
||||
end
|
||||
|
||||
--- Determines whether the given node/content id is a sapling or not.
|
||||
-- Nodes with the "sapling" group are considered saplings.
|
||||
-- It is recommended that the result of this function be cached.
|
||||
-- @param id number The content/node id to check.
|
||||
-- @return bool Whther the given node/content id is a sapxling or not.
|
||||
function worldeditadditions.is_sapling(id)
|
||||
local node_name = minetest.get_name_from_content_id(data[i])
|
||||
return minetest.get_item_group(node_name, "sapling") ~= 0
|
||||
return result
|
||||
end
|
||||
|
|
|
@ -157,8 +157,9 @@ end
|
|||
--- Parses a list of strings as a list of weighted nodes - e.g. like in the //mix command.
|
||||
-- @param parts string[] The list of strings to parse (try worldeditadditions.split)
|
||||
-- @param as_list bool If true, then table.insert() successive { node = string, weight = number } subtables when parsing instead of populating as an associative array.
|
||||
-- @param func_normalise callable If specified, the given function will be used to normalise node names instead of worldedit.normalize_nodename. A single argument is passed containing the un-normalised node name, and the return value is assumed to be the normalised node name.
|
||||
-- @returns table A table in the form node_name => weight.
|
||||
function worldeditadditions.parse_weighted_nodes(parts, as_list)
|
||||
function worldeditadditions.parse_weighted_nodes(parts, as_list, func_normalise)
|
||||
if as_list == nil then as_list = false end
|
||||
local MODE_EITHER = 1
|
||||
local MODE_NODE = 2
|
||||
|
@ -170,7 +171,9 @@ function worldeditadditions.parse_weighted_nodes(parts, as_list)
|
|||
print("i: "..i..", part: "..part)
|
||||
if mode == MODE_NODE then
|
||||
print("mode: node");
|
||||
local next = worldedit.normalize_nodename(part)
|
||||
local next
|
||||
if not func_normalise then next = worldedit.normalize_nodename(part)
|
||||
else next = func_normalise(part) end
|
||||
if not next then
|
||||
return false, "Error: Invalid node name '"..part.."'"
|
||||
end
|
||||
|
@ -181,7 +184,10 @@ function worldeditadditions.parse_weighted_nodes(parts, as_list)
|
|||
local chance = tonumber(part)
|
||||
if not chance then
|
||||
print("not a chance, trying a node name")
|
||||
local node_name = worldedit.normalize_nodename(part)
|
||||
local node_name
|
||||
if not func_normalise then node_name = worldedit.normalize_nodename(part)
|
||||
else node_name = func_normalise(part) end
|
||||
|
||||
if not node_name then
|
||||
return false, "Error: Invalid number '"..chance.."'"
|
||||
end
|
||||
|
|
36
worldeditadditions_commands/commands/forest.lua
Normal file
36
worldeditadditions_commands/commands/forest.lua
Normal file
|
@ -0,0 +1,36 @@
|
|||
-- ██████ ██ ██ ███████ ██████ ██ █████ ██ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██ ██ █████ ██████ ██ ███████ ████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██████ ████ ███████ ██ ██ ███████ ██ ██ ██
|
||||
worldedit.register_command("forest", {
|
||||
params = "<sapling_a> [<chance_a>] <sapling_b> [<chance_b>] [<sapling_N> [<chance_N>]] ...",
|
||||
description = "Plants and grows trees in the defined region according to the given list of sapling names and chances. Saplings are planted using //overlay - so the chances a 1-in-N change of actually planting a sapling at each candidate location. Saplings that fail to grow are subsequently removed (this will affect pre-existing saplings too)",
|
||||
privs = { worldedit = true },
|
||||
require_pos = 2,
|
||||
parse = function(params_text)
|
||||
local success, sapling_list = worldeditadditions.parse_weighted_nodes(
|
||||
worldeditadditions.split(params_text, "%s+", false),
|
||||
false,
|
||||
function(name)
|
||||
return worldedit.normalize_nodename(
|
||||
worldeditadditions.normalise_saplingname(name)
|
||||
)
|
||||
end
|
||||
)
|
||||
return success, sapling_list
|
||||
end,
|
||||
nodes_needed = function(name)
|
||||
-- //overlay only modifies up to 1 node per column in the selected region
|
||||
local pos1, pos2 = worldedit.sort_pos(worldedit.pos1[name], worldedit.pos2[name])
|
||||
return (pos2.x - pos1.x) * (pos2.y - pos1.y)
|
||||
end,
|
||||
func = function(name, sapling_list)
|
||||
local start_time = worldeditadditions.get_ms_time()
|
||||
local changes = worldeditadditions.forest(worldedit.pos1[name], worldedit.pos2[name], sapling_list)
|
||||
local time_taken = worldeditadditions.get_ms_time() - start_time
|
||||
|
||||
minetest.log("action", name .. " used //forest at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. changes.updated .. " nodes and skipping " .. changes.skipped_columns .. " columns in " .. time_taken .. "s")
|
||||
return true, changes.updated .. " nodes replaced and " .. changes.skipped_columns .. " columns skipped in " .. worldeditadditions.human_time(time_taken)
|
||||
end
|
||||
})
|
34
worldeditadditions_commands/commands/saplingaliases.lua
Normal file
34
worldeditadditions_commands/commands/saplingaliases.lua
Normal file
|
@ -0,0 +1,34 @@
|
|||
minetest.register_chatcommand("/saplingaliases", {
|
||||
params = "[aliases|all_saplings]",
|
||||
description = "Lists all the currently registered sapling aliases (default). A single argument is taken as the mode of operation. Current modes: aliases (default; as described previously), all_saplings (lists all node names with the group \"sapling\")",
|
||||
privs = { worldedit = true },
|
||||
func = function(name, params_text)
|
||||
if name == nil then return end
|
||||
if params_text == "" or not params_text then
|
||||
params_text = "aliases"
|
||||
end
|
||||
|
||||
local msg = {}
|
||||
|
||||
if params_text == "aliases" then
|
||||
table.insert(msg, "Currently registered aliases:\n")
|
||||
local aliases = worldeditadditions.get_all_sapling_aliases()
|
||||
local display = {}
|
||||
for node_name, alias in pairs(aliases) do
|
||||
table.insert(display, { node_name, alias })
|
||||
end
|
||||
table.insert(msg, worldeditadditions.make_ascii_table(display))
|
||||
elseif params_text == "all_saplings" then
|
||||
local results = worldeditadditions.registered_nodes_by_group("sapling")
|
||||
table.insert(msg, "Sapling-like nodes:\n")
|
||||
local str = table.concat(results, "\n")
|
||||
print(str)
|
||||
table.insert(msg, str)
|
||||
else
|
||||
table.insert(msg, "Unknown mode '")
|
||||
table.insert(msg, params_text)
|
||||
table.insert(msg, "' (valid modes: aliases, all_saplings).")
|
||||
end
|
||||
worldedit.player_notify(name, table.concat(msg))
|
||||
end
|
||||
})
|
|
@ -34,6 +34,7 @@ dofile(we_c.modpath.."/commands/convolve.lua")
|
|||
dofile(we_c.modpath.."/commands/erode.lua")
|
||||
|
||||
dofile(we_c.modpath.."/commands/count.lua")
|
||||
dofile(we_c.modpath.."/commands/forestaliases.lua")
|
||||
|
||||
dofile(we_c.modpath.."/commands/subdivide.lua")
|
||||
|
||||
|
|
Loading…
Reference in a new issue