Add migration code to player skins using '.' delimiters

Previously, the players would have their selected skin reset.
See 'skins.__fuzzy_match_skin_name' for a detailed explanation.

This also fixes an issue where player.[name].[number].png skins
were not recognized.
This commit is contained in:
SmallJoker 2024-06-09 17:26:11 +02:00
parent 71f803e2fb
commit 00e5696eec
3 changed files with 75 additions and 4 deletions

18
api.lua
View File

@ -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

View File

@ -97,6 +97,65 @@ local function process_skin_texture(path, filename)
end end
end 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
--[[
Public skin names:
character_[number]
Private skin names:
player_sam_doe
player_sam_doe_1234 <-- might also belong to player "sam_doe_1233"
. ^^^^^^^^^^^^ identifier
^^^^^^------------- prefix
Approach: try to find a match for the longest possible name
Assumption 1: There are no skin variations without numeric ending
Assumption 2: Player names to not end with `_%d+`
]]
local prefix, identifier = unpack(skin_name:split("_", true, 1))
local for_player, number
if prefix == "player" then
for_player, number = identifier:match("^([%w_]+)_(%d+)$")
if not number then
for_player = identifier
end
else -- character
number = identifier
end
local skin = nil
if not for_player or for_player == player_name then
skin = skins.get(prefix
.. (for_player and ("." .. for_player) or "")
.. (number and ("." .. number) or "")
)
end
if skin then
-- MATCH!
dbgprint("Match", skin_name, skin:get_key())
return skin
end
if be_noisy then
minetest.log("warning", "skinsdb: cannot find matching skin '" ..
skin_name .. "' for player '" .. player_name .. "'.")
end
end
do do
-- Load skins from the current mod directory -- Load skins from the current mod directory
local skins_path = skins.modpath.."/textures" local skins_path = skins.modpath.."/textures"

View File

@ -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`.