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()
function skins.get_player_skin(player)
local player_name = player:get_player_name()
local meta = player:get_meta()
if meta:get("skinsdb:skin_key") then
-- 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", "")
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
-- Assign skin to player

View File

@ -97,6 +97,65 @@ local function process_skin_texture(path, filename)
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
-- Load skins from the current mod directory
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.
character_[number or name].png
player_[nick]_png
player_[nick].png
player_[nick]_[number or name].png
... and corresponding previews that end in `_preview.png`.