mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-11-22 15:33:00 +00:00
Rework metaballs backend
We need a way of defining metaballs per-player. Our solution to this is a custom in-memory per-player storage system. The reason for this is because just a position (e.g. that provided by pos1/pos2) is not enough - we need a radius as well.
This commit is contained in:
parent
0d7922d747
commit
3311d80a2a
5 changed files with 196 additions and 3 deletions
|
@ -59,11 +59,11 @@ dofile(wea.modpath.."/lib/scale.lua")
|
||||||
dofile(wea.modpath.."/lib/spiral_square.lua")
|
dofile(wea.modpath.."/lib/spiral_square.lua")
|
||||||
dofile(wea.modpath.."/lib/spiral_circle.lua")
|
dofile(wea.modpath.."/lib/spiral_circle.lua")
|
||||||
dofile(wea.modpath.."/lib/dome.lua")
|
dofile(wea.modpath.."/lib/dome.lua")
|
||||||
dofile(wea.modpath.."/lib/metaballs.lua")
|
|
||||||
dofile(wea.modpath.."/lib/conv/conv.lua")
|
dofile(wea.modpath.."/lib/conv/conv.lua")
|
||||||
dofile(wea.modpath.."/lib/erode/erode.lua")
|
dofile(wea.modpath.."/lib/erode/erode.lua")
|
||||||
dofile(wea.modpath.."/lib/noise/init.lua")
|
dofile(wea.modpath.."/lib/noise/init.lua")
|
||||||
wea.sculpt = dofile(wea.modpath.."/lib/sculpt/init.lua")
|
wea.sculpt = dofile(wea.modpath.."/lib/sculpt/init.lua")
|
||||||
|
wea.metaballs = dofile(wea.modpath.."/lib/metaballs.lua")
|
||||||
|
|
||||||
dofile(wea.modpath.."/lib/copy.lua")
|
dofile(wea.modpath.."/lib/copy.lua")
|
||||||
dofile(wea.modpath.."/lib/move.lua")
|
dofile(wea.modpath.."/lib/move.lua")
|
||||||
|
|
15
worldeditadditions/lib/metaballs/init.lua
Normal file
15
worldeditadditions/lib/metaballs/init.lua
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
local wea = worldeditadditions
|
||||||
|
local wea_m = wea.modpath .. "/lib/metaballs/"
|
||||||
|
|
||||||
|
local playerdata = dofile(wea_m.."playerdata.lua")
|
||||||
|
|
||||||
|
local metaballs_ns = {
|
||||||
|
render = dofile(wea_m.."render.lua"),
|
||||||
|
add = playerdata.add,
|
||||||
|
remove = playerdata.remove,
|
||||||
|
list = playerdata.list,
|
||||||
|
list_pretty = playerdata.list_pretty,
|
||||||
|
clear = playerdata.clear
|
||||||
|
}
|
||||||
|
|
||||||
|
return metaballs_ns
|
104
worldeditadditions/lib/metaballs/playerdata.lua
Normal file
104
worldeditadditions/lib/metaballs/playerdata.lua
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
local wea = worldeditadditions
|
||||||
|
local Vector3 = wea.Vector3
|
||||||
|
|
||||||
|
local metaballdata = {}
|
||||||
|
|
||||||
|
--- Adds a new metaball for a given player at the specified position with a specified radius.
|
||||||
|
-- @param player_name string The name of the player.
|
||||||
|
-- @param pos Vector3 The position of the metaball.
|
||||||
|
-- @param radius number The radius of the metaball.
|
||||||
|
-- @returns bool,number The number of metaballs now defined for the given player.
|
||||||
|
local function add(player_name, pos, radius)
|
||||||
|
local pos = Vector3.clone(pos)
|
||||||
|
|
||||||
|
if type(player_name) ~= "string" then
|
||||||
|
return false, "Error: Invalid player name specified."
|
||||||
|
end
|
||||||
|
if type(radius) ~= "number" then
|
||||||
|
return false, "Error: Expected the radius to be of type number, but got value of type "..type(radius).." instead."
|
||||||
|
end
|
||||||
|
if radius < 1 then
|
||||||
|
return false, "The minimum radius of a metaball is 1, but got a radius of "..tostring(radius).."."
|
||||||
|
end
|
||||||
|
|
||||||
|
if not metaballdata[player_name] then
|
||||||
|
metaballdata[player_name] = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: Limit the number of metaballs that can be defined?
|
||||||
|
table.insert(metaballdata[player_name], {
|
||||||
|
pos = pos,
|
||||||
|
radius = radius
|
||||||
|
})
|
||||||
|
|
||||||
|
return true, #metaballdata[player_name]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a list of all metaballs defined for the given player.
|
||||||
|
-- @param player_name string The name of the player.
|
||||||
|
-- @returns bool,[{ pos: Vector3, radius: number }, ...] A list of metaballs for the given player.
|
||||||
|
local function list(player_name)
|
||||||
|
if type(player_name) ~= "string" then
|
||||||
|
return false, "Error: Invalid player name specified."
|
||||||
|
end
|
||||||
|
|
||||||
|
if not metaballdata[player_name] then return {} end
|
||||||
|
|
||||||
|
return true, metaballdata[player_name]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns a pretty-printed list of metaballs for the given player.
|
||||||
|
-- @param player_name string The name of the player.
|
||||||
|
-- @returns bool,string A pretty-printed list of metaballs for the given player.
|
||||||
|
local function list_pretty(player_name)
|
||||||
|
local success, metaball_list = list(player_name)
|
||||||
|
if not success then return success, metaball_list end
|
||||||
|
|
||||||
|
local rows = { { "Index", "Position", "Radius" } }
|
||||||
|
for i,metaball in ipairs(metaball_list) do
|
||||||
|
table.insert(rows, {
|
||||||
|
i,
|
||||||
|
metaball.pos,
|
||||||
|
metaball.radius
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
return true, wea.format.make_ascii_table(rows).."\n---------------------------\nTotal "..tostring(#metaball_list).." metaballs"
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Removes the metaball with the specified index for a given player.
|
||||||
|
-- @param player_name string The name of the player.
|
||||||
|
-- @param index number The index of the metaball to remove.
|
||||||
|
-- @returns bool,number The number of metaballs now defined for the given player.
|
||||||
|
local function remove(player_name, index)
|
||||||
|
local success, metaball_list = list(player_name)
|
||||||
|
if not success then return success, metaball_list end
|
||||||
|
|
||||||
|
if #metaball_list > index then
|
||||||
|
return false, "Error: Requested the removal of metaball "..tostring(index)..", but there are "..tostring(#metaball_list).." metaballs defined."
|
||||||
|
end
|
||||||
|
|
||||||
|
table.remove(metaball_list, index)
|
||||||
|
|
||||||
|
return #metaball_list
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Removes all the currently defined metaballs for the given player.
|
||||||
|
-- @param player_name string The name of the player.
|
||||||
|
-- @returns bool,number The number of metaballs that WERE defined for the given player.
|
||||||
|
local function clear(player_name)
|
||||||
|
local success, metaball_list = list(player_name)
|
||||||
|
if not success then return success, metaball_list end
|
||||||
|
|
||||||
|
metaballdata[player_name] = {}
|
||||||
|
|
||||||
|
return #metaball_list
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
add = add,
|
||||||
|
list = list,
|
||||||
|
list_pretty = list_pretty,
|
||||||
|
remove = remove,
|
||||||
|
clear = clear
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ local Vector3 = wea.Vector3
|
||||||
-- direction the point should point.
|
-- direction the point should point.
|
||||||
-- @param metaballs [{pos: Vector3, radius: number}] Aa list of metaballs to render. Each metaball should be a table with 2 properties: pos - the position of the centre of the metaball as a Vector3, and radius - the radius of the metaball.
|
-- @param metaballs [{pos: Vector3, radius: number}] Aa list of metaballs to render. Each metaball should be a table with 2 properties: pos - the position of the centre of the metaball as a Vector3, and radius - the radius of the metaball.
|
||||||
-- @param replace_node string The fully qualified name of the node to use to make the dome with.
|
-- @param replace_node string The fully qualified name of the node to use to make the dome with.
|
||||||
function worldeditadditions.metaballs(metaballs, replace_node, threshold)
|
local function render(metaballs, replace_node, threshold)
|
||||||
local pos1, pos2
|
local pos1, pos2
|
||||||
if not threshold then threshold = 1 end
|
if not threshold then threshold = 1 end
|
||||||
|
|
||||||
|
@ -61,3 +61,6 @@ function worldeditadditions.metaballs(metaballs, replace_node, threshold)
|
||||||
|
|
||||||
return true, replaced
|
return true, replaced
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return render
|
71
worldeditadditions_commands/commands/metaballs.lua
Normal file
71
worldeditadditions_commands/commands/metaballs.lua
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
local wea = worldeditadditions
|
||||||
|
local Vector3 = wea.Vector3
|
||||||
|
|
||||||
|
-- ██████ ██████ ███ ███ ███████
|
||||||
|
-- ██ ██ ██ ██ ████ ████ ██
|
||||||
|
-- ██ ██ ██ ██ ██ ████ ██ █████
|
||||||
|
-- ██ ██ ██ ██ ██ ██ ██ ██
|
||||||
|
-- ██████ ██████ ██ ██ ███████
|
||||||
|
worldedit.register_command("metaballs", {
|
||||||
|
params = "add <radius> | remove <index> | list | render <replace_node> | clear",
|
||||||
|
description = "Defines and creates metaballs. After using the add subcommand to define 1 or more metaballs (uses pos1), the render subcommand can then be used to create the metaballs as nodes.",
|
||||||
|
privs = { worldedit = true },
|
||||||
|
require_pos = 1,
|
||||||
|
parse = function(params_text)
|
||||||
|
if not params_text then params_text = "" end
|
||||||
|
|
||||||
|
local parts = wea.split_shell(params_text)
|
||||||
|
|
||||||
|
if #parts < 1 then
|
||||||
|
return false, "Error: Not enough arguments (see /help /dome for usage information)."
|
||||||
|
end
|
||||||
|
local subcommand = parts[1]
|
||||||
|
local subargs = {}
|
||||||
|
if subcommand == "add" then
|
||||||
|
local radius = tonumber(parts[2])
|
||||||
|
if not radius then
|
||||||
|
return false, "Error: Invalid radius '"..parts[1].."'. The radius must be a positive integer."
|
||||||
|
end
|
||||||
|
if radius < 1 then
|
||||||
|
return false, "Error: The minimum radius size is 1, but you entered "..tostring(radius).."."
|
||||||
|
end
|
||||||
|
table.insert(subargs, radius)
|
||||||
|
elseif subcommand == "remove" then
|
||||||
|
local index = tonumber(parts[2])
|
||||||
|
if not index then
|
||||||
|
return false, "Error: Invalid index '"..parts[1].."'. The index to remove must be a positive integer."
|
||||||
|
end
|
||||||
|
if index < 1 then
|
||||||
|
return false, "Error: The minimum index size is 1, but you entered "..tostring(index).."."
|
||||||
|
end
|
||||||
|
table.insert(subargs, index)
|
||||||
|
elseif subcommand == "render" then
|
||||||
|
local replace_node = worldedit.normalize_nodename(parts[2])
|
||||||
|
if not replace_node then
|
||||||
|
return false, "Error: Invalid replace_node '"..parts[2].."'."
|
||||||
|
end
|
||||||
|
table.insert(subargs, replace_node)
|
||||||
|
end
|
||||||
|
|
||||||
|
return true, subcommand, subargs
|
||||||
|
end,
|
||||||
|
nodes_needed = function(name, subcommand)
|
||||||
|
if subcommand == "render" then
|
||||||
|
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
func = function(name, radius, replace_node, axes, hollow)
|
||||||
|
local start_time = wea.get_ms_time()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local time_taken = wea.get_ms_time() - start_time
|
||||||
|
|
||||||
|
|
||||||
|
minetest.log("action", name.." used //dome+ at "..pos.." with a radius of "..tostring(radius)..", modifying "..nodes_replaced.." nodes in "..wea.format.human_time(time_taken))
|
||||||
|
return true, nodes_replaced.." nodes replaced "..wea.format.human_time(time_taken)
|
||||||
|
end
|
||||||
|
})
|
Loading…
Reference in a new issue