Support custom props, custom media

The config stuff is in place, just doesn't
have an interface yet.
This commit is contained in:
Aaron Suen 2022-11-30 20:18:18 -05:00
parent 8777428dd1
commit 1adb4e5e27
7 changed files with 88 additions and 30 deletions

View File

@ -14,6 +14,8 @@ You will get a folder in your worldpath containing a skeletal mod:
- All media files referenced by the items, split into textures/sounds/models.
- An `exported.lua` file with each definition.
- A `mediasource.json` file that identifies the mod source of each media file included, for help tracing licensing and attribution.
- A `defripper.json` file that stores the configuration, and can be used to "rehydrate" the configuation in another world with the same mods installed, making it possible to incrementally extend the extracted data without needing to keep the entire original world around.
You will need to provide your own `init.lua`, `mod.conf` and other infrastructure, but the exported definitions are kept in a separate file so you can safely overwrite it later (e.g. if you add definitions) without destroying your custom logic.
@ -58,4 +60,18 @@ Minetest "items" includes all nodes, craftitems and tools. The definition rippe
- For each of these commands, if the `defripper_node_inv` setting is `true` (default `false`), it will descend into node meta inventories and rip items found there as well.
- `/defripper_here [rx [ry [rz]]]` - rip all nodes/items within a cuboid/rectanguloid centered around the player, right now.
- `/defripper_step [rx [ry [rz [step]]]]` - rip all nodes/items within a cuboid/rectanguloid centered around the player, continuously, every time the player moves `step` nodes, until the server is restarted or command is re-run to change it. `/defripper_step 0` disables it.
- `/defripper_step [rx [ry [rz [step]]]]` - rip all nodes/items within a cuboid/rectanguloid centered around the player, continuously, every time the player moves `step` nodes, until the server is restarted or command is re-run to change it. `/defripper_step 0` disables it.
## Advanced Usage
### Recreating World for Updates
It is not necessary to keep the original world you used defripper on to update your definitions, so long as you can recreate that world with the same mods.
- The defripper export contains its config, and you can copy it all back into the corresponding dir in the recreated world to restore state.
- defripper will warn you if there are any mods you're missing when trying to re-export. Finding the correct version, when forks exist, is still your responsibility, so you may want to keep note of which versions things were based on.
- Media files are NOT updated by default if they already exist in the dump, so you can use alternative or texturepack versions if you want. New ones are still added, and unused ones are still pruned. If you want to force an update, remove the affected media from the export.
### Custom Property Filtering
- TBD

4
TODO
View File

@ -1,9 +1,5 @@
------------------------------------------------------------------------
- Add some kind of warning when things are expected but missing, like
exported items that aren't found, in case a player recreated the
sampling world but forgot some mods.
- Commands to manage "extra media", for things that are related to a
definition but actually directly linked, like door open/close sounds
that may be wanted to use the door post-export. Using defripper's

View File

@ -1,8 +1,10 @@
-- LUALOCALS < ---------------------------------------------------------
local ipairs, minetest, next, pairs, pcall, string, tonumber, vector
= ipairs, minetest, next, pairs, pcall, string, tonumber, vector
local string_format, string_gsub, string_match
= string.format, string.gsub, string.match
local ipairs, minetest, next, pairs, pcall, string, table, tonumber,
vector
= ipairs, minetest, next, pairs, pcall, string, table, tonumber,
vector
local string_format, string_gsub, string_match, table_concat
= string.format, string.gsub, string.match, table.concat
-- LUALOCALS > ---------------------------------------------------------
local include = ...
@ -13,8 +15,19 @@ local modname = minetest.get_current_modname()
local function save_export_report()
savedb()
local defs, media = exportall()
return true, string_format("exported %d defs and %d media", defs, media)
local result = exportall()
local lines = {
string_format("exported %d def(s) and %d media",
result.exported_defs, result.exported_media)
}
for k, v in pairs(result.missing_defs) do
lines[#lines + 1] = string_format("WARNING: %d def(s) missing from mod %q", v, k)
end
for k, v in pairs(result.missing_media) do
lines[#lines + 1] = string_format("WARNING: %d medial file(s) missing from %q", v, k)
end
return true, table_concat(lines, "\n")
end
minetest.register_chatcommand(modname, {

View File

@ -49,7 +49,9 @@ end
------------------------------------------------------------------------
local allkeys = {
items = true
items = {},
media = {},
props = false,
}
setmetatable(configdb, {
__newindex = function(t, k, v)
@ -59,9 +61,9 @@ setmetatable(configdb, {
return rawset(t, k, v)
end
})
for k in pairs(allkeys) do
if not configdb[k] then
configdb[k] = {}
for k, v in pairs(allkeys) do
if v and not configdb[k] then
configdb[k] = v
end
end

View File

@ -45,6 +45,11 @@ local nodekeys = {
walkable = true,
wield_image = true,
}
for k, v in pairs(nodekeys) do
if v == true then
nodekeys[k] = function(def) return rawget(def, k) end
end
end
local blocked = {
air = true,
@ -70,18 +75,26 @@ local function exportall()
.. "\n\nlocal reg = ...\n\n")
local filtered = {}
for k, v in pairs(minetest.registered_items) do
if not blocked[k] and configdb.items[k] then
local t = {}
for k2, v2 in pairs(nodekeys) do
if type(v2) == "function" then
t[k2] = deepcopy(v2(v))
else
t[k2] = deepcopy(rawget(v, k2))
do
local props = configdb.props or nodekeys
for k, v in pairs(minetest.registered_items) do
if not blocked[k] and configdb.items[k] then
local t = {}
for k2, v2 in pairs(nodekeys) do
if props[k2] then
t[k2] = deepcopy(v2(v))
end
end
t._raw_name = k
filtered[k] = t
end
t._raw_name = k
filtered[k] = t
end
end
local missing_defs = {}
for k in pairs(configdb.items) do
if not (blocked[k] or filtered[k]) then
local mod = string_gsub(k, ":.*", "")
missing_defs[mod] = (missing_defs[mod] or 0) + 1
end
end
@ -162,6 +175,13 @@ local function exportall()
end
end
local missing_media = {}
for k, v in pairs(configdb.media) do
if not ripmedia(mymedia, k, outdir, v) then
missing_media[v] = (missing_media[v] or 0) + 1
end
end
local mediaqty = 0
if next(mymedia) then
local _, first = next(mymedia)
@ -189,7 +209,12 @@ local function exportall()
attrf:close()
end
return count, mediaqty
return {
exported_defs = count,
exported_media = mediaqty,
missing_defs = missing_defs,
missing_media = missing_media
}
end
return exportall

View File

@ -36,6 +36,7 @@ end
local function ripmedia(reffed, thing, dest, rel, test)
test = test or function(a, b) return a == b end
local foundany
if type(thing) == "string" then
for _, s in ipairs(string_gsub(thing, "[\\[:,=&{()]", "^"):split("^")) do
for k, v in pairs(mediacache) do
@ -43,15 +44,18 @@ local function ripmedia(reffed, thing, dest, rel, test)
local fulldest = getdir(dest .. "/" .. rel) .. "/" .. k
cpfile(v, fulldest)
reffed[fulldest] = v
foundany = true
break
end
end
end
elseif type(thing) == "table" then
if thing.name then return ripmedia(reffed, thing.name, dest, rel, test) end
for _, v in pairs(thing) do
ripmedia(reffed, v, dest, rel, test)
foundany = ripmedia(reffed, v, dest, rel, test) or foundany
end
end
return foundany
end
return getdir, ripmedia

View File

@ -1,6 +1,6 @@
-- LUALOCALS < ---------------------------------------------------------
local loadfile, minetest, unpack
= loadfile, minetest, unpack
local error, loadfile, minetest, unpack
= error, loadfile, minetest, unpack
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
@ -12,7 +12,9 @@ do
include = function(n)
local found = included[n]
if found ~= nil then return unpack(found) end
found = {loadfile(modpath .. "/" .. n .. ".lua")(include)}
local func, err = loadfile(modpath .. "/" .. n .. ".lua")
if not func then error(err) end
found = {func(include)}
included[n] = found
return unpack(found)
end