mirror of
https://codeberg.org/AntumLuanti/mod-cleaner.git
synced 2025-04-30 14:11:44 -04:00
Compare commits
160 commits
Author | SHA1 | Date | |
---|---|---|---|
|
c72b710c56 | ||
|
209008b88d | ||
|
f35e2f1808 | ||
|
ecf5201220 | ||
|
0d42a1bdd8 | ||
|
7d47f8ff5d | ||
|
93fa96d6c2 | ||
|
9ca550703b | ||
|
b261dda15c | ||
|
06e4408b91 | ||
|
6b3220048b | ||
|
f0004e3c7b | ||
|
e3959a815f | ||
|
45e59dbf8b | ||
|
0098ef5da4 | ||
|
51a812fa86 | ||
|
5efafec098 | ||
|
0ab5d51584 | ||
|
319e671fc2 | ||
|
dd61f9f9cf | ||
|
8645c7aa49 | ||
|
3ac5558a9e | ||
|
50c7a8cd98 | ||
|
f9acae8bc7 | ||
|
93767a2723 | ||
|
da24ace035 | ||
|
e5e0d7f620 | ||
|
b6ce523957 | ||
|
c00ee93e79 | ||
|
bb528d74a8 | ||
|
7f9e645900 | ||
|
fd6032a879 | ||
|
28f1f355c0 | ||
|
df81a7755b | ||
|
689f911cb3 | ||
|
9c80a957e3 | ||
|
29f772dc92 | ||
|
9972213c9b | ||
|
0dbd7b1243 | ||
|
0acbd3318b | ||
|
95adf18f23 | ||
|
09d6475ce0 | ||
|
1277f7a784 | ||
|
44f643195c | ||
|
657ba25890 | ||
|
df515241ed | ||
|
f4b1053064 | ||
|
cbc6235f25 | ||
|
9052543301 | ||
|
970d8b3aab | ||
|
c41f6e8a0a | ||
|
f4b3e2e7c2 | ||
|
c13f78b471 | ||
|
99544d286f | ||
|
fbcfe1646a | ||
|
4d959e69cb | ||
|
c98f6a656e | ||
|
3a708a03b6 | ||
|
e0bf9a56e6 | ||
|
4c5069447c | ||
|
64f31da3f2 | ||
|
c5ae889ee5 | ||
|
cc11d749c2 | ||
|
a708add44d | ||
|
182726e999 | ||
|
982a746e23 | ||
|
14394db3ea | ||
|
4f9e5a6434 | ||
|
43dadcb706 | ||
|
ca65bafb5f | ||
|
d3082948b1 | ||
|
cf01b532f0 | ||
|
d4ec55be08 | ||
|
9dfa90292c | ||
|
6c1104d19b | ||
|
6bbc63dd19 | ||
|
a657e566d5 | ||
|
b9455caeb2 | ||
|
6b211cf5f6 | ||
|
84d3960664 | ||
|
a221c11ec6 | ||
|
b1fd6df8ce | ||
|
5568a1e91a | ||
|
d2209675ed | ||
|
cad47e4c88 | ||
|
4bb6bd0300 | ||
|
9365fd9515 | ||
|
9fa1b2b4ff | ||
|
9230e0c392 | ||
|
3080612409 | ||
|
2c9a44fbc1 | ||
|
7a482de659 | ||
|
5fcc824d0e | ||
|
e81ed836dc | ||
|
9592b1df73 | ||
|
f8fd1506eb | ||
|
cc5856b561 | ||
|
4cece82cfa | ||
|
df3428059c | ||
|
50db695476 | ||
|
1495ebea16 | ||
|
02489ec530 | ||
|
bb36a723d3 | ||
|
efc5ef2660 | ||
|
37ca2b7dab | ||
|
d065c3f7ae | ||
|
ad2fc046a1 | ||
|
13a6fd04be | ||
|
2d7c5aee1f | ||
|
69f87b6b73 | ||
|
7f042330b1 | ||
|
7d5f61756e | ||
|
bf37b2e4a5 | ||
|
0d4b29573c | ||
|
2afbdd55e2 | ||
|
fe80682515 | ||
|
bb94fa86a2 | ||
|
958d45775c | ||
|
e75ee0ccd8 | ||
|
261d0ed5e7 | ||
|
774b22a55b | ||
|
7280c2a538 | ||
|
3ee5184958 | ||
|
2c127af4af | ||
|
6b50d1c52a | ||
|
f247118c63 | ||
|
80e70900b2 | ||
|
540ee14930 | ||
|
51e76caeb2 | ||
|
7a2d38a64c | ||
|
0daee12f57 | ||
|
8b5d09283e | ||
|
9876268545 | ||
|
e8359d8db3 | ||
|
35f409c5c0 | ||
|
8a7fc3ca04 | ||
|
d69e47ca2a | ||
|
871981ddd7 | ||
|
00ab41d6de | ||
|
839c32f5c0 | ||
|
5c58fd8f5d | ||
|
5a918081e2 | ||
|
9130ca1034 | ||
|
1f169c5774 | ||
|
6d4fb21114 | ||
|
68222b1479 | ||
|
076211d48c | ||
|
388e5481e7 | ||
|
04338946da | ||
|
0fcbdb8edf | ||
|
c5e9b10fcb | ||
|
5054f4c185 | ||
|
6622ea8bab | ||
|
49fc2c6315 | ||
|
f7e12b5f77 | ||
|
a0a3dc370d | ||
|
9200ed9c20 | ||
|
3b02b109f5 | ||
|
d9c7f9bab5 | ||
|
1efe6ea229 |
30 changed files with 2362 additions and 69 deletions
11
.cdb.json
Normal file
11
.cdb.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"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
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.* export-ignore
|
||||
*.py export-ignore
|
30
.github/workflows/reference.yml
vendored
Normal file
30
.github/workflows/reference.yml
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
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/
|
98
.ldoc/build_versioned_docs.sh
Executable file
98
.ldoc/build_versioned_docs.sh
Executable file
|
@ -0,0 +1,98 @@
|
|||
#!/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
Normal file
201
.ldoc/config.ld
Normal file
|
@ -0,0 +1,201 @@
|
|||
|
||||
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
|
55
.ldoc/config.luadoc
Normal file
55
.ldoc/config.luadoc
Normal file
|
@ -0,0 +1,55 @@
|
|||
|
||||
--- 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",
|
||||
-- },
|
||||
-- },
|
||||
-- }
|
54
.ldoc/gendoc.sh
Executable file
54
.ldoc/gendoc.sh
Executable file
|
@ -0,0 +1,54 @@
|
|||
#!/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!"
|
81
.ldoc/tags.ld
Normal file
81
.ldoc/tags.ld
Normal file
|
@ -0,0 +1,81 @@
|
|||
|
||||
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,13 +1,21 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2021 Jordan Irwin (AntumDeluge)
|
||||
|
||||
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
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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,18 +1,86 @@
|
|||
## Clean mod for [Minetest][]
|
||||
## Cleaner mod for Luanti
|
||||
|
||||
### 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)
|
||||
|
||||
|
||||
---
|
||||
### **Description:**
|
||||
|
||||
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
|
||||
[Luanti]: https://luanti.org/
|
||||
[f.pilzadam]: https://forum.luanti.org/viewtopic.php?t=2777
|
||||
[ContentDB]: https://content.luanti.org/packages/AntumDeluge/cleaner/
|
||||
|
|
14
TODO.txt
Normal file
14
TODO.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
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
Normal file
194
api.lua
Normal file
|
@ -0,0 +1,194 @@
|
|||
|
||||
--- 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
|
63
changelog.txt
Normal file
63
changelog.txt
Normal file
|
@ -0,0 +1,63 @@
|
|||
|
||||
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
Normal file
660
chat.lua
Normal file
|
@ -0,0 +1,660 @@
|
|||
|
||||
--- 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 +0,0 @@
|
|||
A very simple mod that deletes unknown blocks and removes unknown entities.
|
59
entities.lua
Normal file
59
entities.lua
Normal file
|
@ -0,0 +1,59 @@
|
|||
|
||||
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,43 +1,48 @@
|
|||
-- clean by PilzAdam
|
||||
-- LICENSE: WTFPL
|
||||
|
||||
local old_nodes = {}
|
||||
local old_entities = {}
|
||||
cleaner = {}
|
||||
cleaner.modname = core.get_current_modname()
|
||||
cleaner.modpath = core.get_modpath(cleaner.modname)
|
||||
|
||||
-- Old/Missing nodes that should be replaced with something currently in game
|
||||
local replace_nodes = {}
|
||||
local cleaner_debug = core.settings:get_bool("enable_debug_mods", false)
|
||||
|
||||
function cleaner.log(lvl, msg)
|
||||
if lvl == "debug" and not cleaner_debug then return end
|
||||
|
||||
-- "Replaces" an old/non-existent node
|
||||
local function replace_node(old_node, new_node)
|
||||
minetest.register_alias(old_node, new_node)
|
||||
if lvl and not msg then
|
||||
msg = lvl
|
||||
lvl = nil
|
||||
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
|
||||
|
||||
local aux = dofile(cleaner.modpath .. "/misc_functions.lua")
|
||||
|
||||
for _,node_name in ipairs(old_nodes) do
|
||||
minetest.register_node(':'..node_name, {
|
||||
groups = {old=1},
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {'group:old'},
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
action = function(pos, node)
|
||||
minetest.remove_node(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
for _,entity_name in ipairs(old_entities) do
|
||||
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])
|
||||
-- initialize world file
|
||||
aux.update_world_data()
|
||||
|
||||
|
||||
local scripts = {
|
||||
"settings",
|
||||
"api",
|
||||
"chat",
|
||||
"tools",
|
||||
"entities",
|
||||
"nodes",
|
||||
"items",
|
||||
"ores",
|
||||
}
|
||||
|
||||
for _, script in ipairs(scripts) do
|
||||
dofile(cleaner.modpath .. "/" .. script .. ".lua")
|
||||
end
|
||||
|
|
49
items.lua
Normal file
49
items.lua
Normal file
|
@ -0,0 +1,49 @@
|
|||
|
||||
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)
|
66
locale/cleaner.es.tr
Normal file
66
locale/cleaner.es.tr
Normal file
|
@ -0,0 +1,66 @@
|
|||
# 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
|
66
locale/template.txt
Normal file
66
locale/template.txt
Normal file
|
@ -0,0 +1,66 @@
|
|||
# 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=
|
258
misc_functions.lua
Normal file
258
misc_functions.lua
Normal file
|
@ -0,0 +1,258 @@
|
|||
|
||||
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,4 +1,7 @@
|
|||
name = clean
|
||||
author = PilzAdam
|
||||
license = WTFPL
|
||||
version = 0.1
|
||||
name = cleaner
|
||||
description = A mod that can be used to remove/replace unknown entities, nodes, & items.
|
||||
version = 2025-01-18
|
||||
license = MIT
|
||||
author = PilzAdam, Jordan Irwin (AntumDeluge)
|
||||
min_minetest_version = 5.0
|
||||
optional_depends = sounds
|
||||
|
|
97
nodes.lua
Normal file
97
nodes.lua
Normal file
|
@ -0,0 +1,97 @@
|
|||
|
||||
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
Normal file
17
ores.lua
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
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
Normal file
BIN
screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 183 KiB |
70
set_version.py
Executable file
70
set_version.py
Executable file
|
@ -0,0 +1,70 @@
|
|||
#!/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
Normal file
15
settings.lua
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
--- 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)
|
6
settingtypes.txt
Normal file
6
settingtypes.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
# Enables unsafe methods & chat commands.
|
||||
#
|
||||
# - cleaner.remove_ore
|
||||
# - /remove_ores
|
||||
cleaner.unsafe (Enable unsafe methods) bool false
|
BIN
textures/cleaner_pencil.png
Normal file
BIN
textures/cleaner_pencil.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 255 B |
44
tools.lua
Normal file
44
tools.lua
Normal file
|
@ -0,0 +1,44 @@
|
|||
|
||||
--- 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