Refactor table functions into subtable of wea

Also, you can return a value from dofile()!!!!

This changes everything.
This commit is contained in:
Starbeamrainbowlabs 2021-06-28 00:56:29 +01:00
parent 624abc899b
commit db7b20d485
No known key found for this signature in database
GPG Key ID: 1BE5172E637709C2
30 changed files with 85 additions and 61 deletions

@ -58,7 +58,7 @@ function worldeditadditions.convolve(pos1, pos2, kernel, kernel_size)
local node_id_air = minetest.get_content_id("air") local node_id_air = minetest.get_content_id("air")
local heightmap, heightmap_size = worldeditadditions.make_heightmap(pos1, pos2, manip, area, data) local heightmap, heightmap_size = worldeditadditions.make_heightmap(pos1, pos2, manip, area, data)
local heightmap_conv = worldeditadditions.shallowcopy(heightmap) local heightmap_conv = worldeditadditions.table.shallowcopy(heightmap)
worldeditadditions.conv.convolve( worldeditadditions.conv.convolve(
heightmap_conv, heightmap_conv,

@ -18,7 +18,7 @@ function worldeditadditions.erode.run(pos1, pos2, algorithm, params)
local region_height = (pos2.y - pos1.y) + 1 local region_height = (pos2.y - pos1.y) + 1
local heightmap = worldeditadditions.make_heightmap(pos1, pos2, manip, area, data) local heightmap = worldeditadditions.make_heightmap(pos1, pos2, manip, area, data)
local heightmap_eroded = worldeditadditions.shallowcopy(heightmap) local heightmap_eroded = worldeditadditions.table.shallowcopy(heightmap)
-- print("[erode.run] algorithm: "..algorithm..", params:"); -- print("[erode.run] algorithm: "..algorithm..", params:");
-- print(worldeditadditions.format.map(params)) -- print(worldeditadditions.format.map(params))

@ -5,7 +5,7 @@ local wea = worldeditadditions
-- @returns number[] A list of side numbers. -- @returns number[] A list of side numbers.
local function parse_sides_list(list) local function parse_sides_list(list)
list = list:gsub("%s", "") -- Spaces are not permitted list = list:gsub("%s", "") -- Spaces are not permitted
return wea.table_unique(wea.table_map( return wea.table.unique(wea.table.map(
wea.split(list, ","), wea.split(list, ","),
function(value) return tonumber(value) end function(value) return tonumber(value) end
)) ))
@ -20,7 +20,7 @@ function worldeditadditions.erode.river(heightmap_initial, heightmap, heightmap_
dolower = true -- Whether to do lower operations or not dolower = true -- Whether to do lower operations or not
} }
-- Apply the custom settings -- Apply the custom settings
wea.table_apply(params_custom, params) wea.table.apply(params_custom, params)
params.lower_sides = parse_sides_list(params.lower_sides) params.lower_sides = parse_sides_list(params.lower_sides)
params.raise_sides = parse_sides_list(params.raise_sides) params.raise_sides = parse_sides_list(params.raise_sides)

@ -87,7 +87,7 @@ function worldeditadditions.erode.snowballs(heightmap_initial, heightmap, height
count = 25000 count = 25000
} }
-- Apply the custom settings -- Apply the custom settings
worldeditadditions.table_apply(params_custom, params) worldeditadditions.table.apply(params_custom, params)
-- print("[erode/snowballs] params: ") -- print("[erode/snowballs] params: ")
-- print(worldeditadditions.format.map(params)) -- print(worldeditadditions.format.map(params))

@ -23,7 +23,7 @@ function worldeditadditions.noise2d(pos1, pos2, noise_params)
manip, area, manip, area,
data data
) )
local heightmap_new = worldeditadditions.shallowcopy(heightmap_old) local heightmap_new = worldeditadditions.table.shallowcopy(heightmap_old)
local perlin_map = PerlinNoiseMap(noise_params, heightmap_size) local perlin_map = PerlinNoiseMap(noise_params, heightmap_size)

@ -25,8 +25,8 @@ function worldeditadditions.noise.params_apply_default(params)
-- If params[1] is thing, this is a list of params -- If params[1] is thing, this is a list of params
-- This might be a thing if we're dealingw ith multiple octaves -- This might be a thing if we're dealingw ith multiple octaves
for i,params_el in ipairs(params) do for i,params_el in ipairs(params) do
local default_copy = worldeditadditions.shallowcopy(params_default) local default_copy = worldeditadditions.table.shallowcopy(params_default)
worldeditadditions.table_apply( worldeditadditions.table.apply(
params_el, params_el,
default_copy default_copy
) )

@ -39,7 +39,7 @@ function worldeditadditions.scale_down(pos1, pos2, scale, anchor)
local manip, area = worldedit.manip_helpers.init(pos1, pos2) local manip, area = worldedit.manip_helpers.init(pos1, pos2)
local data = manip:get_data() local data = manip:get_data()
local data_copy = worldeditadditions.shallowcopy(data) local data_copy = worldeditadditions.table.shallowcopy(data)
local node_id_air = minetest.get_content_id("air") local node_id_air = minetest.get_content_id("air")
@ -68,7 +68,7 @@ function worldeditadditions.scale_down(pos1, pos2, scale, anchor)
for x = pos2.x, pos1.x, -1 do for x = pos2.x, pos1.x, -1 do
local posi_rel = vector.subtract({ x = x, y = y, z = z }, pos1) local posi_rel = vector.subtract({ x = x, y = y, z = z }, pos1)
-- local posi_copy = worldeditadditions.shallowcopy(posi_rel) -- local posi_copy = worldeditadditions.table.shallowcopy(posi_rel)
-- posi_copy = vector.floor(vector.divide(posi_rel/*, scale_down*/)) -- posi_copy = vector.floor(vector.divide(posi_rel/*, scale_down*/))
local posi_copy = { local posi_copy = {

@ -88,7 +88,7 @@ local function subdivide_step_afterload(state_emerge, state_ours)
state_ours.times.emerge_last = wea.get_ms_time() - state_ours.times.emerge_last state_ours.times.emerge_last = wea.get_ms_time() - state_ours.times.emerge_last
table.insert(state_ours.times.emerge, state_ours.times.emerge_last) table.insert(state_ours.times.emerge, state_ours.times.emerge_last)
if #state_ours.times.emerge > 25 then if #state_ours.times.emerge > 25 then
state_ours.times.emerge = wea.table_get_last(state_ours.times.emerge, 100) state_ours.times.emerge = wea.table.get_last(state_ours.times.emerge, 100)
end end
state_ours.times.emerge_total = state_ours.times.emerge_total + state_ours.times.emerge_last state_ours.times.emerge_total = state_ours.times.emerge_total + state_ours.times.emerge_last
@ -108,7 +108,7 @@ local function subdivide_step_afterload(state_emerge, state_ours)
state_ours.times.step_last = wea.get_ms_time() - state_ours.times.step_start_abs state_ours.times.step_last = wea.get_ms_time() - state_ours.times.step_start_abs
table.insert(state_ours.times.steps, state_ours.times.step_last) table.insert(state_ours.times.steps, state_ours.times.step_last)
if #state_ours.times.steps > 25 then if #state_ours.times.steps > 25 then
state_ours.times.steps = wea.table_get_last(state_ours.times.steps, 100) state_ours.times.steps = wea.table.get_last(state_ours.times.steps, 100)
end end
state_ours.times.steps_total = state_ours.times.steps_total + state_ours.times.step_last state_ours.times.steps_total = state_ours.times.steps_total + state_ours.times.step_last
state_ours.times.step_start_abs = wea.get_ms_time() state_ours.times.step_start_abs = wea.get_ms_time()

@ -36,4 +36,4 @@ function worldeditadditions.dir_to_xyz(name, dir)
end end
-- Tests -- Tests
-- /lua print(unpack(worldeditadditions.player_axis2d(myname))) -- /lua print(worldeditadditions.table.unpack(worldeditadditions.player_axis2d(myname)))

@ -70,7 +70,7 @@ function Mesh.dedupe(self)
for j,face_next in ipairs(self.faces) do for j,face_next in ipairs(self.faces) do
if i ~= j -- If we're not comparing a face to itself... if i ~= j -- If we're not comparing a face to itself...
and face_check == face_next -- ....and the 2 faces are equal.... and face_check == face_next -- ....and the 2 faces are equal....
and not wea.table_contains(toremove, j) then -- ...and we haven't already marked it for removal... and not wea.table.contains(toremove, j) then -- ...and we haven't already marked it for removal...
-- Mark it for removal -- Mark it for removal
table.insert(toremove, j) table.insert(toremove, j)
end end

@ -71,7 +71,7 @@ end
function worldeditadditions.eta(existing_times, done_count, total_count) function worldeditadditions.eta(existing_times, done_count, total_count)
local max = 100 local max = 100
local average = worldeditadditions.average( local average = worldeditadditions.average(
worldeditadditions.table_get_last(existing_times, max) worldeditadditions.table.get_last(existing_times, max)
) )
local times_left = total_count - done_count local times_left = total_count - done_count
if times_left == 0 then return 0 end if times_left == 0 then return 0 end

@ -8,16 +8,17 @@
-- Lua doesn't exactly come with batteries included, so this is quite an -- Lua doesn't exactly come with batteries included, so this is quite an
-- extensive collection of functions :P -- extensive collection of functions :P
-- TODO: Refactor into its own worldeditadditions.tables namespace. local wea = worldeditadditions
worldeditadditions.tables = {}
dofile(worldeditadditions.modpath.."/utils/tables/sets.lua") wea.table = {
dofile(worldeditadditions.modpath.."/utils/tables/shallowcopy.lua") apply = dofile(wea.modpath.."/utils/tables/table_apply.lua"),
dofile(worldeditadditions.modpath.."/utils/tables/table_apply.lua") contains = dofile(wea.modpath.."/utils/tables/table_contains.lua"),
dofile(worldeditadditions.modpath.."/utils/tables/table_filter.lua") filter = dofile(wea.modpath.."/utils/tables/table_filter.lua"),
dofile(worldeditadditions.modpath.."/utils/tables/table_get_last.lua") get_last = dofile(wea.modpath.."/utils/tables/table_get_last.lua"),
dofile(worldeditadditions.modpath.."/utils/tables/table_map.lua") makeset = dofile(wea.modpath.."/utils/tables/makeset.lua"),
dofile(worldeditadditions.modpath.."/utils/tables/table_tostring.lua") map = dofile(wea.modpath.."/utils/tables/table_map.lua"),
dofile(worldeditadditions.modpath.."/utils/tables/table_unique.lua") shallowcopy = dofile(wea.modpath.."/utils/tables/shallowcopy.lua"),
dofile(worldeditadditions.modpath.."/utils/tables/table_unpack.lua") tostring = dofile(wea.modpath.."/utils/tables/table_tostring.lua"),
dofile(worldeditadditions.modpath.."/utils/tables/table_contains.lua") unique = dofile(wea.modpath.."/utils/tables/table_unique.lua"),
unpack = dofile(wea.modpath.."/utils/tables/table_unpack.lua"),
}

@ -1,9 +1,13 @@
--- Creates a table that stores data in keys. --- Creates a table that stores data in keys.
-- @source https://riptutorial.com/lua/example/13407/search-for-an-item-in-a-list -- @source https://riptutorial.com/lua/example/13407/search-for-an-item-in-a-list
-- @param list table The table of values to convert to keys. -- @param list table The table of values to convert to keys.
-- @return table The table of (key,true) pairs. -- @return table The table of (key => true) pairs.
function worldeditadditions.makeset (list) local function makeset(list)
local set = {} local set = {}
for _, l in ipairs(list) do set[l] = true end for _, l in ipairs(list) do
set[l] = true
end
return set return set
end end
return makeset

@ -3,7 +3,7 @@
-- @source http://lua-users.org/wiki/CopyTable -- @source http://lua-users.org/wiki/CopyTable
-- @param orig table The table to clone. -- @param orig table The table to clone.
-- @return table The cloned table. -- @return table The cloned table.
function worldeditadditions.shallowcopy(orig) local function shallowcopy(orig)
local orig_type = type(orig) local orig_type = type(orig)
local copy local copy
if orig_type == 'table' then if orig_type == 'table' then
@ -16,3 +16,5 @@ function worldeditadditions.shallowcopy(orig)
end end
return copy return copy
end end
return shallowcopy

@ -2,8 +2,10 @@
-- Warning: This function mutates target! -- Warning: This function mutates target!
-- @param source table The source to take values from -- @param source table The source to take values from
-- @param target table The target to write values to -- @param target table The target to write values to
function worldeditadditions.table_apply(source, target) local function table_apply(source, target)
for key, value in pairs(source) do for key, value in pairs(source) do
target[key] = value target[key] = value
end end
end end
return table_apply

@ -3,16 +3,11 @@
-- @param tbl table The table to look in. -- @param tbl table The table to look in.
-- @param target any The target to look for. -- @param target any The target to look for.
-- @returns bool Whether the table contains the given target or not. -- @returns bool Whether the table contains the given target or not.
local function table_contains(tbl, target) local function contains(tbl, target)
for key, value in ipairs(tbl) do for key, value in ipairs(tbl) do
if value == target then return true end if value == target then return true end
end end
return false return false
end end
return table_contains
if worldeditadditions then
worldeditadditions.table_contains = table_contains
else
return table_contains
end

@ -7,7 +7,7 @@
-- @param tbl table The table of values to filter. -- @param tbl table The table of values to filter.
-- @param func function<any, number>:bool The filter function to execute - should return a boolean value indicating whether the item provided as the first argument should be kept -- @param func function<any, number>:bool The filter function to execute - should return a boolean value indicating whether the item provided as the first argument should be kept
-- @returns table A new table containing the values that the given function returned true for. -- @returns table A new table containing the values that the given function returned true for.
function worldeditadditions.table_filter(tbl, func) local function table_filter(tbl, func)
local result = {} local result = {}
for i,value in ipairs(tbl) do for i,value in ipairs(tbl) do
if func(value, i) then if func(value, i) then
@ -16,3 +16,5 @@ function worldeditadditions.table_filter(tbl, func)
end end
return result return result
end end
return table_filter

@ -1,7 +1,17 @@
local wea = worldeditadditions
local table_unpack = dofile(wea.modpath.."/utils/tables/table_unpack.lua")
--- Returns only the last count items in a given numerical table-based list. --- Returns only the last count items in a given numerical table-based list.
function worldeditadditions.table_get_last(tbl, count) -- @param tbl table The table to fetch items from.
return {worldeditadditions.table_unpack( -- @param count number The number of items to fetch from the end of the table.
-- @returns table A table containing the last count items from the given table.
local function table_get_last(tbl, count)
return {table_unpack(
tbl, tbl,
math.max(0, (#tbl) - (count - 1)) math.max(0, (#tbl) - (count - 1))
)} )}
end end
return table_get_last

@ -3,7 +3,7 @@
-- @param tbl table The table to operate on. -- @param tbl table The table to operate on.
-- @param func function<any>:any|nil The function to execute on every item in the table. -- @param func function<any>:any|nil The function to execute on every item in the table.
-- @returns table A new table containing the return values of the function. -- @returns table A new table containing the return values of the function.
function worldeditadditions.table_map(tbl, func) local function table_map(tbl, func)
local result = {} local result = {}
for i,value in ipairs(tbl) do for i,value in ipairs(tbl) do
local newval = func(value, i) local newval = func(value, i)
@ -11,3 +11,5 @@ function worldeditadditions.table_map(tbl, func)
end end
return result return result
end end
return table_map

@ -3,7 +3,7 @@
-- @param sep string key value seperator -- @param sep string key value seperator
-- @param new_line string key value pair delimiter -- @param new_line string key value pair delimiter
-- @return string concatenated table pairs -- @return string concatenated table pairs
function worldeditadditions.table_tostring(tbl, sep, new_line) local function table_tostring(tbl, sep, new_line)
if type(sep) ~= "string" then sep = ": " end if type(sep) ~= "string" then sep = ": " end
if type(new_line) ~= "string" then new_line = ", " end if type(new_line) ~= "string" then new_line = ", " end
local ret = {} local ret = {}
@ -16,3 +16,5 @@ function worldeditadditions.table_tostring(tbl, sep, new_line)
end end
return ret:concat("") return ret:concat("")
end end
return table_tostring

@ -1,7 +1,7 @@
--- Builds a new table with the elements of the given table appearing at most once. --- Builds a new table with the elements of the given table appearing at most once.
-- @param tbl table The table of values to make unique. -- @param tbl table The table of values to make unique.
-- @returns table A new table containing the values of the given table appearing at most once. -- @returns table A new table containing the values of the given table appearing at most once.
function worldeditadditions.table_unique(tbl) local function table_unique(tbl)
local newtbl = {} local newtbl = {}
for i,value in ipairs(tbl) do for i,value in ipairs(tbl) do
local seen = false local seen = false
@ -17,3 +17,5 @@ function worldeditadditions.table_unique(tbl)
end end
return newtbl return newtbl
end end
return table_unique

@ -3,10 +3,12 @@
-- found. -- found.
-- This is needed because in Lua 5.1 it's the global unpack(), but in Lua 5.4 -- This is needed because in Lua 5.1 it's the global unpack(), but in Lua 5.4
-- it's moved to table.unpack(). -- it's moved to table.unpack().
function worldeditadditions.table_unpack(tbl, offset, count) local function table_unpack(tbl, offset, count)
if type(unpack) == "function" then if type(unpack) == "function" then
return unpack(tbl, offset, count) return unpack(tbl, offset, count)
else else
return table.unpack(tbl, offset, count) return table.unpack(tbl, offset, count)
end end
end end
return table_unpack

@ -90,7 +90,7 @@ end
-- @param area VoxelArea The VoxelArea object (see worldedit.manip_helpers.init) -- @param area VoxelArea The VoxelArea object (see worldedit.manip_helpers.init)
-- @param data number[] The node ids data array containing the slice of the Minetest world extracted using the Voxel Manipulator. -- @param data number[] The node ids data array containing the slice of the Minetest world extracted using the Voxel Manipulator.
-- @param heightmap_old number[] The original heightmap from worldeditadditions.make_heightmap. -- @param heightmap_old number[] The original heightmap from worldeditadditions.make_heightmap.
-- @param heightmap_new number[] The new heightmap containing the altered updated values. It is expected that worldeditadditions.shallowcopy be used to make a COPY of the data worldeditadditions.make_heightmap for this purpose. Both heightmap_old AND heightmap_new are REQUIRED in order for this function to work. -- @param heightmap_new number[] The new heightmap containing the altered updated values. It is expected that worldeditadditions.table.shallowcopy be used to make a COPY of the data worldeditadditions.make_heightmap for this purpose. Both heightmap_old AND heightmap_new are REQUIRED in order for this function to work.
-- @param heightmap_size vector The x / z size of the heightmap. Any y value set in the vector is ignored. -- @param heightmap_size vector The x / z size of the heightmap. Any y value set in the vector is ignored.
-- --
function worldeditadditions.apply_heightmap_changes(pos1, pos2, area, data, heightmap_old, heightmap_new, heightmap_size) function worldeditadditions.apply_heightmap_changes(pos1, pos2, area, data, heightmap_old, heightmap_new, heightmap_size)

@ -37,7 +37,7 @@ worldedit.register_command("ellipsoid", {
require_pos = 1, require_pos = 1,
parse = function(params_text) parse = function(params_text)
local values = {parse_params_ellipsoid(params_text)} local values = {parse_params_ellipsoid(params_text)}
return unpack(values) return wea.table.unpack(values)
end, end,
nodes_needed = function(name, target_node, radius) nodes_needed = function(name, target_node, radius)
return math.ceil(4/3 * math.pi * radius.x * radius.y * radius.z) return math.ceil(4/3 * math.pi * radius.x * radius.y * radius.z)
@ -60,7 +60,7 @@ worldedit.register_command("hollowellipsoid", {
require_pos = 1, require_pos = 1,
parse = function(params_text) parse = function(params_text)
local values = {parse_params_ellipsoid(params_text)} local values = {parse_params_ellipsoid(params_text)}
return unpack(values) return wea.table.unpack(values)
end, end,
nodes_needed = function(name, target_node, radius) nodes_needed = function(name, target_node, radius)
return math.ceil(4/3 * math.pi * radius.x * radius.y * radius.z) return math.ceil(4/3 * math.pi * radius.x * radius.y * radius.z)

@ -95,7 +95,7 @@ worldedit.register_command("maze3d", {
require_pos = 2, require_pos = 2,
parse = function(params_text) parse = function(params_text)
local values = {parse_params_maze(params_text, true)} local values = {parse_params_maze(params_text, true)}
return unpack(values) return worldeditadditions.table.unpack(values)
end, end,
nodes_needed = function(name) nodes_needed = function(name)
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])

@ -51,7 +51,7 @@ worldedit.register_command("ellipsoidapply", {
local success, stats_time = worldeditadditions.ellipsoidapply( local success, stats_time = worldeditadditions.ellipsoidapply(
worldedit.pos1[name], worldedit.pos2[name], worldedit.pos1[name], worldedit.pos2[name],
function() function()
cmd.func(name, unpack(args_parsed)) cmd.func(name, worldeditadditions.table.unpack(args_parsed))
end, args end, args
) )
local time_overhead = 100 - worldeditadditions.round((stats_time.fn / stats_time.all) * 100, 3) local time_overhead = 100 - worldeditadditions.round((stats_time.fn / stats_time.all) * 100, 3)

@ -13,7 +13,7 @@ local function will_trigger_saferegion(name, cmd_name, args)
if not parse_success then return nil, table.remove(parsed, 1) end if not parse_success then return nil, table.remove(parsed, 1) end
if not def.nodes_needed then return false end if not def.nodes_needed then return false end
local result = def.nodes_needed(name, unpack(parsed)) local result = def.nodes_needed(name, wea.table.unpack(parsed))
if not result then return nil, result end if not result then return nil, result end
if result > 10000 then return true end if result > 10000 then return true end
return false return false
@ -117,7 +117,7 @@ worldedit.register_command("subdivide", {
worldedit.pos1[name] = cpos1 worldedit.pos1[name] = cpos1
worldedit.pos2[name] = cpos2 worldedit.pos2[name] = cpos2
worldedit.marker_update(name) worldedit.marker_update(name)
cmd.func(name, unpack(cmd_args_parsed)) cmd.func(name, wea.table.unpack(cmd_args_parsed))
if will_trigger_saferegion(name, cmd_name, args) then if will_trigger_saferegion(name, cmd_name, args) then
minetest.chatcommands["/y"].func(name) minetest.chatcommands["/y"].func(name)
end end

@ -18,9 +18,9 @@ worldedit.register_command("smake", {
for i=3,4 do if not parts[i] then parts[i] = false end end for i=3,4 do if not parts[i] then parts[i] = false end end
end end
-- Initialze local variables and sets -- Initialize local variables and sets
local oper, mode, targ, base = unpack(parts) local oper, mode, targ, base = wea.table.unpack(parts)
local operSet, modeSet = wea.makeset {"equal", "odd", "even"}, wea.makeset {"grow", "shrink", "avg"} local operSet, modeSet = wea.table.makeset {"equal", "odd", "even"}, wea.table.makeset {"grow", "shrink", "avg"}
-- Main Logic -- Main Logic
-- Check base if base is present and if so valid. -- Check base if base is present and if so valid.

@ -59,7 +59,7 @@ worldedit.register_command("torus", {
require_pos = 1, require_pos = 1,
parse = function(params_text) parse = function(params_text)
local values = {parse_params_torus(params_text)} local values = {parse_params_torus(params_text)}
return unpack(values) return worldeditadditions.table.unpack(values)
end, end,
nodes_needed = function(name, target_node, major_radius, minor_radius) nodes_needed = function(name, target_node, major_radius, minor_radius)
return math.ceil(2 * math.pi*math.pi * major_radius * minor_radius*minor_radius) return math.ceil(2 * math.pi*math.pi * major_radius * minor_radius*minor_radius)
@ -88,7 +88,7 @@ worldedit.register_command("hollowtorus", {
require_pos = 1, require_pos = 1,
parse = function(params_text) parse = function(params_text)
local values = {parse_params_torus(params_text)} local values = {parse_params_torus(params_text)}
return unpack(values) return worldeditadditions.table.unpack(values)
end, end,
nodes_needed = function(name, target_node, major_radius, minor_radius) nodes_needed = function(name, target_node, major_radius, minor_radius)
return math.ceil(2 * math.pi*math.pi * major_radius * minor_radius*minor_radius) return math.ceil(2 * math.pi*math.pi * major_radius * minor_radius*minor_radius)

@ -32,7 +32,7 @@ end
function worldeditadditions.doc.parse_reference() function worldeditadditions.doc.parse_reference()
local lines = get_reference() local lines = get_reference()
local headings = worldeditadditions.table_filter( local headings = worldeditadditions.table.filter(
group_by_heading(lines, 2), group_by_heading(lines, 2),
function(item, i) return item.level ~= 2 end function(item, i) return item.level ~= 2 end
) )