Merge branch 'main' into VorTechnix

This commit is contained in:
VorTechnix 2021-08-01 07:03:31 -07:00
commit b20c8f9af1
37 changed files with 256 additions and 51 deletions

62
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,62 @@
name: "CI Tests"
on: [push]
jobs:
Syntax-Check:
runs-on: ubuntu-latest
steps:
# Checkout the git repo
- name: Checkout
uses: actions/checkout@v2
- name: Install apt dependencies
run: sudo apt-get --quiet install lua5.1
- name: uname -a
run: uname -a
- name: Lua version
run: lua -v
- name: Perform Check
run: find . -type f -name '*.lua' -not -path '*luarocks*' -not -path '*.git/*' -print0 | xargs -0 -n1 -P "$(nproc)" luac -p;
Busted:
runs-on: ubuntu-latest
steps:
# Checkout the git repo
- name: Checkout
uses: actions/checkout@v2
- name: Install apt dependencies
run: sudo apt-get --quiet install lua5.1 luarocks
- name: uname -a
run: uname -a
- name: Lua version
run: lua -v
- name: Set up tests
run: ./tests.sh run
- name: Run Tests
run: ./tests.sh run
LuaCheck:
runs-on: ubuntu-latest
steps:
# Checkout the git repo
- name: Checkout
uses: actions/checkout@v2
- name: Install apt dependencies
run: sudo apt-get --quiet install lua5.1 lua-check
- name: uname -a
run: uname -a
- name: Lua version
run: lua -v
# luacheck throws lots of errors at the moment, so don't fail the build
- name: Run luacheck
run: luacheck . || true

36
.luacheckrc Normal file
View File

@ -0,0 +1,36 @@
quiet = 1
codes = true
exclude_files = {
".luarocks/*",
"worldeditadditions/utils/bit.lua"
}
ignore = {
"631", "61[124]",
"542",
"412",
"321/bit",
"21[123]"
}
-- Read-write globals (i.e. they can be defined)
globals = {
"worldedit",
"worldeditadditions",
"worldeditadditions_commands",
"worldeditadditions_core"
}
-- Read-only globals
read_globals = {
"minetest",
"vector",
"assert",
"bit",
"it",
"describe",
"bonemeal",
"dofile"
}
std = "max"

View File

@ -10,6 +10,9 @@ Note to self: See the bottom of this file for the release template text.
- Add `//wcorner` (_wireframe corners_), `//wbox` (_wireframe box_), `//compass` (_wireframe compass_) - Wireframes implemented by @VorTechnix.
- Add `//for` for executing commands while changing their arguments - Implemented by @VorTechnix.
- Add `//sshift` (_selection shift_) - WorldEdit cuboid manipulator replacements implemented by @VorTechnix.
- Use [luacheck](https://github.com/mpeterv/luacheck) to find and fix a large number of bugs and other issues
- Multiple commands: Allow using quotes (`"thing"`, `'thing'`) to quote values when splitting
## v1.12: The selection tools update (26th June 2021)
- Add `//spush`, `//spop`, and `//sstack`

View File

@ -2,6 +2,12 @@
# Make sure the current directory is the location of this script to simplify matters
cd "$(dirname "$(readlink -f "$0")")" || { echo "Error: Failed to cd to script directory" >&2; exit 1; };
# To run Luacheck:
#
# luacheck . --ignore 631 61[124] 412 21[123] --globals minetest worldedit worldeditadditions worldeditadditions_commands worldeditadditions_core vector assert bit it describe bonemeal --codes -j "$(nproc)" --quiet --exclude-files .luarocks/*
#
# This is a work-in-progress, as it currently throws an *enormous* number of warnings.
###############################################################################
log_msg() {
@ -35,6 +41,10 @@ run_setup() {
luarocks --tree "${luarocks_root}" install busted;
}
run_syntax_check() {
find . -type f -name '*.lua' -not -path '*luarocks*' -not -path '*.git/*' -print0 | xargs -0 -n1 -P "$(nproc)" luac -p;
}
run_test() {
.luarocks/bin/busted --no-auto-insulate --pattern ".test.lua" .tests;
}
@ -48,6 +58,7 @@ case "${mode}" in
if [[ ! -d "${luarocks_root}" ]]; then
run_setup;
fi
run_syntax_check;
run_test;
;;

View File

@ -47,7 +47,7 @@ function worldeditadditions.erode.river(heightmap_initial, heightmap, heightmap_
local height_up = heightmap[hi]
local height_down = heightmap[hi]
local height_left = heightmap[hi]
local height_down = heightmap[hi]
local height_right = heightmap[hi]
if x > 0 then height_left = heightmap[z*heightmap_size.x + x-1] end
if x < heightmap_size.x - 1 then height_right = heightmap[z*heightmap_size.x + x+1] end
@ -80,14 +80,14 @@ function worldeditadditions.erode.river(heightmap_initial, heightmap, heightmap_
local action = "none"
if not isedge then
if sides_higher > sides_lower then
for i,sidecount in ipairs(params.raise_sides) do
for _,sidecount in ipairs(params.raise_sides) do
if sidecount == sides_higher then
action = "fill"
break
end
end
else
for i,sidecount in ipairs(params.lower_sides) do
for _i,sidecount in ipairs(params.lower_sides) do
if sidecount == sides_lower then
action = "remove"
break
@ -109,10 +109,10 @@ function worldeditadditions.erode.river(heightmap_initial, heightmap, heightmap_
end
end
for i,hi in ipairs(fill) do
for _i,hi in ipairs(fill) do
heightmap[hi] = heightmap[hi] + 1
end
for i,hi in ipairs(remove) do
for _i,hi in ipairs(remove) do
heightmap[hi] = heightmap[hi] - 1
end

View File

@ -40,7 +40,7 @@ function worldeditadditions.forest(pos1, pos2, density_multiplier, sapling_weigh
local did_grow = false
local new_id_at_pos
local new_name_at_pos
for i=1,100 do
for attempt_number=1,100 do
bonemeal:on_use(
{ x = x, y = y, z = z },
4,
@ -55,7 +55,7 @@ function worldeditadditions.forest(pos1, pos2, density_multiplier, sapling_weigh
if not group_cache[new_id_at_pos] then
did_grow = true
-- Log the number of attempts it took to grow
table.insert(stats.attempts, i)
table.insert(stats.attempts, attempt_number)
-- Update the running total of saplings that grew
if not stats.placed[node_id] then
stats.placed[node_id] = 0

View File

@ -17,7 +17,7 @@ local function printspace(space, w, h)
end
local function generate_maze(seed, width, height, path_length, path_width)
start_time = worldeditadditions.get_ms_time()
local start_time = worldeditadditions.get_ms_time()
if not path_length then path_length = 2 end
if not path_width then path_width = 1 end

View File

@ -5,7 +5,7 @@
----------------------------------
-- function to print out the world
----------------------------------
function printspace3d(space, w, h, d)
local function printspace3d(space, w, h, d)
for z = 0, d - 1, 1 do
for y = 0, h - 1, 1 do
local line = ""
@ -18,9 +18,6 @@ function printspace3d(space, w, h, d)
end
end
-- Initialise the world
start_time = worldeditadditions.get_ms_time()
local function generate_maze3d(seed, width, height, depth, path_length, path_width, path_depth)
if not path_length then path_length = 2 end

View File

@ -37,7 +37,7 @@ function worldeditadditions.noise.params_apply_default(params)
local default_copy = wea.table.shallowcopy(params_default)
-- Keyword support
for i, keyword in ipairs(wea.noise.engines.available) do
for _i, keyword in ipairs(wea.noise.engines.available) do
if params_el[keyword] ~= nil then
params_el.algorithm = keyword
end

View File

@ -48,8 +48,8 @@ function worldeditadditions.noise.run2d(pos1, pos2, noise_params)
)
if not success then return success, message end
local success, stats = wea.apply_heightmap_changes(
local stats
success, stats = wea.apply_heightmap_changes(
pos1, pos2,
area, data,
heightmap_old, heightmap_new,

View File

@ -80,7 +80,7 @@ function worldeditadditions.scale_down(pos1, pos2, scale, anchor)
if anchor.y < 0 then posi_copy.y = size.y - posi_copy.y end
if anchor.z < 0 then posi_copy.z = size.z - posi_copy.z end
local posi_copy = vector.add(pos1, posi_copy)
posi_copy = vector.add(pos1, posi_copy)
local i_source = area:index(x, y, z)
local i_target = area:index(posi_copy.x, posi_copy.y, posi_copy.z)

View File

@ -5,7 +5,7 @@
-- @param decimals number The number of decimal places to show.
-- @return string A formatted string that represents the given input number.
function worldeditadditions.format.human_size(n, decimals)
sizes = { "", "K", "M", "G", "T", "P", "E", "Y", "Z" }
local sizes = { "", "K", "M", "G", "T", "P", "E", "Y", "Z" }
local factor = math.floor((#tostring(n) - 1) / 3)
local multiplier = 10^(decimals or 0)
local result = math.floor(0.5 + (n / math.pow(1000, factor)) * multiplier) / multiplier

View File

@ -16,7 +16,7 @@ local values = {
}
-- From http://lua-users.org/wiki/SimpleRound
function round(num, numDecimalPlaces)
local function round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
@ -37,7 +37,7 @@ end
local values_count = #values
function test(size)
local function test(size)
local cpu_start = os.clock()

View File

@ -25,7 +25,7 @@ function worldeditadditions.is_airlike(id)
return true
end
-- Just in case
if worldeditadditions.str_starts(this_node_name, "wielded_light") then
if worldeditadditions.str_starts(name, "wielded_light") then
return true
end
-- Just in case

View File

@ -21,7 +21,7 @@ function worldeditadditions.unwind_node_list(list)
local result = {}
for i,item in ipairs(list) do
local node_id = minetest.get_content_id(item.node)
for i = 1, item.weight do
for _i = 1, item.weight do
table.insert(result, node_id)
end
end

View File

@ -21,7 +21,7 @@ function worldeditadditions.parse.map(params_text, keywords)
-- Look for bools
if part_converted == "true" then part_converted = true end
if part_converted == "false" then part_converted = false end
result[last_key] = part
result[last_key] = part_converted
mode = "KEY"
else
last_key = part

View File

@ -40,7 +40,7 @@ local function tokenise(str)
-- Decrease the nested depth
nested_depth = nested_depth - 1
-- Pop the start of this block off the stack and find this block's contents
block_start = table.remove(nested_stack, #nested_stack)
local block_start = table.remove(nested_stack, #nested_stack)
local substr = str:sub(block_start, nextpos - 1)
if #substr > 0 and nested_depth == 0 then table.insert(result, substr) end
elseif char == "{" then

View File

@ -6,7 +6,7 @@ local Queue = {}
Queue.__index = Queue
function Queue.new()
result = { first = 0, last = -1, items = {} }
local result = { first = 0, last = -1, items = {} }
setmetatable(result, Queue)
return result
end

View File

@ -1,3 +1,6 @@
dofile(worldeditadditions.modpath.."/utils/strings/split.lua")
dofile(worldeditadditions.modpath.."/utils/strings/polyfill.lua")
dofile(worldeditadditions.modpath.."/utils/strings/tochars.lua")
local wea = worldeditadditions
dofile(wea.modpath.."/utils/strings/split.lua")
dofile(wea.modpath.."/utils/strings/polyfill.lua")
dofile(wea.modpath.."/utils/strings/tochars.lua")
wea.split_shell = dofile(wea.modpath.."/utils/strings/split_shell.lua")

View File

@ -0,0 +1,92 @@
-- worldeditadditions = { modpath="/home/sbrl/.minetest/worlds/Mod-Sandbox/worldmods/WorldEditAdditions/worldeditadditions/" }
local table_map = dofile(worldeditadditions.modpath.."/utils/tables/table_map.lua")
local function is_whitespace(char)
return char:match("%s")
end
local function split_shell(text)
local text_length = #text
local scan_pos = 1
local result = { }
local acc = {}
local mode = "NORMAL" -- NORMAL, INSIDE_QUOTES_SINGLE, INSIDE_QUOTES_DOUBLE
for i=1,text_length do
local prevchar = ""
local curchar = text:sub(i,i)
local nextchar = ""
local nextnextchar = ""
if i > 1 then prevchar = text:sub(i-1, i-1) end
if i < text_length then nextchar = text:sub(i+1, i+1) end
if i+1 < text_length then nextnextchar = text:sub(i+2, i+2) end
-- print("mode", mode, "prevchar", prevchar, "curchar", curchar, "nextchar", nextchar)
if mode == "NORMAL" then
if is_whitespace(curchar) and #acc > 0 then
table.insert(result, table.concat(acc, ""))
acc = {}
elseif (curchar == "\"" or curchar == "'") and #acc == 0 and prevchar ~= "\\" then
if curchar == "\"" then
mode = "INSIDE_QUOTES_DOUBLE"
else
mode = "INSIDE_QUOTES_SINGLE"
end
else
table.insert(acc, curchar)
end
elseif mode == "INSIDE_QUOTES_DOUBLE" then
if curchar == "\"" and prevchar ~= "\\" and (is_whitespace(nextchar) or #nextchar == 0) then
-- It's the end of a quote!
mode = "NORMAL"
elseif (curchar == "\\" and (
nextchar ~= "\""
or (nextchar == "\"" and not is_whitespace(nextnextchar))
)) or curchar ~= "\\" then
-- It's a regular character
table.insert(acc, curchar)
end
elseif mode == "INSIDE_QUOTES_SINGLE" then
if curchar == "'" and prevchar ~= "\\" and is_whitespace(nextchar) then
-- It's the end of a quote!
mode = "NORMAL"
elseif (curchar == "\\" and (
nextchar ~= "'"
or (nextchar == "'" and not is_whitespace(nextnextchar))
)) or curchar ~= "\\" then
-- It's a regular character
table.insert(acc, curchar)
end
end
end
if #acc > 0 then
table.insert(result, table.concat(acc, ""))
end
-- Unwind all escapes by 1 level
return table_map(result, function(str)
return str:gsub("\\([\"'\\])", "%1")
end)
end
return split_shell
-- local function test(text)
-- print("Source", text)
-- for i,value in ipairs(split_shell(text)) do
-- print("i", i, "→", value)
-- end
-- print("************")
-- end
--
-- test("yay yay yay")
-- test("dirt \"snow block\"")
-- test("yay \"yay yay\" yay")
-- test("yay \"yay\\\" yay\" yay")
-- test("yay \"yay 'inside quotes' yay\\\"\" yay")
-- test("yay 'inside quotes' another")
-- test("y\"ay \"yay 'in\\\"side quotes' yay\" y\\\"ay")

View File

@ -15,7 +15,7 @@ worldedit.register_command("bonemeal", {
params_text = "1"
end
local parts = worldeditadditions.split(params_text, "%s+", false)
local parts = worldeditadditions.split_shell(params_text, "%s+", false)
local strength = 1
local chance = 1

View File

@ -11,7 +11,8 @@ worldedit.register_command("convolve", {
parse = function(params_text)
if not params_text then params_text = "" end
local parts = worldeditadditions.split(params_text, "%s+", false)
-- local parts = worldeditadditions.split(params_text, "%s+", false)
local parts = worldeditadditions.split_shell(params_text)
local kernel_name = "gaussian"
local width = 5
@ -58,10 +59,12 @@ worldedit.register_command("convolve", {
kernel_size[0] = kernel_height
kernel_size[1] = kernel_width
local success, stats = worldeditadditions.convolve(
local stats
success, stats = worldeditadditions.convolve(
worldedit.pos1[name], worldedit.pos2[name],
kernel, kernel_size
)
if not success then return success, stats end
local time_taken = worldeditadditions.get_ms_time() - start_time

View File

@ -5,7 +5,7 @@
-- ███████ ███████ ███████ ██ ██ ███████ ██████ ██ ██████
local wea = worldeditadditions
local function parse_params_ellipsoid(params_text)
local parts = wea.split(params_text, "%s+", false)
local parts = wea.split_shell(params_text)
if #parts < 4 then
return false, "Error: Not enough arguments. Expected \"<rx> <ry> <rz> <replace_node> [h[ollow]]\"."

View File

@ -18,7 +18,7 @@ worldedit.register_command("forest", {
end
local success, sapling_list = worldeditadditions.parse.weighted_nodes(
worldeditadditions.split(params_text, "%s+", false),
worldeditadditions.split_shell(params_text),
false,
function(name)
return worldedit.normalize_nodename(

View File

@ -14,7 +14,7 @@ worldedit.register_command("layers", {
end
local success, node_list = worldeditadditions.parse.weighted_nodes(
worldeditadditions.split(params_text, "%s+", false),
worldeditadditions.split_shell(params_text),
true
)
return success, node_list

View File

@ -24,8 +24,7 @@ worldedit.register_command("line", {
replace_node = worldedit.normalize_nodename(replace_node)
if not replace_node then
worldedit.player_notify(name, "Error: Invalid node name.")
return false
return false, "Error: Invalid node name '"..replace_node.."'."
end
return true, replace_node, radius

View File

@ -5,7 +5,7 @@ local function parse_params_maze(params_text, is_3d)
return false, "No arguments specified"
end
local parts = worldeditadditions.split(params_text, "%s+", false)
local parts = worldeditadditions.split_shell(params_text)
local replace_node = parts[1]
local seed = os.time()

View File

@ -43,7 +43,7 @@ worldedit.register_command("airapply", {
end,
func = function(name, cmd, args_parsed)
if not minetest.check_player_privs(name, cmd.privs) then
return false, "Your privileges are insufficient to execute the command '"..cmd_name.."'."
return false, "Your privileges are insufficient to execute the command '"..cmd.."'."
end
local pos1, pos2 = worldeditadditions.Vector3.sort(
@ -56,7 +56,7 @@ worldedit.register_command("airapply", {
pos1, pos2,
function()
cmd.func(name, worldeditadditions.table.unpack(args_parsed))
end, args
end, args_parsed
)

View File

@ -45,14 +45,14 @@ worldedit.register_command("ellipsoidapply", {
end,
func = function(name, cmd, args_parsed)
if not minetest.check_player_privs(name, cmd.privs) then
return false, "Your privileges are insufficient to execute the command '"..cmd_name.."'."
return false, "Your privileges are insufficient to execute the command '"..cmd.."'."
end
local success, stats_time = worldeditadditions.ellipsoidapply(
worldedit.pos1[name], worldedit.pos2[name],
function()
cmd.func(name, worldeditadditions.table.unpack(args_parsed))
end, args
end, args_parsed
)
local time_overhead = 100 - worldeditadditions.round((stats_time.fn / stats_time.all) * 100, 3)

View File

@ -3,6 +3,7 @@
-- explode(separator, string)
-- From http://lua-users.org/wiki/SplitJoin
-- TODO: Refactor this to use wea.split instead
local function explode(delim, str)
local ll, is_done
local delim_length = string.len(delim)
@ -12,7 +13,7 @@ local function explode(delim, str)
return function()
if is_done then return end
local result = nil
local result
local loc = string.find(str, delim, ll, true) -- find the next d in the string
if loc ~= nil then -- if "not not" found then..
result = string.sub(str, ll, loc - 1) -- Save it in our array.

View File

@ -12,7 +12,7 @@ local function explode(delim, str)
return function()
if is_done then return end
local result = nil
local result
local loc = string.find(str, delim, ll, true) -- find the next d in the string
if loc ~= nil then -- if "not not" found then..
result = string.sub(str, ll, loc - 1) -- Save it in our array.
@ -35,8 +35,6 @@ minetest.register_chatcommand("/multi", {
params_text = worldeditadditions.trim(params_text)
if #params_text == 0 then return false, "Error: No commands specified, so there's nothing to do." end
local i = 1 -- For feedback only
local master_start_time = worldeditadditions.get_ms_time()
local times = {}

View File

@ -93,7 +93,7 @@ worldedit.register_command("subdivide", {
local cmd_args_parsed = {cmd.parse(args)}
local success = table.remove(cmd_args_parsed, 1)
if not success then
return false, cmd_name..": "..(parsed[1] or "invalid usage")
return false, cmd_name..": "..(cmd_args_parsed[1] or "invalid usage")
end
wea.subdivide(pos1, pos2, chunk_size, function(cpos1, cpos2, stats)

View File

@ -10,7 +10,7 @@ worldedit.register_command("overlay", {
require_pos = 2,
parse = function(params_text)
local success, node_list = worldeditadditions.parse.weighted_nodes(
worldeditadditions.split(params_text, "%s+", false)
worldeditadditions.split_shell(params_text)
)
return success, node_list
end,

View File

@ -15,7 +15,7 @@ worldedit.register_command("replacemix", {
return false, "Error: No arguments specified"
end
local parts = wea.split(params_text, "%s+", false)
local parts = wea.split_shell(params_text)
local target_node = nil
local target_node_chance = 1

View File

@ -30,14 +30,14 @@ worldedit.register_command("scale", {
parse = function(params_text)
if not params_text then params_text = "" end
local parts = worldeditadditions.split(params_text, "%s+", false)
local parts = worldeditadditions.split_shell(params_text)
local scale = vector.new(1, 1, 1)
local anchor = vector.new(1, 1, 1)
if #parts == 2 then
if not (parts[1] == "x" or parts[1] == "y" or parts[1] == "z"
or parts[1] == "-x" or parts[1] == "-y" or parts[1] == "-z") then
or parts[1] == "-x" or parts[1] == "-y" or parts[1] == "-z") then
return false, "Error: Got 2 arguments, but the first doesn't look like the name of an axis."
end
local axis = parts[1]

View File

@ -4,7 +4,7 @@
-- ██ ██ ██ ██ ██ ██ ██ ██
-- ██ ██████ ██ ██ ██████ ███████
local function parse_params_torus(params_text)
local parts = worldeditadditions.split(params_text, "%s+", false)
local parts = worldeditadditions.split_shell(params_text)
if #parts < 1 then
return false, "Error: No replace_node specified."

View File

@ -37,7 +37,7 @@ function worldeditadditions.doc.parse_reference()
function(item, i) return item.level ~= 2 end
)
for i,value in ipairs(headings) do
print(i, "level", level, "heading", heading, "text", text)
print(i, "level", value.level, "heading", value.heading, "text", value.text)
end
end