-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpersistence.lua
171 lines (155 loc) · 5.99 KB
/
persistence.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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)