171 lines
6.0 KiB
Lua
171 lines
6.0 KiB
Lua
local concat_path = modlib.file.concat_path
|
|
local auth_handler = minetest.get_auth_handler()
|
|
|
|
epidermis.paths = {dynamic_textures = {}}
|
|
for _, folder in pairs{"skindb", "epidermi"} do
|
|
local path = modlib.file.concat_path({ minetest.get_worldpath(), "data", "epidermis", "textures", folder })
|
|
minetest.mkdir(path)
|
|
epidermis.paths.dynamic_textures[folder] = path
|
|
end
|
|
epidermis.paths.playerdata = modlib.file.concat_path({ minetest.get_worldpath(), "data", "epidermis", "players" })
|
|
minetest.mkdir(epidermis.paths.playerdata)
|
|
|
|
function epidermis.get_player_data(playername)
|
|
local filepath = concat_path{epidermis.paths.playerdata, playername .. ".lua"}
|
|
local content = modlib.file.read(filepath)
|
|
if not content then return end
|
|
local playerdata = assert(modlib.luon:read_string(content))
|
|
return playerdata
|
|
end
|
|
|
|
function epidermis.set_player_data(playername, data)
|
|
local filepath = concat_path{epidermis.paths.playerdata, playername .. ".lua"}
|
|
assert(modlib.file.write(filepath, modlib.luon:write_string(data)))
|
|
end
|
|
|
|
local function player_exists(name)
|
|
if name == "singleplayer" and minetest.is_singleplayer() then
|
|
return true
|
|
end
|
|
return auth_handler.get_auth(name) ~= nil
|
|
end
|
|
|
|
-- Remove unused player data & mark used textures
|
|
local used_textures = {}
|
|
for _, filename in ipairs(minetest.get_dir_list(epidermis.paths.playerdata, false)) do
|
|
local playername = filename:match"^(.-)%.lua$"
|
|
if playername then
|
|
local playerdata = epidermis.get_player_data(playername)
|
|
used_textures[playerdata.epidermis] = true
|
|
end
|
|
end
|
|
|
|
-- HACK the auth handler returns nil at load time (see https://github.com/minetest/minetest/issues/11956)
|
|
minetest.after(0, function()
|
|
for _, filename in ipairs(minetest.get_dir_list(epidermis.paths.playerdata, false)) do
|
|
local playername = filename:match"^(.-)%.lua$"
|
|
if playername and not player_exists(playername) then
|
|
local playerdata = epidermis.get_player_data(playername)
|
|
used_textures[playerdata.epidermis] = true
|
|
assert(os.remove(concat_path{epidermis.paths.playerdata, playername .. ".lua"}))
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- Remove unused textures & store highest texture ID
|
|
local epidermi_texture_path = epidermis.paths.dynamic_textures.epidermi
|
|
for _, dirname in ipairs(minetest.get_dir_list(epidermi_texture_path, true)) do
|
|
local dir_path = concat_path{epidermi_texture_path, dirname}
|
|
local highest_number
|
|
local last_filename
|
|
local used = false
|
|
local function remove_if_unused(filename)
|
|
if used_textures[filename] then
|
|
used = true
|
|
else
|
|
assert(os.remove(concat_path{dir_path, filename}))
|
|
end
|
|
end
|
|
local filenames = minetest.get_dir_list(dir_path, false)
|
|
local delete = modlib.table.contains(filenames, "delete")
|
|
if delete then
|
|
-- Move deletion marker to end through a swap so that it is deleted last
|
|
filenames[#filenames], filenames[delete] = filenames[delete], filenames[#filenames]
|
|
end
|
|
for _, filename in ipairs(filenames) do
|
|
if delete then
|
|
remove_if_unused(filename)
|
|
else
|
|
local number = filename:match("^" .. modlib.text.escape_magic_chars(dirname) .. "_(%d+)%.png$")
|
|
if number then
|
|
number = tonumber(number)
|
|
if last_filename then
|
|
if number > highest_number then
|
|
remove_if_unused(last_filename)
|
|
highest_number = number
|
|
last_filename = filename
|
|
else
|
|
remove_if_unused(filename)
|
|
end
|
|
else
|
|
highest_number = number
|
|
last_filename = filename
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if not used and (delete or #filenames == 0) then
|
|
assert(os.remove(dir_path))
|
|
end
|
|
end
|
|
|
|
function epidermis.get_epidermis_path(paintable_id, texture_id)
|
|
local texture_name = ("epidermis_paintable_%d_%d.png"):format(paintable_id, texture_id)
|
|
local path = concat_path{
|
|
epidermi_texture_path,
|
|
("epidermis_paintable_%d"):format(paintable_id),
|
|
texture_name
|
|
}
|
|
return path, texture_name
|
|
end
|
|
|
|
function epidermis.get_epidermis_path_from_texture(dynamic_texture)
|
|
local tex_name, dir_name = dynamic_texture:match"^((epidermis_paintable_%d+)_%d+.png)$"
|
|
if not (tex_name and dir_name) then return end
|
|
return modlib.file.concat_path{epidermi_texture_path, dir_name, tex_name}
|
|
end
|
|
|
|
function epidermis.get_last_epidermis_path(paintable_id)
|
|
local dir_name = ("epidermis_paintable_%d"):format(paintable_id)
|
|
local max_tex_id = -math.huge
|
|
for _, filename in ipairs(minetest.get_dir_list(concat_path{epidermi_texture_path, dir_name}, false)) do
|
|
local number = filename:match("^" .. modlib.text.escape_magic_chars(dir_name) .. "_(%d+)%.png$")
|
|
if number then
|
|
max_tex_id = math.max(max_tex_id, tonumber(number))
|
|
end
|
|
end
|
|
if max_tex_id == -math.huge then return end
|
|
return epidermis.get_epidermis_path(paintable_id, max_tex_id)
|
|
end
|
|
|
|
function epidermis.write_epidermis(paintable_id, texture_id, raw_png_data)
|
|
local path, texture_name = epidermis.get_epidermis_path(paintable_id, texture_id)
|
|
assert(modlib.file.write_binary(path, raw_png_data))
|
|
return path, texture_name
|
|
end
|
|
|
|
function epidermis.mark_for_deletion(paintable_id)
|
|
assert(modlib.file.write_unsafe(concat_path{
|
|
epidermi_texture_path,
|
|
("epidermis_paintable_%d"):format(paintable_id),
|
|
"delete"
|
|
}, ""))
|
|
end
|
|
|
|
-- SkinDB
|
|
|
|
function epidermis.write_skindb_skin(id, raw_png_data, meta_data)
|
|
local texture_name = ("epidermis_skindb_%d.png"):format(id)
|
|
local path = concat_path{ epidermis.paths.dynamic_textures.skindb, texture_name }
|
|
assert(modlib.file.write_binary(path, raw_png_data))
|
|
assert(modlib.file.write(concat_path{ epidermis.paths.dynamic_textures.skindb, texture_name .. ".json" },
|
|
modlib.json:write_string(meta_data)))
|
|
return path, texture_name
|
|
end
|
|
|
|
function epidermis.remove_skindb_skin(id)
|
|
local texture_name = ("epidermis_skindb_%d.png"):format(id)
|
|
local path = concat_path{ epidermis.paths.dynamic_textures.skindb, texture_name }
|
|
assert(os.remove(path))
|
|
assert(os.remove(path .. ".json"))
|
|
end
|
|
|
|
-- Player-set epidermis persistence
|
|
minetest.register_on_joinplayer(function(player)
|
|
local data = epidermis.get_player_data(player:get_player_name())
|
|
if data then
|
|
epidermis.dynamic_add_media(assert(epidermis.get_epidermis_path_from_texture(data.epidermis)), function()
|
|
epidermis.set_skin(player, data.epidermis)
|
|
end, true)
|
|
end
|
|
end) |