mirror of
https://github.com/minetest-mods/skinsdb.git
synced 2024-12-22 23:40:18 +01:00
Add migration code to player skins using '.' delimiters (#105)
Previously, the players would have their selected skin reset after renaming the skin textures to the dot separator. This commit implements skin name migration to ease the transition for server owners. See 'skins.__fuzzy_match_skin_name' for a detailed explanation.
This commit is contained in:
parent
71f803e2fb
commit
11bb5bad0e
18
api.lua
18
api.lua
@ -2,14 +2,26 @@
|
|||||||
local storage = minetest.get_mod_storage()
|
local storage = minetest.get_mod_storage()
|
||||||
|
|
||||||
function skins.get_player_skin(player)
|
function skins.get_player_skin(player)
|
||||||
|
local player_name = player:get_player_name()
|
||||||
local meta = player:get_meta()
|
local meta = player:get_meta()
|
||||||
if meta:get("skinsdb:skin_key") then
|
if meta:get("skinsdb:skin_key") then
|
||||||
-- Move player data prior July 2018 to mod storage
|
-- Move player data prior July 2018 to mod storage
|
||||||
storage:set_string(player:get_player_name(), meta:get_string("skinsdb:skin_key"))
|
storage:set_string(player_name, meta:get_string("skinsdb:skin_key"))
|
||||||
meta:set_string("skinsdb:skin_key", "")
|
meta:set_string("skinsdb:skin_key", "")
|
||||||
end
|
end
|
||||||
local skin = storage:get_string(player:get_player_name())
|
|
||||||
return skins.get(skin) or skins.get(skins.default)
|
local skin_name = storage:get_string(player_name)
|
||||||
|
local skin = skins.get(skin_name)
|
||||||
|
if #skin_name > 0 and not skin then
|
||||||
|
-- Migration step to convert `_`-delimited skins to `.` (if possible)
|
||||||
|
skin = skins.__fuzzy_match_skin_name(player_name, skin_name, true)
|
||||||
|
if skin then
|
||||||
|
storage:set_string(player_name, skin:get_key())
|
||||||
|
else
|
||||||
|
storage:set_string(player_name, "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return skin or skins.get(skins.default)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Assign skin to player
|
-- Assign skin to player
|
||||||
|
3
init.lua
3
init.lua
@ -111,3 +111,6 @@ minetest.register_allow_player_inventory_action(function(player, action, inv, da
|
|||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
--dofile(skins.modpath.."/unittest.lua")
|
||||||
|
|
||||||
|
59
skinlist.lua
59
skinlist.lua
@ -2,7 +2,8 @@ local dbgprint = false and print or function() end
|
|||||||
|
|
||||||
--- @param path Path to the "textures" directory, without tailing slash.
|
--- @param path Path to the "textures" directory, without tailing slash.
|
||||||
--- @param filename Current file name, such as "player.groot.17.png".
|
--- @param filename Current file name, such as "player.groot.17.png".
|
||||||
local function process_skin_texture(path, filename)
|
--- @return On error: false, error message. On success: true, skin key
|
||||||
|
function skins.register_skin(path, filename)
|
||||||
-- See "textures/readme.txt" for allowed formats
|
-- See "textures/readme.txt" for allowed formats
|
||||||
|
|
||||||
local prefix, sep, identifier, extension = filename:match("^(%a+)([_.])([%w_.]+)%.(%a+)$")
|
local prefix, sep, identifier, extension = filename:match("^(%a+)([_.])([%w_.]+)%.(%a+)$")
|
||||||
@ -16,17 +17,21 @@ local function process_skin_texture(path, filename)
|
|||||||
|
|
||||||
-- Filter out files that do not match the allowed patterns
|
-- Filter out files that do not match the allowed patterns
|
||||||
if not extension or extension:lower() ~= "png" then
|
if not extension or extension:lower() ~= "png" then
|
||||||
return -- Not a skin texture
|
return false, "invalid skin name"
|
||||||
end
|
end
|
||||||
if prefix ~= "player" and prefix ~= "character" then
|
if prefix ~= "player" and prefix ~= "character" then
|
||||||
return -- Unknown type
|
return false, "unknown type"
|
||||||
end
|
end
|
||||||
|
|
||||||
local preview_suffix = sep .. "preview"
|
local preview_suffix = sep .. "preview"
|
||||||
if identifier:sub(-#preview_suffix) == preview_suffix then
|
if identifier:sub(-#preview_suffix) == preview_suffix then
|
||||||
-- skip preview textures
|
-- The preview texture is added by the main skin texture (if exists)
|
||||||
-- This is added by the main skin texture (if exists)
|
return false, "preview texture"
|
||||||
return
|
end
|
||||||
|
|
||||||
|
assert(path)
|
||||||
|
if path == ":UNITTEST:" then
|
||||||
|
path = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
dbgprint("Found skin", prefix, identifier, extension)
|
dbgprint("Found skin", prefix, identifier, extension)
|
||||||
@ -58,12 +63,16 @@ local function process_skin_texture(path, filename)
|
|||||||
local skin_obj = skins.get(filename_noext) or skins.new(filename_noext)
|
local skin_obj = skins.get(filename_noext) or skins.new(filename_noext)
|
||||||
skin_obj:set_texture(filename)
|
skin_obj:set_texture(filename)
|
||||||
skin_obj:set_meta("_sort_id", sort_id)
|
skin_obj:set_meta("_sort_id", sort_id)
|
||||||
|
if sep ~= "_" then
|
||||||
|
skin_obj._legacy_name = filename_noext:gsub("[._]+", "_")
|
||||||
|
end
|
||||||
|
|
||||||
if playername then
|
if playername then
|
||||||
skin_obj:set_meta("assignment", "player:"..playername)
|
skin_obj:set_meta("assignment", "player:"..playername)
|
||||||
skin_obj:set_meta("playername", playername)
|
skin_obj:set_meta("playername", playername)
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
if path then
|
||||||
-- Get type of skin based on dimensions
|
-- Get type of skin based on dimensions
|
||||||
local file = io.open(path .. "/" .. filename, "r")
|
local file = io.open(path .. "/" .. filename, "r")
|
||||||
local skin_format = skins.get_skin_format(file)
|
local skin_format = skins.get_skin_format(file)
|
||||||
@ -74,7 +83,7 @@ local function process_skin_texture(path, filename)
|
|||||||
skin_obj:set_hand_from_texture()
|
skin_obj:set_hand_from_texture()
|
||||||
skin_obj:set_meta("name", identifier)
|
skin_obj:set_meta("name", identifier)
|
||||||
|
|
||||||
do
|
if path then
|
||||||
-- Optional skin information
|
-- Optional skin information
|
||||||
local file = io.open(path .. "/../meta/" .. filename_noext .. ".txt", "r")
|
local file = io.open(path .. "/../meta/" .. filename_noext .. ".txt", "r")
|
||||||
if file then
|
if file then
|
||||||
@ -86,7 +95,7 @@ local function process_skin_texture(path, filename)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
if path then
|
||||||
-- Optional preview texture
|
-- Optional preview texture
|
||||||
local preview_name = filename_noext .. sep .. "preview.png"
|
local preview_name = filename_noext .. sep .. "preview.png"
|
||||||
local fh = io.open(path .. "/" .. preview_name)
|
local fh = io.open(path .. "/" .. preview_name)
|
||||||
@ -95,6 +104,36 @@ local function process_skin_texture(path, filename)
|
|||||||
skin_obj:set_preview(preview_name)
|
skin_obj:set_preview(preview_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return true, skin_obj:get_key()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Internal function. Fallback/migration code for `.`-delimited skin names that
|
||||||
|
--- were equipped between d3c7fa7 and 312780c (master branch).
|
||||||
|
--- During this period, `.`-delimited skin names were internally registered with
|
||||||
|
--- `_` delimiters. This function tries to find a matching skin.
|
||||||
|
--- @param player_name (string)
|
||||||
|
--- @param skin_name (string) e.g. `player_foo_mc_bar`
|
||||||
|
--- @param be_noisy (boolean) whether to print a warning in case of mismatches`
|
||||||
|
--- @return On match, the new skin (skins.skin_class) or `nil` if nothing matched.
|
||||||
|
function skins.__fuzzy_match_skin_name(player_name, skin_name, be_noisy)
|
||||||
|
if select(2, skin_name:gsub("%.", "")) > 0 then
|
||||||
|
-- Not affected by ambiguity
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, skin in pairs(skins.meta) do
|
||||||
|
if skin._legacy_name == skin_name then
|
||||||
|
dbgprint("Match", skin_name, skin:get_key())
|
||||||
|
return skin
|
||||||
|
end
|
||||||
|
--dbgprint("Try match", skin_name, skin:get_key(), skin._legacy_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
if be_noisy then
|
||||||
|
minetest.log("warning", "skinsdb: cannot find matching skin '" ..
|
||||||
|
skin_name .. "' for player '" .. player_name .. "'.")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -103,7 +142,7 @@ do
|
|||||||
local skins_dir_list = minetest.get_dir_list(skins_path)
|
local skins_dir_list = minetest.get_dir_list(skins_path)
|
||||||
|
|
||||||
for _, fn in pairs(skins_dir_list) do
|
for _, fn in pairs(skins_dir_list) do
|
||||||
process_skin_texture(skins_path, fn)
|
skins.register_skin(skins_path, fn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ The character `_` is accepted in player names, thus it is not recommended to
|
|||||||
use such file names. For compatibility reasons, they are still recognized.
|
use such file names. For compatibility reasons, they are still recognized.
|
||||||
|
|
||||||
character_[number or name].png
|
character_[number or name].png
|
||||||
player_[nick]_png
|
player_[nick].png
|
||||||
player_[nick]_[number or name].png
|
player_[nick]_[number or name].png
|
||||||
|
|
||||||
... and corresponding previews that end in `_preview.png`.
|
... and corresponding previews that end in `_preview.png`.
|
||||||
|
50
unittest.lua
Normal file
50
unittest.lua
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
local function get_skin(skin_name)
|
||||||
|
local skin = skins.get(skin_name)
|
||||||
|
or skins.__fuzzy_match_skin_name("(unittest)", skin_name, true)
|
||||||
|
return skin and skin:get_key() or nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function run_unittest()
|
||||||
|
local PATH = ":UNITTEST:"
|
||||||
|
|
||||||
|
-- -----
|
||||||
|
-- `.`: Simple register + retrieve operations
|
||||||
|
skins.register_skin(PATH, "player.DotSep.png")
|
||||||
|
skins.register_skin(PATH, "player._DotSep_666_.1.png")
|
||||||
|
|
||||||
|
assert(get_skin("player.DotSep"))
|
||||||
|
assert(get_skin("player._DotSep_666_.1"))
|
||||||
|
assert(get_skin("player.DotSep.1") == nil)
|
||||||
|
|
||||||
|
-- -----
|
||||||
|
-- Ambiguous skin names (filenames without extension). Register + retrieve
|
||||||
|
skins.new("player_AmbSki")
|
||||||
|
skins.new("player_AmbSki_1")
|
||||||
|
skins.new("player_AmbSki_666_1")
|
||||||
|
|
||||||
|
assert(get_skin("player_AmbSki"))
|
||||||
|
assert(get_skin("player_AmbSki_") == nil)
|
||||||
|
assert(get_skin("player_AmbSki_1"))
|
||||||
|
assert(get_skin("player_AmbSki_666_1"))
|
||||||
|
-- There are no `__` patterns as they were silently removed by string.split
|
||||||
|
|
||||||
|
|
||||||
|
-- -----
|
||||||
|
-- Mod Storage backwards compatibility
|
||||||
|
-- Match the old `_` notation to `.`-separated skins
|
||||||
|
skins.register_skin(PATH, "player.ComPat42.png")
|
||||||
|
skins.register_skin(PATH, "player.ComPat42.5.png")
|
||||||
|
skins.register_skin(PATH, "player._Com_Pat_42.png")
|
||||||
|
skins.register_skin(PATH, "player._Com_Pat_42.1.png")
|
||||||
|
|
||||||
|
assert(get_skin("player_ComPat42") == "player.ComPat42")
|
||||||
|
assert(get_skin("player_ComPat42_5") == "player.ComPat42.5")
|
||||||
|
assert(get_skin("player_Com_Pat_42") == "player._Com_Pat_42")
|
||||||
|
assert(get_skin("player_Com_Pat_42_1") == "player._Com_Pat_42.1")
|
||||||
|
|
||||||
|
|
||||||
|
error("Unittest passed! Please disable them now.")
|
||||||
|
end
|
||||||
|
|
||||||
|
run_unittest()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user