Initial completion
This commit is contained in:
commit
f91d7157fa
12
.luacheckrc
Normal file
12
.luacheckrc
Normal file
@ -0,0 +1,12 @@
|
||||
globals = {
|
||||
"minetest",
|
||||
"vector",
|
||||
"ItemStack",
|
||||
"VoxelArea",
|
||||
"vector",
|
||||
"SecureRandom",
|
||||
"PcgRandom
|
||||
"profiler",
|
||||
}
|
||||
color = false
|
||||
quiet = 1
|
7
.lualocals
Normal file
7
.lualocals
Normal file
@ -0,0 +1,7 @@
|
||||
minetest
|
||||
ItemStack
|
||||
VoxelArea
|
||||
vector
|
||||
SecureRandom
|
||||
PcgRandom
|
||||
profiler
|
20
LICENSE
Normal file
20
LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (C)2024 Aaron Suen <warr1024@gmail.com>
|
||||
|
||||
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.
|
22
aaschemlib/alphabet.lua
Normal file
22
aaschemlib/alphabet.lua
Normal file
@ -0,0 +1,22 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local string
|
||||
= string
|
||||
local string_sub
|
||||
= string.sub
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
-- Define the chars that are allowed to be used in ascii art tables.
|
||||
-- The size of the alphabet limits the maximum number of unique node
|
||||
-- definition types that can be used in a single schematic.
|
||||
local alphabet = {}
|
||||
do
|
||||
-- Only use printable 7-bit ascii characters that don't
|
||||
-- require escaping in a lua string, for compatibility.
|
||||
local chars = " .abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
.. "0123456789,/;'[]`-=<>?:{}|~!@#$%^&*()_+"
|
||||
for i = 1, #chars do
|
||||
alphabet[#alphabet + 1] = string_sub(chars, i, i)
|
||||
end
|
||||
end
|
||||
|
||||
return alphabet
|
60
aaschemlib/api_asciiart_to_lua.lua
Normal file
60
aaschemlib/api_asciiart_to_lua.lua
Normal file
@ -0,0 +1,60 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local dofile, ipairs, minetest, pairs, rawget, rawset, string, table
|
||||
= dofile, ipairs, minetest, pairs, rawget, rawset, string, table
|
||||
local string_format, table_concat
|
||||
= string.format, table.concat
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local alphabet = dofile(minetest.get_modpath(
|
||||
minetest.get_current_modname()) .. "/alphabet.lua")
|
||||
|
||||
-- Dump an asciiart lua table in a format optimized for editing.
|
||||
-- Use loadstring/dofile/etc to reverse.
|
||||
local function asciiart_to_lua(aa)
|
||||
local t = {
|
||||
"return {",
|
||||
"\tnodes = {",
|
||||
}
|
||||
for _, k in pairs(alphabet) do
|
||||
local v = aa.nodes[k]
|
||||
if v then
|
||||
local u = {}
|
||||
if v.name then u[#u + 1] = string_format("name = %q", v.name) end
|
||||
if v.param2 then u[#u + 1] = string_format("param2 = %d", v.param2) end
|
||||
if v.prob then u[#u + 1] = string_format("prob = %d", v.prob) end
|
||||
if v.force then u[#u + 1] = "force = true" end
|
||||
t[#t + 1] = string_format("\t\t[%q] = {%s},", k, table_concat(u, ", "))
|
||||
end
|
||||
end
|
||||
t[#t + 1] = "\t},"
|
||||
if aa.sliceprob then
|
||||
t[#t + 1] = "\tsliceprob = {"
|
||||
for y = 0, aa.size.y - 1 do
|
||||
local p = aa.sliceprob[y]
|
||||
if p then
|
||||
t[#t + 1] = string_format("\t\t[%d] = %d,", y, p)
|
||||
end
|
||||
end
|
||||
t[#t + 1] = "\t},"
|
||||
end
|
||||
t[#t + 1] = "\tlayers = {"
|
||||
for _, layer in ipairs(aa.layers) do
|
||||
t[#t + 1] = "\t\t{"
|
||||
local row = 1
|
||||
for _, row in ipairs(layer) do
|
||||
t[#t + 1] = string_format("\t\t\t%q,", row)
|
||||
end
|
||||
t[#t + 1] = "\t\t},"
|
||||
end
|
||||
t[#t + 1] = "\t},"
|
||||
t[#t + 1] = "}"
|
||||
return table_concat(t, "\n")
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
local api = rawget(_G, modname) or {}
|
||||
rawset(_G, modname, api)
|
||||
|
||||
api.asciiart_to_lua = asciiart_to_lua
|
43
aaschemlib/api_asciiart_to_schematic.lua
Normal file
43
aaschemlib/api_asciiart_to_schematic.lua
Normal file
@ -0,0 +1,43 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local error, ipairs, minetest, pairs, rawget, rawset
|
||||
= error, ipairs, minetest, pairs, rawget, rawset
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
-- Convert an asciiart lua table back into a minetest schematic one,
|
||||
-- reversing schematic_to_asciiart.
|
||||
local function asciiart_to_schematic(aa)
|
||||
local schem = {
|
||||
size = {y = #aa.layers},
|
||||
data = {},
|
||||
yslice_prob = {},
|
||||
}
|
||||
for y, ys in ipairs(aa.layers) do
|
||||
if schem.size.z and schem.size.z ~= #ys then
|
||||
error("inconsistent z size")
|
||||
end
|
||||
schem.size.z = #ys
|
||||
for z, zs in ipairs(ys) do
|
||||
if schem.size.x and schem.size.x ~= #zs then
|
||||
error("inconsistent x size")
|
||||
end
|
||||
schem.size.x = #zs
|
||||
for x = 1, zs:len() do
|
||||
local node = aa.nodes[zs:sub(x, x)]
|
||||
schem.data[(schem.size.z - z) * schem.size.x * schem.size.y
|
||||
+ (y - 1) * schem.size.x + x] = node
|
||||
end
|
||||
end
|
||||
end
|
||||
for k, v in pairs(aa.sliceprob or {}) do
|
||||
yslice_prob[#yslice_prob + 1] = {ypos = k, prob = v}
|
||||
end
|
||||
return schem
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
local api = rawget(_G, modname) or {}
|
||||
rawset(_G, modname, api)
|
||||
|
||||
api.asciiart_to_schematic = asciiart_to_schematic
|
103
aaschemlib/api_schematic_to_asciiart.lua
Normal file
103
aaschemlib/api_schematic_to_asciiart.lua
Normal file
@ -0,0 +1,103 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local dofile, error, minetest, next, pairs, rawget, rawset, string
|
||||
= dofile, error, minetest, next, pairs, rawget, rawset, string
|
||||
local string_sub
|
||||
= string.sub
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local alphabet = dofile(minetest.get_modpath(
|
||||
minetest.get_current_modname()) .. "/alphabet.lua")
|
||||
|
||||
-- Convert a schematic lua table (in the format of minetest.read_schematic)
|
||||
-- into an asciiart lua table. Use asciiart_to_schematic to reverse.
|
||||
local function schematic_to_asciiart(mts)
|
||||
local nodes = {
|
||||
-- Reserve space for "void" (don't overwrite existing node)
|
||||
[" "] = {prob = 0},
|
||||
-- Reserve period for air (just remove existing node)
|
||||
["."] = {name = "air"},
|
||||
}
|
||||
local alphaidx = 3
|
||||
local usage = {}
|
||||
|
||||
local layers = {}
|
||||
local function set(x, y, z, s)
|
||||
x, y, z = x + 1, y + 1, mts.size.z - z
|
||||
local l = layers[y]
|
||||
if not l then
|
||||
l = {}
|
||||
layers[y] = l
|
||||
end
|
||||
local r = l[z] or ""
|
||||
while (#r < x) do r = r .. " " end
|
||||
l[z] = string_sub(r, 1, x - 1)
|
||||
.. s .. string_sub(r, x + 2)
|
||||
usage[s] = true
|
||||
end
|
||||
|
||||
local i = 1
|
||||
for z = 0, mts.size.z - 1 do
|
||||
for y = 0, mts.size.y - 1 do
|
||||
for x = 0, mts.size.x - 1 do
|
||||
local v = mts.data[i]
|
||||
i = i + 1
|
||||
local t = {
|
||||
name = v.name,
|
||||
param2 = v.param2,
|
||||
prob = v.prob,
|
||||
force = v.force_place or nil
|
||||
}
|
||||
if t.param2 == 0 then t.param2 = nil end
|
||||
if t.prob and t.prob >= 254 then t.prob = nil end
|
||||
if t.prob and t.prob <= 0 then
|
||||
t.name = nil
|
||||
t.param2 = nil
|
||||
end
|
||||
local added
|
||||
for nk, nv in pairs(nodes) do
|
||||
if nv.name == t.name and nv.param2 == t.param2
|
||||
and nv.prob == nv.prob and nv.force == t.force then
|
||||
set(x, y, z, nk)
|
||||
added = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not added then
|
||||
local s = alphabet[alphaidx]
|
||||
alphaidx = alphaidx + 1
|
||||
if not s then error("too many unique nodes for chars") end
|
||||
nodes[s] = t
|
||||
set(x, y, z, s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local t = {}
|
||||
for k, v in pairs(mts) do t[k] = v end
|
||||
t.size = nil
|
||||
t.data = nil
|
||||
t.layers = layers
|
||||
t.nodes = {}
|
||||
for k in pairs(usage) do
|
||||
t.nodes[k] = nodes[k]
|
||||
end
|
||||
if t.yslice_prob and next(t.yslice_prob) then
|
||||
local d = {}
|
||||
for _, v in pairs(t.yslice_prob) do
|
||||
d[v.ypos] = v.prob
|
||||
end
|
||||
t.sliceprob = d
|
||||
end
|
||||
t.yslice_prob = nil
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
local api = rawget(_G, modname) or {}
|
||||
rawset(_G, modname, api)
|
||||
|
||||
api.schematic_to_asciiart = schematic_to_asciiart
|
11
aaschemlib/init.lua
Normal file
11
aaschemlib/init.lua
Normal file
@ -0,0 +1,11 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local dofile, ipairs, minetest
|
||||
= dofile, ipairs, minetest
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
for _, fn in ipairs({
|
||||
"api_asciiart_to_lua",
|
||||
"api_asciiart_to_schematic",
|
||||
"api_schematic_to_asciiart",
|
||||
}) do dofile(modpath .. "/" .. fn .. ".lua") end
|
3
aaschemlib/mod.conf
Normal file
3
aaschemlib/mod.conf
Normal file
@ -0,0 +1,3 @@
|
||||
name = aaschemlib
|
||||
title = ASCII Art Schematic Library
|
||||
description = Library for converting Minetest schematics to/from ASCII art
|
BIN
aaschemlib/screenshot.png
Normal file
BIN
aaschemlib/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
53
aaschemtools/api_fileconv.lua
Normal file
53
aaschemtools/api_fileconv.lua
Normal file
@ -0,0 +1,53 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local io, minetest, pairs, pcall, rawget, rawset, string, unpack
|
||||
= io, minetest, pairs, pcall, rawget, rawset, string, unpack
|
||||
local io_open, string_format, string_sub
|
||||
= io.open, string.format, string.sub
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local function fileconv(func)
|
||||
return function(_, param)
|
||||
local src, dest = unpack(param:split(" "))
|
||||
if (not src) or (src == "") or (not dest) or (dest == "") then
|
||||
return false, "incorrect params"
|
||||
end
|
||||
|
||||
-- Input pathnames can be prefixed with modname: to make the path
|
||||
-- relative to a loaded mod. Input pathnames can be prefixed with
|
||||
-- just a bare colon to make the path relative to the loaded world.
|
||||
for _, n in pairs(minetest.get_modnames()) do
|
||||
if string_sub(src, 1, #n + 1) == n .. ":" then
|
||||
src = minetest.get_modpath(n) .. "/" .. string_sub(src, #n + 2)
|
||||
end
|
||||
end
|
||||
if string_sub(src, 1, 1) == ":" then
|
||||
src = minetest.get_worldpath() .. "/" .. string_sub(src, 2)
|
||||
end
|
||||
|
||||
-- Output pathnames must always be relative to the world path.
|
||||
dest = minetest.get_worldpath() .. "/" .. dest
|
||||
|
||||
-- Run the conversion process and check for errors.
|
||||
local okay, result = pcall(func, src, dest)
|
||||
if not okay then
|
||||
return false, string_format("error convertin %q to %q: %s", src, dest, result)
|
||||
end
|
||||
|
||||
-- Write the output
|
||||
local f = io_open(dest, "wb")
|
||||
if not f then
|
||||
return false, string_format("failed to open %q for writing", dest)
|
||||
end
|
||||
f:write(result)
|
||||
f:close()
|
||||
return true, string_format("wrote %d bytes to %q", #result, dest)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
local api = rawget(_G, modname) or {}
|
||||
rawset(_G, modname, api)
|
||||
|
||||
api.fileconv = fileconv
|
18
aaschemtools/cmd_aa2mts.lua
Normal file
18
aaschemtools/cmd_aa2mts.lua
Normal file
@ -0,0 +1,18 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local dofile, minetest, rawget
|
||||
= dofile, minetest, rawget
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
local api = rawget(_G, modname)
|
||||
|
||||
minetest.register_chatcommand("aa2mts", {
|
||||
privs = {server = true},
|
||||
description = "Convert Lua AA schematic to MTS (WARNING: Arbitrary Code Execution)",
|
||||
params = "modname:path/to/file.lua output.mts",
|
||||
func = api.fileconv(function(src, dest)
|
||||
return minetest.serialize_schematic(
|
||||
aaschemlib.asciiart_to_schematic(dofile(src)),
|
||||
"mts", {})
|
||||
end)
|
||||
})
|
22
aaschemtools/cmd_mts2aa.lua
Normal file
22
aaschemtools/cmd_mts2aa.lua
Normal file
@ -0,0 +1,22 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, rawget
|
||||
= minetest, rawget
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
local api = rawget(_G, modname)
|
||||
|
||||
minetest.register_chatcommand("mts2aa", {
|
||||
privs = {server = true},
|
||||
description = "Convert MTS schematic to Lua AA",
|
||||
params = "modname:path/to/file.mts output.lua",
|
||||
func = api.fileconv(function(src, dest)
|
||||
return aaschemlib.asciiart_to_lua(
|
||||
aaschemlib.schematic_to_asciiart(
|
||||
minetest.read_schematic(src, {
|
||||
write_yslice_prob = "low"
|
||||
})
|
||||
)
|
||||
)
|
||||
end)
|
||||
})
|
11
aaschemtools/init.lua
Normal file
11
aaschemtools/init.lua
Normal file
@ -0,0 +1,11 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local dofile, ipairs, minetest
|
||||
= dofile, ipairs, minetest
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
for _, fn in ipairs({
|
||||
"api_fileconv",
|
||||
"cmd_mts2aa",
|
||||
"cmd_aa2mts",
|
||||
}) do dofile(modpath .. "/" .. fn .. ".lua") end
|
4
aaschemtools/mod.conf
Normal file
4
aaschemtools/mod.conf
Normal file
@ -0,0 +1,4 @@
|
||||
name = aaschemtools
|
||||
title = ASCII Art Schematic Tools
|
||||
description = Developer tools for converting Minetest schematics to/from ASCII art
|
||||
depends = aaschemlib
|
BIN
aaschemtools/screenshot.png
Normal file
BIN
aaschemtools/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
BIN
cdb-screen.webp
Normal file
BIN
cdb-screen.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 99 KiB |
2
modpack.conf
Normal file
2
modpack.conf
Normal file
@ -0,0 +1,2 @@
|
||||
title = ASCII Art Schematics
|
||||
description = Manage Minetest schematics as ASCII art
|
BIN
screenshot.png
Normal file
BIN
screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
Loading…
x
Reference in New Issue
Block a user