mirror of
https://codeberg.org/AntumLuanti/mod-cleaner.git
synced 2025-04-30 22:21:44 -04:00
Compare commits
No commits in common. "master" and "v0.1" have entirely different histories.
30 changed files with 69 additions and 2362 deletions
11
.cdb.json
11
.cdb.json
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"type": "MOD",
|
|
||||||
"title": "Cleaner",
|
|
||||||
"short_description": "Remove/Replace unknown entities, nodes, & items.",
|
|
||||||
"license": "MIT",
|
|
||||||
"media_license": "CC0-1.0",
|
|
||||||
"tags": ["world_tools"],
|
|
||||||
"repo": "https://codeberg.org/AntumLuanti/mod-cleaner",
|
|
||||||
"issue_tracker": "https://codeberg.org/AntumLuanti/mod-cleaner/issues",
|
|
||||||
"forums": 18381
|
|
||||||
}
|
|
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -1,2 +0,0 @@
|
||||||
.* export-ignore
|
|
||||||
*.py export-ignore
|
|
30
.github/workflows/reference.yml
vendored
30
.github/workflows/reference.yml
vendored
|
@ -1,30 +0,0 @@
|
||||||
|
|
||||||
name: Build Reference
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- 'v[0-9]*'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build Reference
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Setup Lua
|
|
||||||
uses: leafo/gh-actions-lua@v8
|
|
||||||
with:
|
|
||||||
luaVersion: 5.4
|
|
||||||
- name: Setup Lua Rocks
|
|
||||||
uses: leafo/gh-actions-luarocks@v4
|
|
||||||
- name: Setup dependencies
|
|
||||||
run: luarocks install --only-deps https://raw.githubusercontent.com/lunarmodules/LDoc/master/ldoc-scm-3.rockspec
|
|
||||||
- name: Setup LDoc
|
|
||||||
run: git clone --single-branch --branch=custom https://github.com/AntumDeluge/LDoc.git ldoc
|
|
||||||
- name: Checkout & Build Docs
|
|
||||||
run: git clone https://github.com/AntumMT/mod-cleaner.git cleaner && cd cleaner && chmod +x .ldoc/build_versioned_docs.sh && ./.ldoc/build_versioned_docs.sh
|
|
||||||
- name: Deploy
|
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
publish_dir: cleaner/docs/
|
|
|
@ -1,98 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# place this file in mod ".ldoc" directory
|
|
||||||
|
|
||||||
|
|
||||||
d_config="$(dirname $(readlink -f $0))"
|
|
||||||
|
|
||||||
cd "${d_config}/.."
|
|
||||||
|
|
||||||
d_root="$(pwd)"
|
|
||||||
d_export="${d_export:-${d_root}/docs/reference}"
|
|
||||||
|
|
||||||
cmd_ldoc="${d_root}/../ldoc/ldoc.lua"
|
|
||||||
if test -f "${cmd_ldoc}"; then
|
|
||||||
if test ! -x "${cmd_ldoc}"; then
|
|
||||||
chmod +x "${cmd_ldoc}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
cmd_ldoc="ldoc"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# clean old files
|
|
||||||
rm -rf "${d_export}"
|
|
||||||
|
|
||||||
# store current branch
|
|
||||||
main_branch="$(git branch --show-current)"
|
|
||||||
|
|
||||||
html_out="<html>\n<head></head>\n\n<body>\n\n<ul>\n"
|
|
||||||
|
|
||||||
# generate new doc files
|
|
||||||
mkdir -p "${d_export}"
|
|
||||||
for vinfo in $(git tag -l --sort=-v:refname | grep "^v[0-9]"); do
|
|
||||||
echo -e "\nbuilding ${vinfo} docs ..."
|
|
||||||
git checkout ${vinfo}
|
|
||||||
d_temp="${d_config}/temp"
|
|
||||||
mkdir -p "${d_temp}"
|
|
||||||
|
|
||||||
# backward compat
|
|
||||||
f_config="${d_root}/docs/config.ld"
|
|
||||||
if test ! -f "${f_config}"; then
|
|
||||||
f_config="${d_config}/config.ld"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test ! -f "${f_config}"; then
|
|
||||||
echo -e "\nLDoc config not available for ${vinfo}, skipping build ..."
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
"${cmd_ldoc}" --UNSAFE_NO_SANDBOX --multimodule -c "${f_config}" -d "${d_temp}" "${d_root}"; retval=$?
|
|
||||||
if test ${retval} -ne 0; then
|
|
||||||
echo -e "\nERROR: doc build for ${vinfo} failed!"
|
|
||||||
rm -rf "${d_temp}"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# show version info
|
|
||||||
for html in $(find "${d_temp}" -type f -name "*.html"); do
|
|
||||||
sed -i -e "s|^<h1>[cC]leaner</h1>$|<h1>Cleaner <span style=\"font-size:12pt;\">(${vinfo})</span></h1>|" \
|
|
||||||
"${html}"
|
|
||||||
done
|
|
||||||
|
|
||||||
if test -d "${d_root}/textures"; then
|
|
||||||
# copy textures to data directory
|
|
||||||
echo -e "\ncopying textures ..."
|
|
||||||
d_data="${d_temp}/data"
|
|
||||||
mkdir -p "${d_data}"
|
|
||||||
texture_count=0
|
|
||||||
for png in $(find "${d_root}/textures" -maxdepth 1 -type f -name "*.png"); do
|
|
||||||
t_png="${d_data}/$(basename ${png})"
|
|
||||||
if test -f "${t_png}"; then
|
|
||||||
echo "WARNING: not overwriting existing file: ${t_png}"
|
|
||||||
else
|
|
||||||
cp "${png}" "${d_data}"
|
|
||||||
texture_count=$((texture_count + 1))
|
|
||||||
printf "\rcopied ${texture_count} textures"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv "${d_temp}" "${d_export}/${vinfo}"
|
|
||||||
if test -z ${vcur+x}; then
|
|
||||||
vcur="${vinfo}"
|
|
||||||
ln -s "${d_export}/${vinfo}" "${d_export}/current"
|
|
||||||
ln -s "${d_export}/${vinfo}" "${d_export}/latest"
|
|
||||||
html_out="${html_out} <li><a href=\"current/\">current</a></li>\n"
|
|
||||||
html_out="${html_out} <li><a href=\"latest/\">latest</a></li>\n"
|
|
||||||
fi
|
|
||||||
html_out="${html_out} <li><a href=\"${vinfo}/\">${vinfo}</a></li>\n"
|
|
||||||
done
|
|
||||||
|
|
||||||
html_out="${html_out}</ul>\n\n</body></html>"
|
|
||||||
|
|
||||||
cd "${d_root}"
|
|
||||||
git checkout ${main_branch}
|
|
||||||
|
|
||||||
echo -e "${html_out}" > "${d_export}/index.html"
|
|
||||||
|
|
||||||
echo -e "\nDone!"
|
|
201
.ldoc/config.ld
201
.ldoc/config.ld
|
@ -1,201 +0,0 @@
|
||||||
|
|
||||||
local dofile, print, error, type, table, ipairs, string, tostring
|
|
||||||
if import then
|
|
||||||
dofile = import("dofile")
|
|
||||||
print = import("print")
|
|
||||||
error = import("error")
|
|
||||||
type = import("type")
|
|
||||||
table = import("table")
|
|
||||||
ipairs = import("ipairs")
|
|
||||||
string = import("string")
|
|
||||||
tostring = import("tostring")
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
project = "Cleaner"
|
|
||||||
title = "Cleaner mod for Luanti"
|
|
||||||
format = "markdown"
|
|
||||||
not_luadoc=true
|
|
||||||
boilerplate = false
|
|
||||||
icon = "textures/cleaner_pencil.png"
|
|
||||||
favicon = "https://www.luanti.org/media/icon.svg"
|
|
||||||
|
|
||||||
file = {
|
|
||||||
"settings.lua",
|
|
||||||
"api.lua",
|
|
||||||
"chat.lua",
|
|
||||||
"tools.lua",
|
|
||||||
".ldoc/config.luadoc",
|
|
||||||
}
|
|
||||||
|
|
||||||
new_type("chatcmd", "Chat Commands")
|
|
||||||
new_type("setting", "Settings")
|
|
||||||
new_type("tool", "Tools")
|
|
||||||
new_type("json", "JSON Configurations")
|
|
||||||
|
|
||||||
|
|
||||||
local function video_frame(src)
|
|
||||||
return '<iframe width="560" height="315" src="' .. src
|
|
||||||
.. '" title="Video Player" frameborder="0"'
|
|
||||||
.. ' allow="fullscreen;"></iframe>'
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local tags
|
|
||||||
tags, custom_tags = dofile(".ldoc/tags.ld")
|
|
||||||
|
|
||||||
|
|
||||||
-- START: handling items to prevent re-parsing
|
|
||||||
|
|
||||||
local registered_items = {}
|
|
||||||
|
|
||||||
local function is_registered(item)
|
|
||||||
if not registered_items[item.type] then return false end
|
|
||||||
|
|
||||||
for _, tbl in ipairs(registered_items[item.type]) do
|
|
||||||
if item == tbl then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local function register(item)
|
|
||||||
if not registered_items[item.type] then
|
|
||||||
registered_items[item.type] = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
if not is_registered(item) then
|
|
||||||
table.insert(registered_items[item.type], item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- END:
|
|
||||||
|
|
||||||
|
|
||||||
local function format_setting_tag(desc, value)
|
|
||||||
return "\n- <span style=\"font-size:80%;\">`" .. desc .. ":`</span> `" .. value .. "`"
|
|
||||||
end
|
|
||||||
|
|
||||||
local function setting_handler(item)
|
|
||||||
if not ipairs or not type then
|
|
||||||
return item
|
|
||||||
end
|
|
||||||
|
|
||||||
local tags = {
|
|
||||||
{"settype", "type"},
|
|
||||||
{"default"},
|
|
||||||
{"min", "minimum value"},
|
|
||||||
{"max", "maximum value"},
|
|
||||||
}
|
|
||||||
|
|
||||||
local def = {
|
|
||||||
["settype"] = format_setting_tag("type", "string"),
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, t in ipairs(tags) do
|
|
||||||
local name = t[1]
|
|
||||||
local desc = t[2]
|
|
||||||
if not desc then desc = name end
|
|
||||||
|
|
||||||
local value = item.tags[name]
|
|
||||||
if type(value) == "table" then
|
|
||||||
if #value > 1 then
|
|
||||||
local msg = item.file.filename .. " (line " .. item.lineno
|
|
||||||
.. "): multiple instances of tag \"" .. name .. "\" found"
|
|
||||||
if error then
|
|
||||||
error(msg)
|
|
||||||
elseif print then
|
|
||||||
print("WARNING: " .. msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if value[1] then
|
|
||||||
def[name] = format_setting_tag(desc, value[1])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
item.description = item.description .. "\n\n**Definition:**\n" .. def.settype
|
|
||||||
for _, t in ipairs({def.default, def.min, def.max}) do
|
|
||||||
if t then
|
|
||||||
item.description = item.description .. t
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return item
|
|
||||||
end
|
|
||||||
|
|
||||||
local function chatcmd_handler(item)
|
|
||||||
for _, p in ipairs(item.params) do
|
|
||||||
if item.modifiers.param[p].opt then
|
|
||||||
item.name = item.name .. " [" .. p .. "]"
|
|
||||||
else
|
|
||||||
item.name = item.name .. " <" .. p .. ">"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if #item.params > 0 then
|
|
||||||
local pstring = "### Parameters:\n"
|
|
||||||
for k, param in pairs(item.params) do
|
|
||||||
if type(k) == "number" then
|
|
||||||
local value = item.params.map[param]
|
|
||||||
|
|
||||||
pstring = pstring .. '\n- <span class="parameter">'
|
|
||||||
.. param .. '</span>'
|
|
||||||
|
|
||||||
local modifiers = item.modifiers.param[param]
|
|
||||||
if modifiers and modifiers.type then
|
|
||||||
pstring = pstring .. ' <span class="types"><span class="type">`' .. modifiers.type .. '`</span></span>'
|
|
||||||
end
|
|
||||||
|
|
||||||
if value then
|
|
||||||
pstring = pstring .. value
|
|
||||||
end
|
|
||||||
|
|
||||||
if modifiers and modifiers.opt then
|
|
||||||
pstring = pstring .. " *(optional)*"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
item.description = item.description .. "\n\n" .. pstring
|
|
||||||
-- clear parameter list
|
|
||||||
item.params = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
return item
|
|
||||||
end
|
|
||||||
|
|
||||||
function custom_display_name_handler(item, default_handler)
|
|
||||||
if not is_registered(item) then
|
|
||||||
if item.type == "setting" then
|
|
||||||
item = setting_handler(item)
|
|
||||||
elseif item.type == "chatcmd" then
|
|
||||||
item = chatcmd_handler(item)
|
|
||||||
end
|
|
||||||
|
|
||||||
local parse_tags = {"priv", "note"}
|
|
||||||
for _, pt in ipairs(parse_tags) do
|
|
||||||
local tvalues = item.tags[pt]
|
|
||||||
if tvalues then
|
|
||||||
local tstring = ""
|
|
||||||
|
|
||||||
local title = tags.get_title(pt)
|
|
||||||
if title then
|
|
||||||
tstring = tstring .. "\n\n### " .. title .. ":\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, tv in ipairs(tvalues) do
|
|
||||||
tstring = tstring .. "\n- " .. tags.format(pt, tv)
|
|
||||||
end
|
|
||||||
|
|
||||||
item.description = item.description .. tstring
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
register(item)
|
|
||||||
return default_handler(item)
|
|
||||||
end
|
|
|
@ -1,55 +0,0 @@
|
||||||
|
|
||||||
--- World Path Configuration
|
|
||||||
--
|
|
||||||
-- @topic config
|
|
||||||
|
|
||||||
|
|
||||||
--- Main configuration file.
|
|
||||||
--
|
|
||||||
-- Registering items, entities, etc. for cleaning can be done in ***cleaner.json***
|
|
||||||
-- in the world directory (`<world_path>/cleaner.json`). If it does not exist
|
|
||||||
-- it will be created automatically when the server is started.
|
|
||||||
--
|
|
||||||
-- It is formatted as follows:
|
|
||||||
--
|
|
||||||
-- {
|
|
||||||
-- "entities" :
|
|
||||||
-- {
|
|
||||||
-- "remove" : []
|
|
||||||
-- },
|
|
||||||
-- "items" :
|
|
||||||
-- {
|
|
||||||
-- "replace" : {}
|
|
||||||
-- },
|
|
||||||
-- "nodes" :
|
|
||||||
-- {
|
|
||||||
-- "remove" : [],
|
|
||||||
-- "replace" : {}
|
|
||||||
-- },
|
|
||||||
-- "ores" :
|
|
||||||
-- {
|
|
||||||
-- "remove" : []
|
|
||||||
-- }
|
|
||||||
-- }
|
|
||||||
--
|
|
||||||
-- `remove` key works for nodes, entities, & ores. `replace` key works for
|
|
||||||
-- nodes & items. Their functions are self-explanatory.
|
|
||||||
--
|
|
||||||
-- @json cleaner.json
|
|
||||||
-- @usage
|
|
||||||
-- Cleaning nodes example:
|
|
||||||
-- {
|
|
||||||
-- "nodes" :
|
|
||||||
-- {
|
|
||||||
-- "remove" :
|
|
||||||
-- [
|
|
||||||
-- "old:node_1",
|
|
||||||
-- "old:node_2",
|
|
||||||
-- ],
|
|
||||||
-- "replace" :
|
|
||||||
-- {
|
|
||||||
-- "old:node_3" : "new:node_1",
|
|
||||||
-- "old:node_4" : "new:node_2",
|
|
||||||
-- },
|
|
||||||
-- },
|
|
||||||
-- }
|
|
|
@ -1,54 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# place this file in mod ".ldoc" directory
|
|
||||||
|
|
||||||
|
|
||||||
d_ldoc="$(dirname $(readlink -f $0))"
|
|
||||||
f_config="${d_ldoc}/config.ld"
|
|
||||||
|
|
||||||
cd "${d_ldoc}/.."
|
|
||||||
|
|
||||||
d_root="$(pwd)"
|
|
||||||
d_export="${d_export:-${d_root}/docs/reference}"
|
|
||||||
|
|
||||||
cmd_ldoc="${d_ldoc}/ldoc/ldoc.lua"
|
|
||||||
if test ! -x "${cmd_ldoc}"; then
|
|
||||||
cmd_ldoc="ldoc"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# clean old files
|
|
||||||
rm -rf "${d_export}"
|
|
||||||
|
|
||||||
vinfo="v$(grep "^version = " "${d_root}/mod.conf" | head -1 | sed -e 's/version = //')"
|
|
||||||
d_data="${d_export}/${vinfo}/data"
|
|
||||||
|
|
||||||
# generate new doc files
|
|
||||||
"${cmd_ldoc}" --UNSAFE_NO_SANDBOX --multimodule -c "${f_config}" -d "${d_export}/${vinfo}" "${d_root}"; retval=$?
|
|
||||||
|
|
||||||
# check exit status
|
|
||||||
if test ${retval} -ne 0; then
|
|
||||||
echo -e "\nan error occurred (ldoc return code: ${retval})"
|
|
||||||
exit ${retval}
|
|
||||||
fi
|
|
||||||
|
|
||||||
# show version info
|
|
||||||
for html in $(find "${d_export}/${vinfo}" -type f -name "*.html"); do
|
|
||||||
sed -i -e "s|^<h1>[cC]leaner</h1>$|<h1>Cleaner <span style=\"font-size:12pt;\">(${vinfo})</span></h1>|" "${html}"
|
|
||||||
done
|
|
||||||
|
|
||||||
# copy textures to data directory
|
|
||||||
echo -e "\ncopying textures ..."
|
|
||||||
mkdir -p "${d_data}"
|
|
||||||
texture_count=0
|
|
||||||
for png in $(find "${d_root}/textures" -maxdepth 1 -type f -name "*.png"); do
|
|
||||||
t_png="${d_data}/$(basename ${png})"
|
|
||||||
if test -f "${t_png}"; then
|
|
||||||
echo "WARNING: not overwriting existing file: ${t_png}"
|
|
||||||
else
|
|
||||||
cp "${png}" "${d_data}"
|
|
||||||
texture_count=$((texture_count + 1))
|
|
||||||
printf "\rcopied ${texture_count} textures"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo -e "\n\nDone!"
|
|
|
@ -1,81 +0,0 @@
|
||||||
|
|
||||||
local tags = {}
|
|
||||||
local tag_list = {}
|
|
||||||
local custom_tags = {}
|
|
||||||
|
|
||||||
local register_tag = function(name, tag)
|
|
||||||
local new_tag = {name, title=tag.title, hidden=tag.hidden, format=tag.format}
|
|
||||||
table.insert(custom_tags, new_tag)
|
|
||||||
tag_list[name] = {title=tag.title, format=tag.format}
|
|
||||||
end
|
|
||||||
|
|
||||||
tags.get_title = function(tname)
|
|
||||||
local t = tag_list[tname]
|
|
||||||
if t then
|
|
||||||
return t.title
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
tags.format = function(tname, value)
|
|
||||||
local t = tag_list[tname]
|
|
||||||
if t then
|
|
||||||
if type(t.format) == "function" then
|
|
||||||
value = t.format(value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return value
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local new_tags = {
|
|
||||||
["priv"] = {
|
|
||||||
title = "Required Privileges",
|
|
||||||
hidden = true,
|
|
||||||
},
|
|
||||||
["note"] = {
|
|
||||||
title = "Notes",
|
|
||||||
hidden = true,
|
|
||||||
format = function(value)
|
|
||||||
return "*" .. value .. "*"
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
["video"] = {
|
|
||||||
title = "Video",
|
|
||||||
format = video_frame,
|
|
||||||
},
|
|
||||||
["youtube"] = {
|
|
||||||
title = "Video",
|
|
||||||
format = function(value)
|
|
||||||
return video_frame("https://www.youtube.com/embed/" .. value)
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
-- settings
|
|
||||||
["settype"] = {
|
|
||||||
title = "Setting Type",
|
|
||||||
hidden = true,
|
|
||||||
},
|
|
||||||
["default"] = {
|
|
||||||
title = "Default Value",
|
|
||||||
hidden = true,
|
|
||||||
},
|
|
||||||
-- craft items/tools
|
|
||||||
["img"] = {
|
|
||||||
title = "Image",
|
|
||||||
format = function(value)
|
|
||||||
return "<img src=\"../data/" .. value .. "\" style=\"width:32px; height:32px;\" />"
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
-- chat commands
|
|
||||||
["chatparam"] = {
|
|
||||||
title = "Parameters",
|
|
||||||
hidden = true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v in pairs(new_tags) do
|
|
||||||
register_tag(k, v)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
return tags, custom_tags
|
|
34
LICENSE.txt
34
LICENSE.txt
|
@ -1,21 +1,13 @@
|
||||||
The MIT License (MIT)
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
Copyright © 2021 Jordan Irwin (AntumDeluge)
|
|
||||||
|
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
the Software without restriction, including without limitation the rights to
|
copies of this license document, and changing it is allowed as long
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
as the name is changed.
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
100
README.md
100
README.md
|
@ -1,86 +1,18 @@
|
||||||
## Cleaner mod for Luanti
|
## Clean mod for [Minetest][]
|
||||||
|
|
||||||
### Description:
|
|
||||||
|
|
||||||
A [Luanti (Minetest)][Luanti] mod that can be used to remove/replace unknown entities, nodes, & items. Originally forked from [PilzAdam's ***clean*** mod][f.pilzadam].
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Licensing:
|
|
||||||
|
|
||||||
- Code: [MIT](LICENSE.txt)
|
|
||||||
- Textures: CC0
|
|
||||||
|
|
||||||
### Requirements:
|
|
||||||
|
|
||||||
- Luanti minimum version: 5.0
|
|
||||||
- Depends: none
|
|
||||||
|
|
||||||
### Usage:
|
|
||||||
|
|
||||||
Registering items, entities, etc. for cleaning can be done in `cleaner.json` in the world directory. If it does not exist it will be created automatically when the server is started.
|
|
||||||
|
|
||||||
It is formatted as follows:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"entities" :
|
|
||||||
{
|
|
||||||
"remove" : []
|
|
||||||
},
|
|
||||||
"items" :
|
|
||||||
{
|
|
||||||
"replace" : {}
|
|
||||||
},
|
|
||||||
"nodes" :
|
|
||||||
{
|
|
||||||
"remove" : [],
|
|
||||||
"replace" : {}
|
|
||||||
},
|
|
||||||
"ores" :
|
|
||||||
{
|
|
||||||
"remove" : []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Cleaning nodes example:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"nodes" :
|
|
||||||
{
|
|
||||||
"remove" : [
|
|
||||||
"old:node_1",
|
|
||||||
"old:node_2",
|
|
||||||
],
|
|
||||||
"replace" : {
|
|
||||||
"old:node_3" : "new:node_1",
|
|
||||||
"old:node_4" : "new:node_2",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`remove` key works for nodes, entities, & ores. `replace` key works for nodes & items. Their functions are self-explanatory.
|
|
||||||
|
|
||||||
#### Settings:
|
|
||||||
|
|
||||||
```
|
|
||||||
cleaner.unsafe
|
|
||||||
- Enables unsafe methods & commands (remove_ore).
|
|
||||||
- type: bool
|
|
||||||
- default: false
|
|
||||||
```
|
|
||||||
|
|
||||||
### Links:
|
|
||||||
|
|
||||||
- [][ContentDB]
|
|
||||||
- [Forum](https://forum.luanti.org/viewtopic.php?t=18381)
|
|
||||||
- [Git repo](https://github.com/AntumMT/mod-cleaner)
|
|
||||||
- [Reference](https://antummt.github.io/mod-cleaner/reference/latest/)
|
|
||||||
- [Changelog](changelog.txt)
|
|
||||||
- [TODO](TODO.txt)
|
|
||||||
|
|
||||||
|
|
||||||
[Luanti]: https://luanti.org/
|
---
|
||||||
[f.pilzadam]: https://forum.luanti.org/viewtopic.php?t=2777
|
### **Description:**
|
||||||
[ContentDB]: https://content.luanti.org/packages/AntumDeluge/cleaner/
|
|
||||||
|
Fork of [PilzAdam's ***clean*** mod][f.pilzadam] for Minetest.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
### **Licensing:**
|
||||||
|
|
||||||
|
[WTFPL](LICENSE.txt)
|
||||||
|
|
||||||
|
|
||||||
|
[Minetest]: http://www.minetest.net/
|
||||||
|
|
||||||
|
[f.pilzadam]: https://forum.minetest.net/viewtopic.php?t=2777
|
||||||
|
|
14
TODO.txt
14
TODO.txt
|
@ -1,14 +0,0 @@
|
||||||
|
|
||||||
TODO:
|
|
||||||
- update world file when chat commands are used
|
|
||||||
- update inventories when items are replaced:
|
|
||||||
- creative
|
|
||||||
- storage (chests, etc.)
|
|
||||||
- add LBM when removing an item if it is a node
|
|
||||||
- add "radius" option for pencil or "xlen", "ylen", & "zlen" options
|
|
||||||
- add "xrotate" & "zrorate" modes for pencil
|
|
||||||
- don't require "server" priv for "find_unknown_nodes" & "find_neaby_nodes" commands
|
|
||||||
- add chat command to find nodes with specified attributes
|
|
||||||
- may be better to update player inventories on login than add aliases for items
|
|
||||||
- use aliases for unknown nodes instead of LBM
|
|
||||||
- only use LBM when a node to replace is still registered
|
|
194
api.lua
194
api.lua
|
@ -1,194 +0,0 @@
|
||||||
|
|
||||||
--- Cleaner API
|
|
||||||
--
|
|
||||||
-- @topic api
|
|
||||||
|
|
||||||
|
|
||||||
local replace_items = {}
|
|
||||||
local replace_nodes = {}
|
|
||||||
|
|
||||||
|
|
||||||
--- Retrieves list of items to be replaced.
|
|
||||||
--
|
|
||||||
-- @treturn table Items to be replaced.
|
|
||||||
function cleaner.get_replace_items()
|
|
||||||
return replace_items
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Retrieves list of nodes to be replaced.
|
|
||||||
--
|
|
||||||
-- @treturn table Nodes to be replaced.
|
|
||||||
function cleaner.get_replace_nodes()
|
|
||||||
return replace_nodes
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Registers an entity to be removed.
|
|
||||||
--
|
|
||||||
-- @tparam string src Entity technical name.
|
|
||||||
function cleaner.register_entity_removal(src)
|
|
||||||
core.register_entity(":" .. src, {
|
|
||||||
on_activate = function(self, ...)
|
|
||||||
self.object:remove()
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Registers a node to be removed.
|
|
||||||
--
|
|
||||||
-- @tparam string src Node technical name.
|
|
||||||
function cleaner.register_node_removal(src)
|
|
||||||
core.register_node(":" .. src, {
|
|
||||||
groups = {to_remove=1},
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
local function update_list(inv, listname, src, tgt)
|
|
||||||
if not inv then
|
|
||||||
cleaner.log("error", "cannot update list of unknown inventory")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local list = inv:get_list(listname)
|
|
||||||
if not list then
|
|
||||||
cleaner.log("warning", "unknown inventory list: " .. listname)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
for idx, stack in pairs(list) do
|
|
||||||
if stack:get_name() == src then
|
|
||||||
local new_stack = ItemStack(tgt)
|
|
||||||
new_stack:set_count(stack:get_count())
|
|
||||||
inv:set_stack(listname, idx, new_stack)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Replaces an item with another registered item.
|
|
||||||
--
|
|
||||||
-- @tparam string src Technical name of item to be replaced.
|
|
||||||
-- @tparam string tgt Technical name of item to be used in place.
|
|
||||||
-- @tparam[opt] bool update_players `true` updates inventory lists associated with players (default: `false`).
|
|
||||||
function cleaner.replace_item(src, tgt, update_players)
|
|
||||||
update_players = not (update_players ~= true)
|
|
||||||
|
|
||||||
if not core.registered_items[tgt] then
|
|
||||||
return false, S('Cannot use unknown item "@1" as replacement.', tgt)
|
|
||||||
end
|
|
||||||
|
|
||||||
if not core.registered_items[src] then
|
|
||||||
cleaner.log("info", "\"" .. src .. "\" not registered, not unregistering")
|
|
||||||
else
|
|
||||||
cleaner.log("warning", "overriding registered item \"" .. src .. "\"")
|
|
||||||
|
|
||||||
core.unregister_item(src)
|
|
||||||
if core.registered_items[src] then
|
|
||||||
cleaner.log("error", "could not unregister \"" .. src .. "\"")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
core.register_alias(src, tgt)
|
|
||||||
if core.registered_aliases[src] == tgt then
|
|
||||||
cleaner.log("info", "registered alias \"" .. src .. "\" for \"" .. tgt .. "\"")
|
|
||||||
else
|
|
||||||
cleaner.log("error", "could not register alias \"" .. src .. "\" for \"" .. tgt .. "\"")
|
|
||||||
end
|
|
||||||
|
|
||||||
local bags = core.get_modpath("bags") ~= nil
|
|
||||||
local armor = core.get_modpath("3d_armor") ~= nil
|
|
||||||
|
|
||||||
-- update player inventories
|
|
||||||
if update_players then
|
|
||||||
for _, player in ipairs(core.get_connected_players()) do
|
|
||||||
local pinv = player:get_inventory()
|
|
||||||
update_list(pinv, "main", src, tgt)
|
|
||||||
|
|
||||||
if bags then
|
|
||||||
for i = 1, 4 do
|
|
||||||
update_list(pinv, "bag" .. i .. "contents", src, tgt)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if armor then
|
|
||||||
local armor_inv = core.get_inventory({type="detached", name=player:get_player_name() .. "_armor"})
|
|
||||||
update_list(armor_inv, "armor", src, tgt)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Registeres an item to be replaced.
|
|
||||||
--
|
|
||||||
-- @tparam string src Technical name of item to be replaced.
|
|
||||||
-- @tparam string tgt Technical name of item to be used in place.
|
|
||||||
function cleaner.register_item_replacement(src, tgt)
|
|
||||||
replace_items[src] = tgt
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Registers a node to be replaced.
|
|
||||||
--
|
|
||||||
-- @tparam string src Technical name of node to be replaced.
|
|
||||||
-- @tparam string tgt Technical name of node to be used in place.
|
|
||||||
function cleaner.register_node_replacement(src, tgt)
|
|
||||||
core.register_node(":" .. src, {
|
|
||||||
groups = {to_replace=1},
|
|
||||||
})
|
|
||||||
|
|
||||||
replace_nodes[src] = tgt
|
|
||||||
cleaner.register_item_replacement(src, tgt)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Unsafe Methods.
|
|
||||||
--
|
|
||||||
-- Enabled with [cleaner.unsafe](settings.html#cleaner.unsafe) setting.
|
|
||||||
--
|
|
||||||
-- @section unsafe
|
|
||||||
|
|
||||||
|
|
||||||
if cleaner.unsafe then
|
|
||||||
local remove_ores = {}
|
|
||||||
|
|
||||||
--- Retrieves list of ores to be removed.
|
|
||||||
--
|
|
||||||
-- @treturn table Ores to be removed.
|
|
||||||
function cleaner.get_remove_ores()
|
|
||||||
return remove_ores
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Registers an ore to be removed after server startup.
|
|
||||||
--
|
|
||||||
-- @tparam string src Ore technical name.
|
|
||||||
function cleaner.register_ore_removal(src)
|
|
||||||
table.insert(remove_ores, src)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Removes an ore definition.
|
|
||||||
--
|
|
||||||
-- @tparam string src Ore technical name.
|
|
||||||
function cleaner.remove_ore(src)
|
|
||||||
local remove_ids = {}
|
|
||||||
local total_removed = 0
|
|
||||||
local registered = false
|
|
||||||
|
|
||||||
for id, def in pairs(core.registered_ores) do
|
|
||||||
if def.ore == src then
|
|
||||||
table.insert(remove_ids, id)
|
|
||||||
registered = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, id in ipairs(remove_ids) do
|
|
||||||
core.registered_ores[id] = nil
|
|
||||||
if core.registered_ores[id] then
|
|
||||||
cleaner.log("error", "unable to unregister ore " .. id)
|
|
||||||
else
|
|
||||||
total_removed = total_removed + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return registered, total_removed
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,63 +0,0 @@
|
||||||
|
|
||||||
2025-01-18
|
|
||||||
----------
|
|
||||||
- fix undeclared global
|
|
||||||
- added nil check after reading world data file
|
|
||||||
|
|
||||||
|
|
||||||
v1.2.1
|
|
||||||
----
|
|
||||||
- use sounds mod for sounds
|
|
||||||
- added nil check after reading world data file
|
|
||||||
|
|
||||||
|
|
||||||
v1.2
|
|
||||||
----
|
|
||||||
- added API
|
|
||||||
- added support for unregistering ores (unsafe)
|
|
||||||
- added setting for enabling "unsafe" methods & commands
|
|
||||||
- all types are loaded from <world_path>/cleaner.json file
|
|
||||||
- added localization support
|
|
||||||
- added Spanish localization
|
|
||||||
- added pencil tool for erasing, adding, & swapping nodes
|
|
||||||
- added chat commands:
|
|
||||||
- remove_entities
|
|
||||||
- remove_nodes
|
|
||||||
- replace_items
|
|
||||||
- replace_nodes
|
|
||||||
- find_unknown_nodes
|
|
||||||
- find_nearby_nodes
|
|
||||||
- remove_ores (unsafe)
|
|
||||||
- ctool (manages wielded cleaner tool settings)
|
|
||||||
|
|
||||||
v1.1
|
|
||||||
----
|
|
||||||
- uses "register_lbm" with "run_at_every_load" instead of "register_abm" to save resources
|
|
||||||
- suggested by bell07 ( https://forum.luanti.org/viewtopic.php?p=325519#p325519 )
|
|
||||||
|
|
||||||
v1.0
|
|
||||||
----
|
|
||||||
- changed license to MIT
|
|
||||||
- "clean_entities" & "clean_nodes" files now use json format
|
|
||||||
- nodes can be replaced with other nodes
|
|
||||||
- items can be replaced with other items (<world_path>/clean_items.json file)
|
|
||||||
|
|
||||||
v0.4
|
|
||||||
----
|
|
||||||
- changed technical name to "cleaner"
|
|
||||||
- re-added functionality to clean nodes
|
|
||||||
|
|
||||||
v0.3
|
|
||||||
----
|
|
||||||
- removed functionality for cleaning anything other than entities
|
|
||||||
|
|
||||||
v0.2
|
|
||||||
----
|
|
||||||
- changed license to CC0
|
|
||||||
- added some log output
|
|
||||||
- entities to be cleaned can be configured & loaded from world directory
|
|
||||||
|
|
||||||
v0.1
|
|
||||||
----
|
|
||||||
- forked from PilzAdam's "clean" mod @ forum post updated: 2013-06-08
|
|
||||||
- replaced deprecated call to "minetest.env"
|
|
660
chat.lua
660
chat.lua
|
@ -1,660 +0,0 @@
|
||||||
|
|
||||||
--- Cleaner Chat Commands
|
|
||||||
--
|
|
||||||
-- @topic commands
|
|
||||||
|
|
||||||
|
|
||||||
local S = core.get_translator(cleaner.modname)
|
|
||||||
|
|
||||||
|
|
||||||
local aux = dofile(cleaner.modpath .. "/misc_functions.lua")
|
|
||||||
|
|
||||||
local function pos_list(ppos, radius)
|
|
||||||
local plist = {}
|
|
||||||
|
|
||||||
for x = ppos.x - radius, ppos.x + radius, 1 do
|
|
||||||
for y = ppos.y - radius, ppos.y + radius, 1 do
|
|
||||||
for z = ppos.z - radius, ppos.z + radius, 1 do
|
|
||||||
table.insert(plist, {x=x, y=y, z=z})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return plist
|
|
||||||
end
|
|
||||||
|
|
||||||
local param_def = {
|
|
||||||
radius = {name=S("radius"), desc=S("Search radius.")},
|
|
||||||
entity = {name=S("entity"), desc=S("Entity technical name.")},
|
|
||||||
node = {name=S("node"), desc=S("Node technical name.")},
|
|
||||||
old_node = {name=S("old_node"), desc=S("Technical name of node to be replaced.")},
|
|
||||||
new_node = {name=S("new_node"), desc=S("Technical name of node to be used in place.")},
|
|
||||||
old_item = {name=S("old_item"), desc=S("Technical name of item to be replaced.")},
|
|
||||||
new_item = {name=S("new_item"), desc=S("Technical name of item to be used in place.")},
|
|
||||||
ore = {name=S("ore"), desc=S("Ore technical name.")},
|
|
||||||
action = {name=S("action"),
|
|
||||||
desc=S('Action to execute. Can be one of "@1", "@2", or "@3".', "status", "setmode", "setnode")},
|
|
||||||
value = {name=S("value"), desc=S('Mode or node to be set for tool (not required for "@1" action).', "status")},
|
|
||||||
}
|
|
||||||
|
|
||||||
local cmd_repo = {
|
|
||||||
entity = {
|
|
||||||
cmd = "remove_entities",
|
|
||||||
params = {"entity"},
|
|
||||||
oparams = {radius=100},
|
|
||||||
},
|
|
||||||
rem_node = {
|
|
||||||
cmd = "remove_nodes",
|
|
||||||
params = {"node"},
|
|
||||||
oparams = {radius=5},
|
|
||||||
},
|
|
||||||
rep_node = {
|
|
||||||
cmd = "replace_nodes",
|
|
||||||
params = {"old_node", "new_node"},
|
|
||||||
oparams = {radius=5},
|
|
||||||
},
|
|
||||||
find_node = {
|
|
||||||
cmd = "find_unknown_nodes",
|
|
||||||
oparams = {radius=100},
|
|
||||||
},
|
|
||||||
near_node = {
|
|
||||||
cmd = "find_nearby_nodes",
|
|
||||||
oparams = {radius=5},
|
|
||||||
},
|
|
||||||
item = {
|
|
||||||
cmd = "replace_items",
|
|
||||||
params = {"old_item", "new_item"},
|
|
||||||
},
|
|
||||||
ore = {
|
|
||||||
cmd = "remove_ores",
|
|
||||||
params = {"ore"},
|
|
||||||
},
|
|
||||||
tool = {
|
|
||||||
cmd = "ctool",
|
|
||||||
params = {"action", "value"},
|
|
||||||
},
|
|
||||||
param = {
|
|
||||||
missing = S("Missing parameter."),
|
|
||||||
excess = S("Too many parameters."),
|
|
||||||
mal_radius = S("Radius must be a number."),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, def in pairs(cmd_repo) do
|
|
||||||
if k ~= "param" then
|
|
||||||
local cmd_help = {
|
|
||||||
param_string = "",
|
|
||||||
usage_string = "/" .. def.cmd,
|
|
||||||
}
|
|
||||||
|
|
||||||
if def.params or def.oparams then
|
|
||||||
if def.params then
|
|
||||||
local params = {}
|
|
||||||
for _, p in ipairs(def.params) do
|
|
||||||
-- translate
|
|
||||||
table.insert(params, S(p))
|
|
||||||
end
|
|
||||||
|
|
||||||
cmd_help.param_string = "<" .. table.concat(params, "> <") .. ">"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if def.oparams then
|
|
||||||
for k, v in pairs(def.oparams) do
|
|
||||||
local op = k
|
|
||||||
if type(op) == "number" then
|
|
||||||
op = v
|
|
||||||
end
|
|
||||||
|
|
||||||
cmd_help.param_string = cmd_help.param_string .. " [" .. S(op) .. "]"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if cmd_help.param_string ~= "" then
|
|
||||||
cmd_help.usage_string = cmd_help.usage_string .. " " .. cmd_help.param_string
|
|
||||||
end
|
|
||||||
|
|
||||||
cmd_repo[k].help = cmd_help
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_cmd_def(cmd)
|
|
||||||
for k, v in pairs(cmd_repo) do
|
|
||||||
if v.cmd == cmd then return v end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function format_usage(cmd)
|
|
||||||
local def = get_cmd_def(cmd)
|
|
||||||
if def then
|
|
||||||
return S("Usage:") .. "\n " .. def.help.usage_string
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function format_params(cmd)
|
|
||||||
local def = get_cmd_def(cmd)
|
|
||||||
|
|
||||||
local param_count
|
|
||||||
-- FIXME: unused?
|
|
||||||
local all_params = {}
|
|
||||||
if def.params then
|
|
||||||
for _, p in ipairs(def.params) do
|
|
||||||
table.insert(all_params, p)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if def.oparams then
|
|
||||||
for k, v in pairs(def.oparams) do
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local retval = ""
|
|
||||||
local p_count = 0
|
|
||||||
|
|
||||||
if def.params then
|
|
||||||
for _, p in ipairs(def.params) do
|
|
||||||
if p_count == 0 then
|
|
||||||
retval = retval .. S("Params:")
|
|
||||||
end
|
|
||||||
|
|
||||||
retval = retval .. "\n " .. S(p) .. ": " .. param_def[p].desc
|
|
||||||
|
|
||||||
p_count = p_count + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if def.oparams then
|
|
||||||
for k, v in pairs(def.oparams) do
|
|
||||||
if p_count == 0 then
|
|
||||||
retval = retval .. S("Params:")
|
|
||||||
end
|
|
||||||
|
|
||||||
local p = k
|
|
||||||
local dvalue = v
|
|
||||||
if type(p) == "number" then
|
|
||||||
p = v
|
|
||||||
dvalue = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
retval = retval .. "\n " .. S(p) .. ": " .. param_def[p].desc
|
|
||||||
if dvalue then
|
|
||||||
retval = retval .. " (" .. S("default: @1", dvalue) .. ")"
|
|
||||||
end
|
|
||||||
|
|
||||||
p_count = p_count + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return retval
|
|
||||||
end
|
|
||||||
|
|
||||||
local function format_help(cmd)
|
|
||||||
return format_usage(cmd) .. "\n\n" .. format_params(cmd)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local function check_radius(radius, pname)
|
|
||||||
local is_admin = core.check_player_privs(pname, {server=true})
|
|
||||||
|
|
||||||
if not is_admin and radius > 10 then
|
|
||||||
radius = 10
|
|
||||||
return radius, S("You do not have permission to set radius that high. Reduced to @1.", radius)
|
|
||||||
end
|
|
||||||
|
|
||||||
if radius > 100 then
|
|
||||||
radius = 100
|
|
||||||
return radius, S("Radius is too high. Reduced to @1.", radius)
|
|
||||||
end
|
|
||||||
|
|
||||||
return radius
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Removes nearby entities.
|
|
||||||
--
|
|
||||||
-- @chatcmd remove_entities
|
|
||||||
-- @param entity Entity technical name.
|
|
||||||
-- @tparam[opt] int radius Search radius (default: 100).
|
|
||||||
-- @priv server
|
|
||||||
-- @usage
|
|
||||||
-- # remove all mobs:horse entities within a radius of 10 nodes
|
|
||||||
-- /remove_entities mobs:horse 10
|
|
||||||
core.register_chatcommand(cmd_repo.entity.cmd, {
|
|
||||||
privs = {server=true},
|
|
||||||
description = S("Remove an entity from game.") .. "\n\n"
|
|
||||||
.. format_params(cmd_repo.entity.cmd),
|
|
||||||
params = cmd_repo.entity.help.param_string,
|
|
||||||
func = function(name, param)
|
|
||||||
local entity
|
|
||||||
local radius = cmd_repo.entity.oparams.radius
|
|
||||||
if param:find(" ") then
|
|
||||||
entity = param:split(" ")
|
|
||||||
radius = tonumber(entity[2])
|
|
||||||
entity = entity[1]
|
|
||||||
else
|
|
||||||
entity = param
|
|
||||||
end
|
|
||||||
|
|
||||||
local err
|
|
||||||
if not entity or entity:trim() == "" then
|
|
||||||
err = cmd_repo.param.missing
|
|
||||||
elseif not radius then
|
|
||||||
err = cmd_repo.param.mal_radius
|
|
||||||
end
|
|
||||||
|
|
||||||
local radius, msg = check_radius(radius, name)
|
|
||||||
if msg then
|
|
||||||
core.chat_send_player(name, msg)
|
|
||||||
end
|
|
||||||
|
|
||||||
if err then
|
|
||||||
return false, err .. "\n\n" .. format_help(cmd_repo.entity.cmd)
|
|
||||||
end
|
|
||||||
|
|
||||||
local player = core.get_player_by_name(name)
|
|
||||||
|
|
||||||
local total_removed = 0
|
|
||||||
for _, object in ipairs(core.get_objects_inside_radius(player:get_pos(), radius)) do
|
|
||||||
local lent = object:get_luaentity()
|
|
||||||
|
|
||||||
if lent then
|
|
||||||
if lent.name == entity then
|
|
||||||
object:remove()
|
|
||||||
total_removed = total_removed + 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if object:get_properties().infotext == entity then
|
|
||||||
object:remove()
|
|
||||||
total_removed = total_removed + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return true, S("Removed @1 entities.", total_removed)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
--- Removes nearby nodes.
|
|
||||||
--
|
|
||||||
-- @chatcmd remove_nodes
|
|
||||||
-- @param node Node technical name.
|
|
||||||
-- @tparam[opt] int radius Search radius (default: 5).
|
|
||||||
-- @priv server
|
|
||||||
-- @usage
|
|
||||||
-- # remove all default:dirt nodes within a radius of 10
|
|
||||||
-- /remove_nodes default:dirt 10
|
|
||||||
core.register_chatcommand(cmd_repo.rem_node.cmd, {
|
|
||||||
privs = {server=true},
|
|
||||||
description = S("Remove a node from game.") .. "\n\n"
|
|
||||||
.. format_params(cmd_repo.rem_node.cmd),
|
|
||||||
params = cmd_repo.rem_node.help.param_string,
|
|
||||||
func = function(name, param)
|
|
||||||
local nname
|
|
||||||
local radius = cmd_repo.rem_node.oparams.radius
|
|
||||||
if param:find(" ") then
|
|
||||||
nname = param:split(" ")
|
|
||||||
radius = tonumber(nname[2])
|
|
||||||
nname = nname[1]
|
|
||||||
else
|
|
||||||
nname = param
|
|
||||||
end
|
|
||||||
|
|
||||||
local err
|
|
||||||
if not nname or nname:trim() == "" then
|
|
||||||
err = cmd_repo.param.missing
|
|
||||||
elseif not radius then
|
|
||||||
err = cmd_repo.param.mal_radius
|
|
||||||
end
|
|
||||||
|
|
||||||
local radius, msg = check_radius(radius, name)
|
|
||||||
if msg then
|
|
||||||
core.chat_send_player(name, msg)
|
|
||||||
end
|
|
||||||
|
|
||||||
if err then
|
|
||||||
return false, err .. "\n\n" .. format_help(cmd_repo.rem_node.cmd)
|
|
||||||
end
|
|
||||||
|
|
||||||
local ppos = core.get_player_by_name(name):get_pos()
|
|
||||||
|
|
||||||
local total_removed = 0
|
|
||||||
for _, npos in ipairs(pos_list(ppos, radius)) do
|
|
||||||
local node = core.get_node_or_nil(npos)
|
|
||||||
if node and node.name == nname then
|
|
||||||
core.remove_node(npos)
|
|
||||||
total_removed = total_removed + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return true, S("Removed @1 nodes.", total_removed)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
--- Replaces an item.
|
|
||||||
--
|
|
||||||
-- @chatcmd replace_items
|
|
||||||
-- @param old_item Technical name of item to replace.
|
|
||||||
-- @param new_item Technical name of item to be used in place.
|
|
||||||
-- @priv server
|
|
||||||
-- @usage
|
|
||||||
-- # replace default:sword_wood with default:sword_mese
|
|
||||||
-- /replace_items default:sword_wood default:sword_mese
|
|
||||||
core.register_chatcommand(cmd_repo.item.cmd, {
|
|
||||||
privs = {server=true},
|
|
||||||
description = S("Replace an item in game.") .. "\n\n"
|
|
||||||
.. format_params(cmd_repo.item.cmd),
|
|
||||||
params = cmd_repo.item.help.param_string,
|
|
||||||
func = function(name, param)
|
|
||||||
if not param:find(" ") then
|
|
||||||
return false, cmd_repo.param.missing .. "\n\n" .. format_help(cmd_repo.item.cmd)
|
|
||||||
end
|
|
||||||
|
|
||||||
local src = param:split(" ")
|
|
||||||
local tgt = src[2]
|
|
||||||
src = src[1]
|
|
||||||
|
|
||||||
local retval, msg = cleaner.replace_item(src, tgt, true)
|
|
||||||
if not retval then
|
|
||||||
return false, msg
|
|
||||||
end
|
|
||||||
|
|
||||||
return true, S("Success!")
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
--- Replaces nearby nodes.
|
|
||||||
--
|
|
||||||
-- @chatcmd replace_nodes
|
|
||||||
-- @param old_node Technical name of node to replace.
|
|
||||||
-- @param new_node Technical name of node to be used in place.
|
|
||||||
-- @tparam[opt] int radius Search radius (default: 5).
|
|
||||||
-- @priv server
|
|
||||||
-- @usage
|
|
||||||
-- # replace all default:dirt nodes with default:cobble within a radius of 10
|
|
||||||
-- /replace_nodes default:dirt default:cobble 10
|
|
||||||
core.register_chatcommand(cmd_repo.rep_node.cmd, {
|
|
||||||
privs = {server=true},
|
|
||||||
description = S("Replace a node in game.") .. "\n\n"
|
|
||||||
.. format_params(cmd_repo.rep_node.cmd),
|
|
||||||
params = cmd_repo.rep_node.help.param_string,
|
|
||||||
func = function(name, param)
|
|
||||||
local help = format_help(cmd_repo.rep_node.cmd)
|
|
||||||
|
|
||||||
if not param:find(" ") then
|
|
||||||
return false, cmd_repo.param.missing .. "\n\n" .. help
|
|
||||||
end
|
|
||||||
|
|
||||||
local radius = cmd_repo.rep_node.oparams.radius
|
|
||||||
local params = param:split(" ")
|
|
||||||
|
|
||||||
local src = params[1]
|
|
||||||
local tgt = tostring(params[2])
|
|
||||||
if #params > 2 then
|
|
||||||
radius = tonumber(params[3])
|
|
||||||
end
|
|
||||||
|
|
||||||
if not radius then
|
|
||||||
return false, cmd_repo.param.mal_radius .. "\n\n" .. help
|
|
||||||
end
|
|
||||||
|
|
||||||
local radius, msg = check_radius(radius, name)
|
|
||||||
if msg then
|
|
||||||
core.chat_send_player(name, msg)
|
|
||||||
end
|
|
||||||
|
|
||||||
if not core.registered_nodes[tgt] then
|
|
||||||
return false, S('Cannot use unknown node "@1" as replacement.', tgt)
|
|
||||||
end
|
|
||||||
|
|
||||||
local total_replaced = 0
|
|
||||||
local ppos = core.get_player_by_name(name):get_pos()
|
|
||||||
for _, npos in ipairs(pos_list(ppos, radius)) do
|
|
||||||
local node = core.get_node_or_nil(npos)
|
|
||||||
if node and node.name == src then
|
|
||||||
if core.swap_node(npos, {name=tgt}) then
|
|
||||||
total_replaced = total_replaced + 1
|
|
||||||
else
|
|
||||||
cleaner.log("error", "could not replace node at " .. core.pos_to_string(npos, 0))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return true, S("Replaced @1 nodes.", total_replaced)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
--- Checks for nearby unknown nodes.
|
|
||||||
--
|
|
||||||
-- @chatcmd find_unknown_nodes
|
|
||||||
-- @tparam[opt] int radius Search radius (default: 100).
|
|
||||||
-- @priv server
|
|
||||||
-- @usage
|
|
||||||
-- # print names of all unknown nodes within radius of 10
|
|
||||||
-- /find_unknown_nodes 10
|
|
||||||
core.register_chatcommand(cmd_repo.find_node.cmd, {
|
|
||||||
privs = {server=true},
|
|
||||||
description = S("Find names of unknown nodes.") .. "\n\n"
|
|
||||||
.. format_params(cmd_repo.find_node.cmd),
|
|
||||||
params = cmd_repo.find_node.help.param_string,
|
|
||||||
func = function(name, param)
|
|
||||||
local help = format_help(cmd_repo.find_node.cmd)
|
|
||||||
|
|
||||||
if param:find(" ") then
|
|
||||||
return false, cmd_repo.param.excess .. "\n\n" .. help
|
|
||||||
end
|
|
||||||
|
|
||||||
local radius = cmd_repo.find_node.oparams.radius
|
|
||||||
if param and param:trim() ~= "" then
|
|
||||||
radius = tonumber(param)
|
|
||||||
end
|
|
||||||
|
|
||||||
if not radius then
|
|
||||||
return false, cmd_repo.param.mal_radius .. "\n\n" .. help
|
|
||||||
end
|
|
||||||
|
|
||||||
local radius, msg = check_radius(radius, name)
|
|
||||||
if msg then
|
|
||||||
core.chat_send_player(name, msg)
|
|
||||||
end
|
|
||||||
|
|
||||||
local ppos = core.get_player_by_name(name):get_pos()
|
|
||||||
|
|
||||||
local checked_nodes = {}
|
|
||||||
local unknown_nodes = {}
|
|
||||||
for _, npos in ipairs(pos_list(ppos, radius)) do
|
|
||||||
local node = core.get_node_or_nil(npos)
|
|
||||||
if node and not checked_nodes[node.name] then
|
|
||||||
if not core.registered_nodes[node.name] then
|
|
||||||
table.insert(unknown_nodes, node.name)
|
|
||||||
end
|
|
||||||
|
|
||||||
checked_nodes[node.name] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local node_count = #unknown_nodes
|
|
||||||
if node_count > 0 then
|
|
||||||
msg = S("Found unknown nodes: @1", node_count) .. "\n " .. table.concat(unknown_nodes, ", ")
|
|
||||||
else
|
|
||||||
msg = S("No unknown nodes found.")
|
|
||||||
end
|
|
||||||
|
|
||||||
return true, msg
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
--- Finds names of nearby nodes.
|
|
||||||
--
|
|
||||||
-- @chatcmd find_nearby_nodes
|
|
||||||
-- @tparam[opt] int radius Search radius (default: 5).
|
|
||||||
-- @priv server
|
|
||||||
-- @usage
|
|
||||||
-- # print names of all node types found within radius of 10
|
|
||||||
-- /find_nearby_nodes 10
|
|
||||||
core.register_chatcommand(cmd_repo.near_node.cmd, {
|
|
||||||
privs = {server=true},
|
|
||||||
description = S("Find names of nearby nodes.") .. "\n\n"
|
|
||||||
.. format_params(cmd_repo.near_node.cmd),
|
|
||||||
params = cmd_repo.near_node.help.param_string,
|
|
||||||
func = function(name, param)
|
|
||||||
local help = format_help(cmd_repo.near_node.cmd)
|
|
||||||
|
|
||||||
if param:find(" ") then
|
|
||||||
return false, cmd_repo.param.excess .. "\n\n" .. help
|
|
||||||
end
|
|
||||||
|
|
||||||
local radius = cmd_repo.near_node.oparams.radius
|
|
||||||
if param and param:trim() ~= "" then
|
|
||||||
radius = tonumber(param)
|
|
||||||
end
|
|
||||||
|
|
||||||
if not radius then
|
|
||||||
return false, cmd_repo.param.mal_radius .. "\n\n" .. help
|
|
||||||
end
|
|
||||||
|
|
||||||
local radius, msg = check_radius(radius, name)
|
|
||||||
if msg then
|
|
||||||
core.chat_send_player(name, msg)
|
|
||||||
end
|
|
||||||
|
|
||||||
local ppos = core.get_player_by_name(name):get_pos()
|
|
||||||
|
|
||||||
local node_names = {}
|
|
||||||
for _, npos in ipairs(pos_list(ppos, radius)) do
|
|
||||||
local node = core.get_node_or_nil(npos)
|
|
||||||
if node and not node_names[node.name] then
|
|
||||||
node_names[node.name] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local found_nodes = {}
|
|
||||||
for k, _ in pairs(node_names) do
|
|
||||||
table.insert(found_nodes, k)
|
|
||||||
end
|
|
||||||
|
|
||||||
local msg
|
|
||||||
local node_count = #found_nodes
|
|
||||||
if node_count > 0 then
|
|
||||||
msg = S("Nearby nodes: @1", node_count) .. "\n " .. table.concat(found_nodes, ", ")
|
|
||||||
else
|
|
||||||
msg = S("No nearby nodes found.")
|
|
||||||
end
|
|
||||||
|
|
||||||
return true, msg
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
--- Unsafe Commands.
|
|
||||||
--
|
|
||||||
-- Enabled with [cleaner.unsafe](settings.html#cleaner.unsafe) setting.
|
|
||||||
--
|
|
||||||
-- @section unsafe
|
|
||||||
|
|
||||||
|
|
||||||
if cleaner.unsafe then
|
|
||||||
--- Registers an ore to be removed.
|
|
||||||
--
|
|
||||||
-- @chatcmd remove_ores
|
|
||||||
-- @param ore Ore technical name.
|
|
||||||
-- @priv server
|
|
||||||
-- @note This action is reverted after server restart. To make changes permanent,
|
|
||||||
-- use the [cleaner.json](config.html#cleaner.json) config.
|
|
||||||
-- @usage
|
|
||||||
-- # remove all registered ores that add default:stone_with_iron to world
|
|
||||||
-- /remove_ores default:stone_with_iron
|
|
||||||
core.register_chatcommand(cmd_repo.ore.cmd, {
|
|
||||||
privs = {server=true},
|
|
||||||
description = S("Remove an ore from game.") .. "\n\n"
|
|
||||||
.. format_params(cmd_repo.ore.cmd),
|
|
||||||
params = cmd_repo.ore.help.param_string,
|
|
||||||
func = function(name, param)
|
|
||||||
local err
|
|
||||||
if not param or param:trim() == "" then
|
|
||||||
err = cmd_repo.param.missing
|
|
||||||
elseif param:find(" ") then
|
|
||||||
err = cmd_repo.param.excess
|
|
||||||
end
|
|
||||||
|
|
||||||
if err then
|
|
||||||
return false, err .. "\n\n" .. format_help(cmd_repo.ore.cmd)
|
|
||||||
end
|
|
||||||
|
|
||||||
local success = false
|
|
||||||
local msg
|
|
||||||
local registered, total_removed = cleaner.remove_ore(param)
|
|
||||||
|
|
||||||
if not registered then
|
|
||||||
msg = S('Ore "@1" not found, not unregistering.', param)
|
|
||||||
else
|
|
||||||
msg = S("Unregistered @1 ores (this will be undone after server restart).", total_removed)
|
|
||||||
success = true
|
|
||||||
end
|
|
||||||
|
|
||||||
return success, msg
|
|
||||||
end
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
--- @section end
|
|
||||||
|
|
||||||
|
|
||||||
--- Manages settings for wielded [cleaner tool](tools.html).
|
|
||||||
--
|
|
||||||
-- <h3>Required Privileges:</h3>
|
|
||||||
--
|
|
||||||
-- - server
|
|
||||||
--
|
|
||||||
-- @chatcmd ctool
|
|
||||||
-- @param action Action to execute. Can be "status", "setmode", or "setnode".
|
|
||||||
-- @param value Mode or node to be set for tool (not required for "status" action).
|
|
||||||
-- @usage
|
|
||||||
-- # while cleaner:pencil is wielded, configure to place default:dirt node when used
|
|
||||||
-- /ctool setmode write
|
|
||||||
-- /ctool setnode default:dirt
|
|
||||||
core.register_chatcommand(cmd_repo.tool.cmd, {
|
|
||||||
privs = {server=true},
|
|
||||||
description = S("Manage settings for wielded cleaner tool.") .. "\n\n"
|
|
||||||
.. format_params(cmd_repo.tool.cmd),
|
|
||||||
params = cmd_repo.tool.help.param_string,
|
|
||||||
func = function(name, param)
|
|
||||||
local action, value = param
|
|
||||||
local idx = param:find(" ")
|
|
||||||
if idx then
|
|
||||||
param = string.split(param, " ")
|
|
||||||
action = param[1]
|
|
||||||
value = param[2]
|
|
||||||
end
|
|
||||||
|
|
||||||
local help = format_help(cmd_repo.tool.cmd)
|
|
||||||
|
|
||||||
local player = core.get_player_by_name(name)
|
|
||||||
local stack = player:get_wielded_item()
|
|
||||||
local iname = aux.tool:format_name(stack)
|
|
||||||
local imeta = stack:get_meta()
|
|
||||||
|
|
||||||
if iname ~= "cleaner:pencil" then
|
|
||||||
return false, S("Unrecognized wielded item: @1", iname) .. "\n\n" .. help
|
|
||||||
end
|
|
||||||
|
|
||||||
if action == "status" then
|
|
||||||
core.chat_send_player(name, iname .. ": " .. S("mode") .. "=" .. imeta:get_string("mode")
|
|
||||||
.. ", " .. S("node") .. "=" .. imeta:get_string("node"))
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
if not action or not value then
|
|
||||||
return false, S("Missing parameter.") .. "\n\n" .. help
|
|
||||||
end
|
|
||||||
|
|
||||||
if action == "setmode" then
|
|
||||||
stack = aux.tool:set_mode(stack, value, name)
|
|
||||||
elseif action == "setnode" then
|
|
||||||
stack = aux.tool:set_node(stack, value, name)
|
|
||||||
else
|
|
||||||
return false, S("Unrecognized action: @1", action) .. "\n\n" .. help
|
|
||||||
end
|
|
||||||
|
|
||||||
return player:set_wielded_item(stack)
|
|
||||||
end,
|
|
||||||
})
|
|
1
description.txt
Normal file
1
description.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
A very simple mod that deletes unknown blocks and removes unknown entities.
|
59
entities.lua
59
entities.lua
|
@ -1,59 +0,0 @@
|
||||||
|
|
||||||
local aux = dofile(cleaner.modpath .. "/misc_functions.lua")
|
|
||||||
|
|
||||||
-- populate entities list from file in world path
|
|
||||||
local entities_data = aux.get_world_data().entities
|
|
||||||
|
|
||||||
|
|
||||||
-- START: backward compat
|
|
||||||
|
|
||||||
local e_path = core.get_worldpath() .. "/clean_entities.json"
|
|
||||||
local e_file = io.open(e_path, "r")
|
|
||||||
|
|
||||||
if e_file then
|
|
||||||
cleaner.log("action", "found deprecated clean_entities.json, updating")
|
|
||||||
|
|
||||||
local data_in = core.parse_json(e_file:read("*a"))
|
|
||||||
e_file:close()
|
|
||||||
if data_in and data_in.remove then
|
|
||||||
for _, r in ipairs(data_in.remove) do
|
|
||||||
table.insert(entities_data.remove, r)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- don't read deprecated file again
|
|
||||||
os.rename(e_path, e_path .. ".old")
|
|
||||||
end
|
|
||||||
|
|
||||||
local e_path_old = core.get_worldpath() .. "/clean_entities.txt"
|
|
||||||
e_file = io.open(e_path_old, "r")
|
|
||||||
|
|
||||||
if e_file then
|
|
||||||
cleaner.log("action", "found deprecated clean_entities.txt, converting to json")
|
|
||||||
|
|
||||||
local data_in = string.split(e_file:read("*a"), "\n")
|
|
||||||
for _, e in ipairs(data_in) do
|
|
||||||
e = e:trim()
|
|
||||||
if e ~= "" and e:sub(1, 1) ~= "#" then
|
|
||||||
table.insert(entities_data.remove, e)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
e_file:close()
|
|
||||||
os.rename(e_path_old, e_path_old .. ".bak") -- don't read deprecated file again
|
|
||||||
end
|
|
||||||
|
|
||||||
-- END: backward compat
|
|
||||||
|
|
||||||
|
|
||||||
entities_data.remove = aux.clean_duplicates(entities_data.remove)
|
|
||||||
|
|
||||||
-- update json file with any changes
|
|
||||||
aux.update_world_data("entities", entities_data)
|
|
||||||
|
|
||||||
core.register_on_mods_loaded(function()
|
|
||||||
for _, e in ipairs(entities_data.remove) do
|
|
||||||
cleaner.log("action", "registering entity for removal: " .. e)
|
|
||||||
cleaner.register_entity_removal(e)
|
|
||||||
end
|
|
||||||
end)
|
|
75
init.lua
75
init.lua
|
@ -1,48 +1,43 @@
|
||||||
|
-- clean by PilzAdam
|
||||||
|
-- LICENSE: WTFPL
|
||||||
|
|
||||||
cleaner = {}
|
local old_nodes = {}
|
||||||
cleaner.modname = core.get_current_modname()
|
local old_entities = {}
|
||||||
cleaner.modpath = core.get_modpath(cleaner.modname)
|
|
||||||
|
|
||||||
local cleaner_debug = core.settings:get_bool("enable_debug_mods", false)
|
-- Old/Missing nodes that should be replaced with something currently in game
|
||||||
|
local replace_nodes = {}
|
||||||
|
|
||||||
function cleaner.log(lvl, msg)
|
|
||||||
if lvl == "debug" and not cleaner_debug then return end
|
|
||||||
|
|
||||||
if lvl and not msg then
|
-- "Replaces" an old/non-existent node
|
||||||
msg = lvl
|
local function replace_node(old_node, new_node)
|
||||||
lvl = nil
|
minetest.register_alias(old_node, new_node)
|
||||||
end
|
|
||||||
|
|
||||||
msg = "[" .. cleaner.modname .. "] " .. msg
|
|
||||||
if lvl == "debug" then
|
|
||||||
msg = "[DEBUG] " .. msg
|
|
||||||
lvl = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if not lvl then
|
|
||||||
core.log(msg)
|
|
||||||
else
|
|
||||||
core.log(lvl, msg)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local aux = dofile(cleaner.modpath .. "/misc_functions.lua")
|
|
||||||
|
|
||||||
-- initialize world file
|
for _,node_name in ipairs(old_nodes) do
|
||||||
aux.update_world_data()
|
minetest.register_node(':'..node_name, {
|
||||||
|
groups = {old=1},
|
||||||
|
})
|
||||||
local scripts = {
|
end
|
||||||
"settings",
|
|
||||||
"api",
|
minetest.register_abm({
|
||||||
"chat",
|
nodenames = {'group:old'},
|
||||||
"tools",
|
interval = 1,
|
||||||
"entities",
|
chance = 1,
|
||||||
"nodes",
|
action = function(pos, node)
|
||||||
"items",
|
minetest.remove_node(pos)
|
||||||
"ores",
|
end,
|
||||||
}
|
})
|
||||||
|
|
||||||
for _, script in ipairs(scripts) do
|
for _,entity_name in ipairs(old_entities) do
|
||||||
dofile(cleaner.modpath .. "/" .. script .. ".lua")
|
minetest.register_entity(':'..entity_name, {
|
||||||
|
on_activate = function(self, staticdata)
|
||||||
|
self.object:remove()
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Replace old nodes
|
||||||
|
for _, node_group in pairs(replace_nodes) do
|
||||||
|
replace_node(node_group[1], node_group[2])
|
||||||
end
|
end
|
||||||
|
|
49
items.lua
49
items.lua
|
@ -1,49 +0,0 @@
|
||||||
|
|
||||||
local aux = dofile(cleaner.modpath .. "/misc_functions.lua")
|
|
||||||
|
|
||||||
-- populate items list from file in world path
|
|
||||||
local items_data = aux.get_world_data().items
|
|
||||||
|
|
||||||
|
|
||||||
-- START: backward compat
|
|
||||||
|
|
||||||
local i_path = core.get_worldpath() .. "/clean_items.json"
|
|
||||||
local i_file = io.open(i_path, "r")
|
|
||||||
|
|
||||||
if i_file then
|
|
||||||
cleaner.log("action", "found deprecated clean_items.json, updating")
|
|
||||||
|
|
||||||
local data_in = core.parse_json(i_file:read("*a"))
|
|
||||||
i_file:close()
|
|
||||||
if data_in and data_in.replace then
|
|
||||||
for k, v in pairs(data_in.replace) do
|
|
||||||
if not items_data.replace[k] then
|
|
||||||
items_data.replace[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- don't read deprecated file again
|
|
||||||
os.rename(i_path, i_path .. ".old")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- END: backward compat
|
|
||||||
|
|
||||||
|
|
||||||
aux.update_world_data("items", items_data)
|
|
||||||
|
|
||||||
for i_old, i_new in pairs(items_data.replace) do
|
|
||||||
cleaner.register_item_replacement(i_old, i_new)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- register actions for after server startup
|
|
||||||
core.register_on_mods_loaded(function()
|
|
||||||
for i_old, i_new in pairs(cleaner.get_replace_items()) do
|
|
||||||
cleaner.log("action", "registering item \"" .. i_old .. "\" to be replaced with \"" .. i_new .. "\"")
|
|
||||||
|
|
||||||
local retval, msg = cleaner.replace_item(i_old, i_new)
|
|
||||||
if not retval then
|
|
||||||
cleaner.log("warning", msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
|
@ -1,66 +0,0 @@
|
||||||
# textdomain:cleaner
|
|
||||||
|
|
||||||
# Translators: Jordan Irwin (AntumDeluge)
|
|
||||||
|
|
||||||
|
|
||||||
# chat commands
|
|
||||||
entity=entidad
|
|
||||||
mode=modo
|
|
||||||
node=nodo
|
|
||||||
radius=radio
|
|
||||||
old_item=objeto_antiguo
|
|
||||||
new_item=objeto_nuevo
|
|
||||||
old_node=nodo_antiguo
|
|
||||||
new_node=nodo_nuevo
|
|
||||||
ore=mineral
|
|
||||||
action=acción
|
|
||||||
value=valor
|
|
||||||
Usage:=Uso:
|
|
||||||
Params:=Parámetros:
|
|
||||||
default: @1=por defecto: @1
|
|
||||||
Search radius.=Radio de búsqueda.
|
|
||||||
Entity technical name.=Nombre técnico de entidad.
|
|
||||||
Node technical name.=Nombre técnico de nodo.
|
|
||||||
Technical name of node to be replaced.=Nombre técnico del nodo reemplazado.
|
|
||||||
Technical name of node to be used in place.=Nombre técnico del nodo de reemplazo.
|
|
||||||
Technical name of item to be replaced.=Nombre técnico del objeto reemplazado.
|
|
||||||
Technical name of item to be used in place.=Nombre técnico del objeto de reemplazo.
|
|
||||||
Ore technical name.=Nombre técnico de mineral.
|
|
||||||
Action to execute. Can be one of "@1", "@2", or "@3".=La acción para ejecutar. Puede ser "@1", "@2", o "@3".
|
|
||||||
Mode or node to be set for tool (not required for "@1" action).=Modo o nodo para configurar a la herramienta (no se requiere para la acción de "@1").
|
|
||||||
Remove an entity from game.=Eliminar una entidad del juego.
|
|
||||||
Remove a node from game.=Eliminar un nodo del juego.
|
|
||||||
Replace an item in game.=Sustituir un objecto del juego.
|
|
||||||
Replace a node in game.=Sustituir un nodo del juego.
|
|
||||||
Find names of unknown nodes.=Descubrir los nombres de nodos desconocidos.
|
|
||||||
Find names of nearby nodes.=Descubrir los nombres de nodos cercanos.
|
|
||||||
Remove an ore from game.=Eliminar un mineral del juego.
|
|
||||||
Missing parameter.=Parámetro extraviado.
|
|
||||||
Too many parameters.=Demasiados parámetros.
|
|
||||||
Radius must be a number.=El radio debe ser un número.
|
|
||||||
Cannot use unknown item "@1" as replacement.=El objeto "@1" es desonocido, no se puede utilizar como sustitución.
|
|
||||||
Cannot use unknown node "@1" as replacement.=El nodo "@1" es desonocido, no se puede utilizar como sustitución.
|
|
||||||
Replaced @1 nodes.=Nodos sustituidos: @1
|
|
||||||
Removed @1 nodes.=Se eliminaron @1 nodos.
|
|
||||||
Removed @1 entities.=Se eliminaron @1 entidades.
|
|
||||||
Found unknown nodes: @1=Se encontraron @1 nodos desconocidos.
|
|
||||||
No unknown nodes found.=No se encontraron nodos desconocidos.
|
|
||||||
Nearby nodes: @1=Nodos cercanos: @1
|
|
||||||
No nearby nodes found.=No se encontraron nodos cercanos.
|
|
||||||
Ore "@1" not found, not unregistering.=No se encontró el mineral "@1", se mantiene registrado.
|
|
||||||
Unregistered @1 ores (this will be undone after server restart).=Se anuló @1 minerales del registro.
|
|
||||||
Success!=¡Éxito!
|
|
||||||
Manage settings for wielded cleaner tool.=Administrar a los ajustes de la herramienta cleaner empuñada.
|
|
||||||
Unrecognized wielded item: @1=Objeto empuñado desconocido: @1
|
|
||||||
Unrecognized action: @1=Acción desconocido: @1
|
|
||||||
You do not have permission to set radius that high. Reduced to @1.=No tienes permiso para poner al radio tan alto. Se reduce a @1.
|
|
||||||
Radius is too high. Reduced to @1.=El radio es demasiado alto. Se reduce a @1.
|
|
||||||
|
|
||||||
# tools:
|
|
||||||
@1: mode set to: @2=@1: modo configurado para: @2
|
|
||||||
@1: node set to: @2=@1: nodo configurado para: @2
|
|
||||||
Modes for tool "@1" not available.=Modos para herramienta "@1" no disponibles.
|
|
||||||
You do not have permission to use this item. Missing privs: @1=No tienes permiso para usar este objeto. Privs que faltan: @1
|
|
||||||
Unknown mode: @1=Modo desconocido: @1
|
|
||||||
Can't place node there.=No se puede poner nodo allí.
|
|
||||||
Cannot place unknown node: @1=No se puede poner nodo desconocido: @1
|
|
|
@ -1,66 +0,0 @@
|
||||||
# textdomain:cleaner
|
|
||||||
|
|
||||||
# Translators:
|
|
||||||
|
|
||||||
|
|
||||||
# chat commands
|
|
||||||
entity=
|
|
||||||
mode=
|
|
||||||
node=
|
|
||||||
radius=
|
|
||||||
old_item=
|
|
||||||
new_item=
|
|
||||||
old_node=
|
|
||||||
new_node=
|
|
||||||
ore=
|
|
||||||
action=
|
|
||||||
value=
|
|
||||||
Usage:=
|
|
||||||
Params:=
|
|
||||||
default: @1=
|
|
||||||
Search radius.=
|
|
||||||
Entity technical name.=
|
|
||||||
Node technical name.=
|
|
||||||
Technical name of node to be replaced.=
|
|
||||||
Technical name of node to be used in place.=
|
|
||||||
Technical name of item to be replaced.=
|
|
||||||
Technical name of item to be used in place.=
|
|
||||||
Ore technical name.=
|
|
||||||
Action to execute. Can be one of "@1", "@2", or "@3".=
|
|
||||||
Mode or node to be set for tool (not required for "@1" action).=
|
|
||||||
Remove an entity from game.=
|
|
||||||
Remove a node from game.=
|
|
||||||
Replace an item in game.=
|
|
||||||
Replace a node in game.=
|
|
||||||
Find names of unknown nodes.=
|
|
||||||
Find names of nearby nodes.=
|
|
||||||
Remove an ore from game.=
|
|
||||||
Missing parameter.=
|
|
||||||
Too many parameters.=
|
|
||||||
Radius must be a number.=
|
|
||||||
Cannot use unknown item "@1" as replacement.=
|
|
||||||
Cannot use unknown node "@1" as replacement.=
|
|
||||||
Replaced @1 nodes.=
|
|
||||||
Removed @1 nodes.=
|
|
||||||
Removed @1 entities.=
|
|
||||||
Found unknown nodes: @1=
|
|
||||||
No unknown nodes found.=
|
|
||||||
Nearby nodes: @1=
|
|
||||||
No nearby nodes found.=
|
|
||||||
Ore "@1" not found, not unregistering.=
|
|
||||||
Unregistered @1 ores (this will be undone after server restart).=
|
|
||||||
Success!=
|
|
||||||
Manage settings for wielded cleaner tool.=
|
|
||||||
Unrecognized wielded item: @1=
|
|
||||||
Unrecognized action: @1=
|
|
||||||
You do not have permission to set radius that high. Reduced to @1.=
|
|
||||||
Radius is too high. Reduced to @1.=
|
|
||||||
|
|
||||||
# tools:
|
|
||||||
@1: mode set to: @2=
|
|
||||||
Modes for tool "@1" not available.=
|
|
||||||
@1: node set to: @2=
|
|
||||||
You do not have permission to use this item. Missing privs: @1=
|
|
||||||
Can't place node there.=
|
|
||||||
Unknown mode: @1=
|
|
||||||
Cannot place unknown node: @1=
|
|
|
@ -1,258 +0,0 @@
|
||||||
|
|
||||||
local S = core.get_translator(cleaner.modname)
|
|
||||||
|
|
||||||
|
|
||||||
--- Cleans duplicate entries from indexed table.
|
|
||||||
--
|
|
||||||
-- @local
|
|
||||||
-- @function clean_duplicates
|
|
||||||
-- @tparam table t
|
|
||||||
-- @treturn table
|
|
||||||
local function clean_duplicates(t)
|
|
||||||
local tmp = {}
|
|
||||||
for _, v in ipairs(t) do
|
|
||||||
tmp[v] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
t = {}
|
|
||||||
for k in pairs(tmp) do
|
|
||||||
table.insert(t, k)
|
|
||||||
end
|
|
||||||
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
|
|
||||||
local world_file = core.get_worldpath() .. "/cleaner.json"
|
|
||||||
|
|
||||||
local function get_world_data()
|
|
||||||
local wdata = {}
|
|
||||||
local buffer = io.open(world_file, "r")
|
|
||||||
if buffer then
|
|
||||||
local err
|
|
||||||
wdata, err = core.parse_json(buffer:read("*a"), nil, true)
|
|
||||||
buffer:close()
|
|
||||||
if wdata == nil then
|
|
||||||
cleaner.log("warning", "reading world data file failed: " .. world_file)
|
|
||||||
wdata = {}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local rem_types = {"entities", "nodes", "ores",}
|
|
||||||
local rep_types = {"items", "nodes",}
|
|
||||||
|
|
||||||
for _, t in ipairs(rem_types) do
|
|
||||||
wdata[t] = wdata[t] or {}
|
|
||||||
wdata[t].remove = wdata[t].remove or {}
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, t in ipairs(rep_types) do
|
|
||||||
wdata[t] = wdata[t] or {}
|
|
||||||
wdata[t].replace = wdata[t].replace or {}
|
|
||||||
end
|
|
||||||
|
|
||||||
return wdata
|
|
||||||
end
|
|
||||||
|
|
||||||
local function update_world_data(t, data)
|
|
||||||
local wdata = get_world_data()
|
|
||||||
if t and data then
|
|
||||||
wdata[t].remove = data.remove
|
|
||||||
wdata[t].replace = data.replace
|
|
||||||
end
|
|
||||||
|
|
||||||
local json_string = core.write_json(wdata, true):gsub("\"remove\" : null", "\"remove\" : []")
|
|
||||||
:gsub("\"replace\" : null", "\"replace\" : {}")
|
|
||||||
|
|
||||||
local buffer = io.open(world_file, "w")
|
|
||||||
if buffer then
|
|
||||||
buffer:write(json_string)
|
|
||||||
buffer:close()
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local tool = {
|
|
||||||
modes = {
|
|
||||||
["cleaner:pencil"] = {"erase", "write", "swap"},
|
|
||||||
},
|
|
||||||
|
|
||||||
format_name = function(self, stack)
|
|
||||||
local iname = stack:get_name()
|
|
||||||
if iname == "cleaner:pencil_1" then
|
|
||||||
iname = "cleaner:pencil"
|
|
||||||
end
|
|
||||||
|
|
||||||
return iname
|
|
||||||
end,
|
|
||||||
|
|
||||||
set_mode = function(self, stack, mode, pname)
|
|
||||||
local iname = self:format_name(stack)
|
|
||||||
|
|
||||||
if not self.modes[iname] then
|
|
||||||
if pname then
|
|
||||||
core.chat_send_player(pname, iname .. ": " .. S("unknown mode: @1", mode))
|
|
||||||
end
|
|
||||||
cleaner.log("warning", iname .. ": unknown mode: " .. mode)
|
|
||||||
return stack
|
|
||||||
end
|
|
||||||
|
|
||||||
local imeta = stack:get_meta()
|
|
||||||
imeta:set_string("mode", mode)
|
|
||||||
|
|
||||||
if pname then
|
|
||||||
core.chat_send_player(pname, S("@1: mode set to: @2", iname, imeta:get_string("mode")))
|
|
||||||
end
|
|
||||||
|
|
||||||
local new_stack
|
|
||||||
if mode == "erase" then
|
|
||||||
new_stack = ItemStack("cleaner:pencil_1")
|
|
||||||
else
|
|
||||||
new_stack = ItemStack("cleaner:pencil")
|
|
||||||
end
|
|
||||||
|
|
||||||
local new_meta = new_stack:get_meta()
|
|
||||||
new_meta:from_table(imeta:to_table())
|
|
||||||
|
|
||||||
return new_stack
|
|
||||||
end,
|
|
||||||
|
|
||||||
next_mode = function(self, stack, pname)
|
|
||||||
local iname = self:format_name(stack)
|
|
||||||
local modes = self.modes[iname]
|
|
||||||
|
|
||||||
if not modes then
|
|
||||||
return false, stack, S('Modes for tool "@1" not available.', stack:get_name())
|
|
||||||
end
|
|
||||||
|
|
||||||
local imeta = stack:get_meta()
|
|
||||||
local current_mode = imeta:get_string("mode")
|
|
||||||
if not current_mode or current_mode:trim() == "" then
|
|
||||||
return true, self:set_mode(stack, modes[1], pname)
|
|
||||||
end
|
|
||||||
|
|
||||||
local idx = 1
|
|
||||||
for _, m in ipairs(modes) do
|
|
||||||
if current_mode == m then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
idx = idx + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
return true, self:set_mode(stack, modes[idx+1] or modes[1], pname)
|
|
||||||
end,
|
|
||||||
|
|
||||||
set_node = function(self, stack, node, pname)
|
|
||||||
local imeta = stack:get_meta()
|
|
||||||
imeta:set_string("node", node)
|
|
||||||
|
|
||||||
if pname then
|
|
||||||
core.chat_send_player(pname, S("@1: node set to: @2", stack:get_name(), imeta:get_string("node")))
|
|
||||||
end
|
|
||||||
|
|
||||||
return stack
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
|
|
||||||
local use_sounds = core.global_exists("sounds")
|
|
||||||
local sound_handle
|
|
||||||
|
|
||||||
tool.on_use = function(stack, user, pointed_thing)
|
|
||||||
if not user:is_player() then return end
|
|
||||||
|
|
||||||
local pname = user:get_player_name()
|
|
||||||
if not core.get_player_privs(pname).server then
|
|
||||||
core.chat_send_player(pname, S("You do not have permission to use this item. Missing privs: @1", "server"))
|
|
||||||
return stack
|
|
||||||
end
|
|
||||||
|
|
||||||
if sound_handle then
|
|
||||||
core.sound_stop(sound_handle)
|
|
||||||
sound_handle = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if pointed_thing.type == "node" then
|
|
||||||
local npos = core.get_pointed_thing_position(pointed_thing)
|
|
||||||
local imeta = stack:get_meta()
|
|
||||||
local mode = imeta:get_string("mode")
|
|
||||||
local new_node_name = imeta:get_string("node")
|
|
||||||
|
|
||||||
if mode == "erase" then
|
|
||||||
core.remove_node(npos)
|
|
||||||
if use_sounds then
|
|
||||||
local sound_handle = sounds.pencil_erase({object=user})
|
|
||||||
end
|
|
||||||
return stack
|
|
||||||
elseif core.registered_nodes[new_node_name] then
|
|
||||||
if mode == "swap" then
|
|
||||||
core.swap_node(npos, {name=new_node_name})
|
|
||||||
if use_sounds then
|
|
||||||
local sound_handle = sounds.pencil_write({object=user})
|
|
||||||
end
|
|
||||||
elseif mode == "write" then
|
|
||||||
local node_above = core.get_node_or_nil(pointed_thing.above)
|
|
||||||
if not node_above or node_above.name == "air" then
|
|
||||||
core.set_node(pointed_thing.above, {name=new_node_name})
|
|
||||||
if use_sounds then
|
|
||||||
local sound_handle = sounds.pencil_write({object=user})
|
|
||||||
end
|
|
||||||
else
|
|
||||||
core.chat_send_player(pname, S("Can't place node there."))
|
|
||||||
end
|
|
||||||
else
|
|
||||||
core.chat_send_player(pname, S("Unknown mode: @1", mode))
|
|
||||||
end
|
|
||||||
|
|
||||||
return stack
|
|
||||||
end
|
|
||||||
|
|
||||||
core.chat_send_player(pname, S("Cannot place unknown node: @1", new_node_name))
|
|
||||||
return stack
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
tool.on_secondary_use = function(stack, user, pointed_thing)
|
|
||||||
if not user:is_player() then return end
|
|
||||||
|
|
||||||
local pname = user:get_player_name()
|
|
||||||
if not core.get_player_privs(pname).server then
|
|
||||||
core.chat_send_player(pname, S("You do not have permission to use this item. Missing privs: @1", "server"))
|
|
||||||
return stack
|
|
||||||
end
|
|
||||||
|
|
||||||
local success, stack, msg = tool.next_mode(tool, stack, pname)
|
|
||||||
if not success then
|
|
||||||
core.chat_send_player(pname, msg)
|
|
||||||
end
|
|
||||||
|
|
||||||
return stack
|
|
||||||
end
|
|
||||||
|
|
||||||
tool.on_place = function(stack, placer, pointed_thing)
|
|
||||||
if not placer:is_player() then return end
|
|
||||||
|
|
||||||
local pname = placer:get_player_name()
|
|
||||||
if not core.get_player_privs(pname).server then
|
|
||||||
core.chat_send_player(pname, S("You do not have permission to use this item. Missing privs: @1", "server"))
|
|
||||||
return stack
|
|
||||||
end
|
|
||||||
|
|
||||||
if pointed_thing.type == "node" then
|
|
||||||
local node = core.get_node_or_nil(core.get_pointed_thing_position(pointed_thing))
|
|
||||||
if node then
|
|
||||||
stack = tool:set_node(stack, node.name, pname)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return stack
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
|
||||||
clean_duplicates = clean_duplicates,
|
|
||||||
get_world_data = get_world_data,
|
|
||||||
update_world_data = update_world_data,
|
|
||||||
tool = tool,
|
|
||||||
}
|
|
11
mod.conf
11
mod.conf
|
@ -1,7 +1,4 @@
|
||||||
name = cleaner
|
name = clean
|
||||||
description = A mod that can be used to remove/replace unknown entities, nodes, & items.
|
author = PilzAdam
|
||||||
version = 2025-01-18
|
license = WTFPL
|
||||||
license = MIT
|
version = 0.1
|
||||||
author = PilzAdam, Jordan Irwin (AntumDeluge)
|
|
||||||
min_minetest_version = 5.0
|
|
||||||
optional_depends = sounds
|
|
||||||
|
|
97
nodes.lua
97
nodes.lua
|
@ -1,97 +0,0 @@
|
||||||
|
|
||||||
local aux = dofile(cleaner.modpath .. "/misc_functions.lua")
|
|
||||||
|
|
||||||
-- populate nodes list from file in world path
|
|
||||||
local nodes_data = aux.get_world_data().nodes
|
|
||||||
|
|
||||||
|
|
||||||
-- START: backward compat
|
|
||||||
|
|
||||||
local n_path = core.get_worldpath() .. "/clean_nodes.json"
|
|
||||||
local n_file = io.open(n_path, "r")
|
|
||||||
|
|
||||||
if n_file then
|
|
||||||
cleaner.log("action", "found deprecated clean_nodes.json, updating")
|
|
||||||
|
|
||||||
local data_in = core.parse_json(n_file:read("*a"))
|
|
||||||
n_file:close()
|
|
||||||
if data_in then
|
|
||||||
if data_in.remove then
|
|
||||||
for _, r in ipairs(data_in.remove) do
|
|
||||||
table.insert(nodes_data.remove, r)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if data_in.replace then
|
|
||||||
for k, v in pairs(data_in.replace) do
|
|
||||||
if not nodes_data.replace[k] then
|
|
||||||
nodes_data.replace[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- don't read deprecated file again
|
|
||||||
os.rename(n_path, n_path .. ".old")
|
|
||||||
end
|
|
||||||
|
|
||||||
local n_path_old = core.get_worldpath() .. "/clean_nodes.txt"
|
|
||||||
n_file = io.open(n_path_old, "r")
|
|
||||||
|
|
||||||
if n_file then
|
|
||||||
cleaner.log("action", "found deprecated clean_nodes.txt, converting to json")
|
|
||||||
|
|
||||||
local data_in = string.split(n_file:read("*a"), "\n")
|
|
||||||
for _, e in ipairs(data_in) do
|
|
||||||
e = e:trim()
|
|
||||||
if e ~= "" and e:sub(1, 1) ~= "#" then
|
|
||||||
table.insert(nodes_data.remove, e)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
n_file:close()
|
|
||||||
os.rename(n_path_old, n_path_old .. ".old") -- don't read deprecated file again
|
|
||||||
end
|
|
||||||
|
|
||||||
-- END: backward compat
|
|
||||||
|
|
||||||
|
|
||||||
nodes_data.remove = aux.clean_duplicates(nodes_data.remove)
|
|
||||||
|
|
||||||
-- update json file with any changes
|
|
||||||
aux.update_world_data("nodes", nodes_data)
|
|
||||||
|
|
||||||
core.register_lbm({
|
|
||||||
name = "cleaner:remove_nodes",
|
|
||||||
nodenames = {"group:to_remove"},
|
|
||||||
run_at_every_load = true,
|
|
||||||
action = function(pos, node)
|
|
||||||
core.remove_node(pos)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
core.register_lbm({
|
|
||||||
name = "cleaner:replace_nodes",
|
|
||||||
nodenames = {"group:to_replace"},
|
|
||||||
run_at_every_load = true,
|
|
||||||
action = function(pos, node)
|
|
||||||
local new_node_name = cleaner.get_replace_nodes()[node.name]
|
|
||||||
if core.registered_nodes[new_node_name] then
|
|
||||||
core.swap_node(pos, {name=new_node_name})
|
|
||||||
else
|
|
||||||
cleaner.log("error", "cannot replace with unregistered node \"" .. tostring(new_node_name) .. "\"")
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
core.register_on_mods_loaded(function()
|
|
||||||
for _, n in ipairs(nodes_data.remove) do
|
|
||||||
cleaner.log("action", "registering node for removal: " .. n)
|
|
||||||
cleaner.register_node_removal(n)
|
|
||||||
end
|
|
||||||
|
|
||||||
for n_old, n_new in pairs(nodes_data.replace) do
|
|
||||||
cleaner.log("action", "registering node \"" .. n_old .. "\" to be replaced with \"" .. n_new .. "\"")
|
|
||||||
cleaner.register_node_replacement(n_old, n_new)
|
|
||||||
end
|
|
||||||
end)
|
|
17
ores.lua
17
ores.lua
|
@ -1,17 +0,0 @@
|
||||||
|
|
||||||
if not cleaner.unsafe then return end
|
|
||||||
|
|
||||||
local aux = dofile(cleaner.modpath .. "/misc_functions.lua")
|
|
||||||
|
|
||||||
local ores_data = aux.get_world_data().ores
|
|
||||||
|
|
||||||
for _, ore in ipairs(ores_data.remove) do
|
|
||||||
cleaner.register_ore_removal(ore)
|
|
||||||
end
|
|
||||||
|
|
||||||
core.register_on_mods_loaded(function()
|
|
||||||
for _, ore in ipairs(cleaner.get_remove_ores()) do
|
|
||||||
cleaner.log("action", "unregistering ore: " .. ore)
|
|
||||||
cleaner.remove_ore(ore)
|
|
||||||
end
|
|
||||||
end)
|
|
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 183 KiB |
|
@ -1,70 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import sys, os, codecs
|
|
||||||
|
|
||||||
|
|
||||||
f_script = os.path.realpath(__file__)
|
|
||||||
d_root = os.path.dirname(f_script)
|
|
||||||
|
|
||||||
os.chdir(d_root)
|
|
||||||
|
|
||||||
args = sys.argv[1:]
|
|
||||||
if len(args) < 1:
|
|
||||||
print("ERROR: must supply version as parameter")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
new_version = args[0]
|
|
||||||
|
|
||||||
to_update = {
|
|
||||||
"mod.conf": "version =",
|
|
||||||
"changelog.txt": "next",
|
|
||||||
os.path.normpath(".ldoc/config.ld"): "local version =",
|
|
||||||
}
|
|
||||||
|
|
||||||
for f in to_update:
|
|
||||||
f_path = os.path.join(d_root, f)
|
|
||||||
if not os.path.isfile(f_path):
|
|
||||||
print("WARNING: {} not found, skipping ...".format(f))
|
|
||||||
continue
|
|
||||||
|
|
||||||
print("\nsetting version to {} in {}".format(new_version, f_path))
|
|
||||||
|
|
||||||
buffer = codecs.open(f_path, "r", "utf-8")
|
|
||||||
if not buffer:
|
|
||||||
print("WARNING: could not open {} for reading, skipping ...".format(f))
|
|
||||||
continue
|
|
||||||
|
|
||||||
read_in = buffer.read()
|
|
||||||
buffer.close()
|
|
||||||
|
|
||||||
read_in = read_in.replace("\r\n", "\n").replace("\r", "\n")
|
|
||||||
replacement = to_update[f]
|
|
||||||
new_lines = []
|
|
||||||
|
|
||||||
version_set = False
|
|
||||||
for li in read_in.split("\n"):
|
|
||||||
if not version_set:
|
|
||||||
if "=" in replacement and li.startswith(replacement):
|
|
||||||
key = li.split(" = ")[0]
|
|
||||||
li = "{} = {}".format(key, new_version)
|
|
||||||
version_set = True
|
|
||||||
elif li == replacement:
|
|
||||||
li = "v{}".format(new_version)
|
|
||||||
version_set = True
|
|
||||||
|
|
||||||
new_lines.append(li)
|
|
||||||
|
|
||||||
write_out = "\n".join(new_lines)
|
|
||||||
if write_out == read_in:
|
|
||||||
print("no changes for {}, skipping ...".format(f))
|
|
||||||
continue
|
|
||||||
|
|
||||||
buffer = codecs.open(f_path, "w", "utf-8")
|
|
||||||
if not buffer:
|
|
||||||
print("WARNING: could not open {} for writing, skipping ...".format(f))
|
|
||||||
continue
|
|
||||||
|
|
||||||
buffer.write("\n".join(new_lines))
|
|
||||||
buffer.close()
|
|
||||||
|
|
||||||
print("done")
|
|
15
settings.lua
15
settings.lua
|
@ -1,15 +0,0 @@
|
||||||
|
|
||||||
--- Cleaner Settings
|
|
||||||
--
|
|
||||||
-- @topic settings
|
|
||||||
|
|
||||||
|
|
||||||
--- Enables unsafe methods & chat commands.
|
|
||||||
--
|
|
||||||
-- - `cleaner.remove_ore`
|
|
||||||
-- - `/remove_ores`
|
|
||||||
--
|
|
||||||
-- @setting cleaner.unsafe
|
|
||||||
-- @settype bool
|
|
||||||
-- @default false
|
|
||||||
cleaner.unsafe = core.settings:get_bool("cleaner.unsafe", false)
|
|
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
# Enables unsafe methods & chat commands.
|
|
||||||
#
|
|
||||||
# - cleaner.remove_ore
|
|
||||||
# - /remove_ores
|
|
||||||
cleaner.unsafe (Enable unsafe methods) bool false
|
|
Binary file not shown.
Before Width: | Height: | Size: 255 B |
44
tools.lua
44
tools.lua
|
@ -1,44 +0,0 @@
|
||||||
|
|
||||||
--- Cleaner Tools
|
|
||||||
--
|
|
||||||
-- @topic tools
|
|
||||||
|
|
||||||
|
|
||||||
local S = core.get_translator(cleaner.modname)
|
|
||||||
|
|
||||||
|
|
||||||
local aux = dofile(cleaner.modpath .. "/misc_functions.lua")
|
|
||||||
|
|
||||||
--- Master Pencil
|
|
||||||
--
|
|
||||||
-- @tool cleaner:pencil
|
|
||||||
-- @img cleaner_pencil.png
|
|
||||||
-- @priv server
|
|
||||||
-- @usage
|
|
||||||
-- place (right-click):
|
|
||||||
-- - when not pointing at a node, changes modes
|
|
||||||
-- - when pointing at a node, sets node to be used
|
|
||||||
--
|
|
||||||
-- use (left-click):
|
|
||||||
-- - executes action for current mode:
|
|
||||||
-- - erase: erases pointed node
|
|
||||||
-- - write: adds node
|
|
||||||
-- - swap: replaces pointed node
|
|
||||||
core.register_tool(cleaner.modname .. ":pencil", {
|
|
||||||
description = S("Master Pencil"),
|
|
||||||
inventory_image = "cleaner_pencil.png",
|
|
||||||
liquids_pointable = true,
|
|
||||||
on_use = aux.tool.on_use,
|
|
||||||
on_secondary_use = aux.tool.on_secondary_use,
|
|
||||||
on_place = aux.tool.on_place,
|
|
||||||
})
|
|
||||||
|
|
||||||
core.register_tool(cleaner.modname .. ":pencil_1", {
|
|
||||||
description = S("Master Pencil"),
|
|
||||||
inventory_image = "cleaner_pencil.png^[transformFXFY",
|
|
||||||
liquids_pointable = true,
|
|
||||||
groups = {not_in_creative_inventory=1},
|
|
||||||
on_use = aux.tool.on_use,
|
|
||||||
on_secondary_use = aux.tool.on_secondary_use,
|
|
||||||
on_place = aux.tool.on_place,
|
|
||||||
})
|
|
Loading…
Add table
Reference in a new issue