wardrobe/storage.lua

185 lines
4.6 KiB
Lua

wardrobe = wardrobe or {};
wardrobe.storage = wardrobe.storage or {};
local MOD_NAME = minetest.get_current_modname();
local MOD_PATH = minetest.get_modpath(MOD_NAME);
local WORLD_PATH = minetest.get_worldpath();
local SKIN_FILES = { MOD_PATH.."/skins.txt", WORLD_PATH.."/skins.txt" };
local PLAYER_SKIN_DB = WORLD_PATH.."/playerSkins.txt";
local function removePrefix(str, prefix)
local n = #prefix;
if #str >= n and string.sub(str, 1, n) == prefix then
return string.sub(str, n+1);
else
return str;
end
end
local function removeSuffix(str, suffix)
local n = #suffix;
if #str >= n and string.sub(str, -n, -1) == suffix then
return string.sub(str, 1, -(n+1));
else
return str;
end
end
local function trimTail(str)
local e = string.find(str, "%s+$");
return (e and string.sub(str, e-1)) or str;
end
local function parsePlayerSkinLine(line)
local k, v;
local p = string.find(line, "%S");
if p and not string.find(line, "^%-%-", p) then
local ss, se = string.find(line, "%s*:%s*", p);
if ss then
k = string.sub(line, p, ss-1);
v = trimTail(string.sub(line, se+1));
if k == "" then k = nil; end
if v == "" then v = nil; end
end
end
return k, v;
end
local function parseSkinLine(line)
local k, v, n, e;
local p = string.find(line, "%S");
if p then
n, e = string.find(line, "^%-%-?", p);
if not n or n == e then
if n then p = n+1; end
local ss, se = string.find(line, "%s*:%s*", p);
if ss then
k = string.sub(line, p, ss-1);
v = trimTail(string.sub(line, se+1));
if v == "" then v = nil; end
else
k = trimTail(string.sub(line, p));
end
if k == "" then k = nil; end
end
end
return k, v, n;
end
--- Parses the files with the given paths for key/value pairs. Once a key is
-- negated, it stays negated. Otherwise, the last (non-nil) value assigned to
-- a key wins.
--
-- @return A list of non-negated keys. This may include keys for which the
-- values are nil.
-- @return A map from key to value for all non-negated keys with non-nil
-- values.
--
local function loadSkinsFromFiles(filePaths)
local normKeys, negKeys, values = {}, {}, {}
for _, filePath in ipairs(filePaths) do
local file = io.open(filePath, "r");
if file then
for line in file:lines() do
local k, v, n = parseSkinLine(line)
if k then
if n then
normKeys[k] = nil;
values[k] = nil;
negKeys[k] = k;
elseif not negKeys[k] then
normKeys[k] = k;
if v then
values[k] = v;
end
end
end
end
file:close()
end
end
local keyList = {};
for k in pairs(normKeys) do
table.insert(keyList, k);
end
return keyList, values;
end
--- Loads skin names from skin files, storing the result in wardrobe.skins and
-- wardrobe.skinNames.
--
function wardrobe.storage.loadSkins()
local skins, skinNames = loadSkinsFromFiles(SKIN_FILES);
for i, skin in ipairs(skins) do
local name = skinNames[skin];
if not name then
local s, e;
name = removeSuffix(
removePrefix(
removePrefix(skin, MOD_NAME.."_"),
"skin_"),
".png");
if name == "" then
name = skin;
else
name = string.gsub(name, "_", " ");
end
end
skinNames[skin] = name;
end
table.sort(skins,
function(sL, sR)
return skinNames[sL] < skinNames[sR];
end);
wardrobe.skins = skins;
wardrobe.skinNames = skinNames;
end
--- Parses the player skins database file and stores the result in
-- wardrobe.playerSkins.
--
function wardrobe.storage.loadPlayerSkins()
local playerSkins = {};
local file = io.open(PLAYER_SKIN_DB, "r");
if file then
for line in file:lines() do
local name, skin = parsePlayerSkinLine(line);
if name then
playerSkins[name] = skin;
end
end
file:close();
end
wardrobe.playerSkins = playerSkins;
end
--- Writes wardrobe.playerSkins to the player skins database file.
--
function wardrobe.storage.savePlayerSkins()
local file = io.open(PLAYER_SKIN_DB, "w");
if not file then error("Couldn't write file '"..filePath.."'"); end
for name, skin in pairs(wardrobe.playerSkins) do
file:write(name, ":", skin, "\n");
end
file:close();
end