From 6756658ee9d70b89afaf8c3b6a7c40b92e88dc84 Mon Sep 17 00:00:00 2001 From: teknomunk Date: Thu, 2 May 2024 03:01:43 +0000 Subject: [PATCH] Fix server crash when server restarts after a player dies but they didn't respawn (#4246) Ensuring that tables storing player data are initialized before being used. Reviewed-on: https://git.minetest.land/MineClone2/MineClone2/pulls/4246 Reviewed-by: the-real-herowl Co-authored-by: teknomunk Co-committed-by: teknomunk --- mods/ENTITIES/mcl_item_entity/init.lua | 9 +-- mods/HELP/mcl_craftguide/init.lua | 57 +++++++++------- mods/HUD/mcl_inventory/survival.lua | 11 +++- mods/HUD/mcl_offhand/init.lua | 29 +++++++-- mods/PLAYER/mcl_player/init.lua | 27 ++++++-- mods/PLAYER/mcl_skins/edit_skin.lua | 90 +++++++++++++++----------- 6 files changed, 138 insertions(+), 85 deletions(-) diff --git a/mods/ENTITIES/mcl_item_entity/init.lua b/mods/ENTITIES/mcl_item_entity/init.lua index daf8986fb..1734fa6af 100644 --- a/mods/ENTITIES/mcl_item_entity/init.lua +++ b/mods/ENTITIES/mcl_item_entity/init.lua @@ -6,9 +6,6 @@ local pool = {} local tick = false - - - minetest.register_on_joinplayer(function(player) pool[player:get_player_name()] = 0 end) @@ -172,17 +169,17 @@ minetest.register_globalstep(function(_) local pos = player:get_pos() - if tick == true and pool[name] > 0 then + if tick == true and (pool[name] or 0) > 0 then minetest.sound_play("item_drop_pickup", { pos = pos, gain = 0.3, max_hear_distance = 16, pitch = math.random(70, 110) / 100 }) - if pool[name] > 6 then + if (pool[name] or 0) > 6 then pool[name] = 6 else - pool[name] = pool[name] - 1 + pool[name] = (pool[name] or 1) - 1 end end diff --git a/mods/HELP/mcl_craftguide/init.lua b/mods/HELP/mcl_craftguide/init.lua index 80df19b90..41fb392fa 100644 --- a/mods/HELP/mcl_craftguide/init.lua +++ b/mods/HELP/mcl_craftguide/init.lua @@ -106,6 +106,31 @@ local item_lists = { "craftpreview", } +local function init_data(name) + player_data[name] = { + filter = "", + pagenum = 1, + iX = sfinv_only and 8 or DEFAULT_SIZE, + items = init_items, + items_raw = init_items, + lang_code = M.get_player_information(name).lang_code or 'en', + } +end +local function get_player_data(name) + -- If the data alrady exists, use it + local data = player_data[name] + if data then return data end + + -- Initialize player data if it doesn't exist + init_data(name) + local player = minetest.get_player_by_name(name) + local meta = player:get_meta() + local data = player_data[name] + + data.inv_items = deserialize(meta:get_string("inv_items")) or {} + return data +end + local function table_merge(t, t2) t, t2 = t or {}, t2 or {} local c = #t @@ -624,7 +649,7 @@ local function get_recipe_fs(data, iY) end local function make_formspec(name) - local data = player_data[name] + local data = get_player_data(name) local iY = sfinv_only and 4 or data.iX - 5 local ipp = data.iX * iY @@ -831,17 +856,6 @@ local function get_inv_items(player) return inv_items end -local function init_data(name) - player_data[name] = { - filter = "", - pagenum = 1, - iX = sfinv_only and 8 or DEFAULT_SIZE, - items = init_items, - items_raw = init_items, - lang_code = M.get_player_information(name).lang_code or 'en', - } -end - local function reset_data(data) data.filter = "" data.pagenum = 1 @@ -877,7 +891,7 @@ end local function on_receive_fields(player, fields) local name = player:get_player_name() - local data = player_data[name] + local data = get_player_data(name) for elem_name, def in pairs(formspec_elements) do if fields[elem_name] and def.action then @@ -981,7 +995,7 @@ if sfinv_only then on_enter = function(self, player, context) if next(recipe_filters) then local name = player:get_player_name() - local data = player_data[name] + local data = get_player_data(name) data.items_raw = get_filtered_items(player) search(data) @@ -1005,7 +1019,7 @@ else local name = user:get_player_name() if next(recipe_filters) then - local data = player_data[name] + local data = get_player_data(name) data.items_raw = get_filtered_items(user) search(data) end @@ -1051,7 +1065,7 @@ if progressive_mode then local function progressive_filter(recipes, player) local name = player:get_player_name() - local data = player_data[name] + local data = get_player_data(name) if #data.inv_items == 0 then return {} @@ -1076,7 +1090,7 @@ if progressive_mode then for i = 1, #players do local player = players[i] local name = player:get_player_name() - local data = player_data[name] + local data = get_player_data(name) local inv_items = get_inv_items(player) local diff = table_diff(inv_items, data.inv_items) @@ -1095,12 +1109,7 @@ if progressive_mode then mcl_craftguide.add_recipe_filter("Default progressive filter", progressive_filter) M.register_on_joinplayer(function(player) - local name = player:get_player_name() - init_data(name) - local meta = player:get_meta() - local data = player_data[name] - - data.inv_items = deserialize(meta:get_string("inv_items")) or {} + get_player_data(player:get_player_name()) end) local function save_meta(player) @@ -1145,7 +1154,7 @@ end function mcl_craftguide.show(name) local player = get_player_by_name(name) if next(recipe_filters) then - local data = player_data[name] + local data = get_player_data(name) data.items_raw = get_filtered_items(player) search(data) end diff --git a/mods/HUD/mcl_inventory/survival.lua b/mods/HUD/mcl_inventory/survival.lua index 4922c8f88..253109cb7 100644 --- a/mods/HUD/mcl_inventory/survival.lua +++ b/mods/HUD/mcl_inventory/survival.lua @@ -36,9 +36,14 @@ function mcl_inventory.register_survival_inventory_tab(def) end local player_current_tab = {} +function get_player_tab(player) + local tab = player_current_tab[player] or "main" + player_current_tab[player] = tab + return tab +end minetest.register_on_joinplayer(function(player, last_login) - player_current_tab[player] = "main" + get_player_tab(player) end) minetest.register_on_leaveplayer(function(player, timed_out) @@ -184,7 +189,7 @@ function mcl_inventory.build_survival_formspec(player) inv:set_width("craft", 2) inv:set_size("craft", 4) - local tab = player_current_tab[player] + local tab = get_player_tab(player) local tab_def = nil @@ -213,7 +218,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end for _, d in ipairs(mcl_inventory.registered_survival_inventory_tabs) do - if player_current_tab[player] == d.id and d.access(player) then + if get_player_tab(player) == d.id and d.access(player) then d.handle(player, fields) return end diff --git a/mods/HUD/mcl_offhand/init.lua b/mods/HUD/mcl_offhand/init.lua index 98954b4f5..e9129e537 100644 --- a/mods/HUD/mcl_offhand/init.lua +++ b/mods/HUD/mcl_offhand/init.lua @@ -16,19 +16,31 @@ local function offhand_get_count(player) return mcl_offhand.get_offhand(player):get_count() end -minetest.register_on_joinplayer(function(player, last_login) - mcl_offhand[player] = { +local function get_offhand(player) + -- Get offhand data if it already exists + local offhand = mcl_offhand[player] + if offhand then return offhand end + + -- Otherwise initialize it + offhand = { hud = {}, last_wear = offhand_get_wear(player), last_count = offhand_get_count(player), } + mcl_offhand[player] = offhand + return offhand +end + +minetest.register_on_joinplayer(function(player, last_login) + get_offhand(player) end) local function remove_hud(player, hud) - local offhand_hud = mcl_offhand[player].hud[hud] + local offhand = get_offhand(player) + local offhand_hud = offhand.hud[hud] if offhand_hud then player:hud_remove(offhand_hud) - mcl_offhand[player].hud[hud] = nil + offhand.hud[hud] = nil end end @@ -48,7 +60,8 @@ local function update_wear_bar(player, itemstack) else color = {255, 511 - wear_i, 0} end - local wear_bar = mcl_offhand[player].hud.wear_bar + local offhand = get_offhand(player) + local wear_bar = offhand.hud.wear_bar player:hud_change(wear_bar, "text", "mcl_wear_bar.png^[colorize:#" .. rgb_to_hex(color[1], color[2], color[3])) player:hud_change(wear_bar, "scale", {x = 40 * wear_bar_percent, y = 3}) player:hud_change(wear_bar, "offset", {x = -320 - (20 - player:hud_get(wear_bar).scale.x / 2), y = -13}) @@ -58,7 +71,8 @@ minetest.register_globalstep(function(dtime) for _, player in pairs(minetest.get_connected_players()) do local itemstack = mcl_offhand.get_offhand(player) local offhand_item = itemstack:get_name() - local offhand_hud = mcl_offhand[player].hud + local offhand = get_offhand(player) + local offhand_hud = offhand.hud local item = minetest.registered_items[offhand_item] if offhand_item ~= "" and item then local item_texture = item.inventory_image .. "^[resize:" .. max_offhand_px .. "x" .. max_offhand_px @@ -145,7 +159,8 @@ minetest.register_globalstep(function(dtime) end elseif offhand_hud.slot then - for index, _ in pairs(mcl_offhand[player].hud) do + local offhand = get_offhand(player) + for index, _ in pairs(offhand.hud) do remove_hud(player, index) end end diff --git a/mods/PLAYER/mcl_player/init.lua b/mods/PLAYER/mcl_player/init.lua index d5e1df5a7..164e0083b 100644 --- a/mods/PLAYER/mcl_player/init.lua +++ b/mods/PLAYER/mcl_player/init.lua @@ -38,9 +38,19 @@ local player_sneak = {} local player_visible = {} mcl_player.player_attached = {} +local function get_player_textures(name) + local textures = player_textures[name] + if textures then return textures end + + local textures = { "character.png", "blank.png", "blank.png" } + player_textures[name] = textures + return textures + +end + function mcl_player.player_get_animation(player) local name = player:get_player_name() - local textures = player_textures[name] + local textures = get_player_textures(name) if not player_visible[name] then textures = table.copy(textures) @@ -63,7 +73,7 @@ end local function update_player_textures(player) local name = player:get_player_name() - local textures = player_textures[name] + local textures = get_player_textures(name) if not player_visible[name] then textures = table.copy(textures) @@ -125,18 +135,21 @@ end function mcl_player.player_set_skin(player, texture) local name = player:get_player_name() - player_textures[name][1] = texture + local textures = get_player_textures(name) + textures[1] = texture update_player_textures(player) end function mcl_player.player_get_skin(player) local name = player:get_player_name() - return player_textures[name][1] + local textures = get_player_textures(name) + return textures[1] end function mcl_player.player_set_armor(player, texture) local name = player:get_player_name() - player_textures[name][2] = texture + local textures = get_player_textures(name) + textures[2] = texture update_player_textures(player) end @@ -151,7 +164,7 @@ function mcl_player.get_player_formspec_model(player, x, y, w, h, fsname) local name = player:get_player_name() local model = player_model[name] local anim = models[model].animations[player_anim[name]] - local textures = player_textures[name] + local textures = get_player_textures(name) if not player_visible[name] then textures = table.copy(textures) textures[1] = "blank.png" @@ -179,7 +192,7 @@ minetest.register_on_joinplayer(function(player) local name = player:get_player_name() mcl_player.player_attached[name] = false player_visible[name] = true - player_textures[name] = { "character.png", "blank.png", "blank.png" } + get_player_textures(name) --player:set_local_animation({x=0, y=79}, {x=168, y=187}, {x=189, y=198}, {x=200, y=219}, 30) -- player:set_fov(86.1) -- see >>> diff --git a/mods/PLAYER/mcl_skins/edit_skin.lua b/mods/PLAYER/mcl_skins/edit_skin.lua index 8531e4263..2128986e4 100644 --- a/mods/PLAYER/mcl_skins/edit_skin.lua +++ b/mods/PLAYER/mcl_skins/edit_skin.lua @@ -59,6 +59,50 @@ mcl_skins = { player_formspecs = {}, } +local player_skins = mcl_skins.player_skins + +local function get_player_skins(player) + local player_skins = player_skins[player] + if player_skins then return player_skins end + + local skin = player:get_meta():get_string("mcl_skins:skin") + if skin then + skin = minetest.deserialize(skin) + end + if skin then + if not mcl_skins.texture_to_simple_skin[skin.simple_skins_id] then + skin.simple_skins_id = nil + end + + mcl_skins.player_skins[player] = skin + else + if math.random() > 0.5 then + skin = table.copy(mcl_skins.template1) + else + skin = table.copy(mcl_skins.template2) + end + mcl_skins.player_skins[player] = skin + end + + mcl_skins.player_formspecs[player] = { + active_tab = "skin", + page_num = 1 + } + + if #mcl_skins.simple_skins > 0 then + local skin_id = tonumber(player:get_meta():get_string("mcl_skins:skin_id")) + if skin_id and mcl_skins.simple_skins[skin_id] then + local texture = mcl_skins.simple_skins[skin_id].texture + local player_skins = get_player_skins(player) + player_skins.simple_skins_id = texture + end + end + mcl_skins.save(player) + mcl_skins.update_player_skin(player) + + return mcl_skins.player_skins[player] +end + function mcl_skins.register_item(item) assert(mcl_skins[item.type], "Skin item type " .. item.type .. " does not exist.") @@ -160,7 +204,7 @@ function mcl_skins.update_player_skin(player) return end - local skin = mcl_skins.player_skins[player] + local skin = get_player_skins(player) local skinval = mcl_skins.compile_skin(skin) if not skin.cape then skin.cape = "blank.png" end @@ -186,39 +230,7 @@ end -- Load player skin on join minetest.register_on_joinplayer(function(player) - local skin = player:get_meta():get_string("mcl_skins:skin") - if skin then - skin = minetest.deserialize(skin) - end - if skin then - if not mcl_skins.texture_to_simple_skin[skin.simple_skins_id] then - skin.simple_skins_id = nil - end - - mcl_skins.player_skins[player] = skin - else - if math.random() > 0.5 then - skin = table.copy(mcl_skins.template1) - else - skin = table.copy(mcl_skins.template2) - end - mcl_skins.player_skins[player] = skin - end - - mcl_skins.player_formspecs[player] = { - active_tab = "skin", - page_num = 1 - } - - if #mcl_skins.simple_skins > 0 then - local skin_id = tonumber(player:get_meta():get_string("mcl_skins:skin_id")) - if skin_id and mcl_skins.simple_skins[skin_id] then - local texture = mcl_skins.simple_skins[skin_id].texture - mcl_skins.player_skins[player].simple_skins_id = texture - end - end - mcl_skins.save(player) - mcl_skins.update_player_skin(player) + get_player_skins(player) end) minetest.register_on_leaveplayer(function(player) @@ -245,7 +257,7 @@ end function mcl_skins.show_formspec(player, active_tab, page_num) local formspec_data = mcl_skins.player_formspecs[player] - local skin = mcl_skins.player_skins[player] + local skin = get_player_skins(player) formspec_data.active_tab = active_tab local page_count = calculate_page_count(active_tab, player) @@ -555,7 +567,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) mcl_skins.show_formspec(player, active_tab, page_num) return true elseif fields.nocape then - mcl_skins.player_skins[player].cape = "blank.png" + local player_skins = get_player_skins(player) + player_skins.cape = "blank.png" mcl_skins.update_player_skin(player) mcl_armor.update(player) --update elytra cape mcl_skins.show_formspec(player, active_tab, page_num) @@ -564,7 +577,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) for cape_index = ((page_num - 1) * 5) + 1, math.min(#mcl_skins.cape, page_num * 5) do local cape = mcl_skins.cape[cape_index] if fields[cape.name] then - mcl_skins.player_skins[player].cape = cape.mask -- the actual overlay image + local player_skins = get_player_skins(player) + player_skins.cape = cape.mask -- the actual overlay image mcl_skins.update_player_skin(player) mcl_armor.update(player) --update elytra cape mcl_skins.show_formspec(player, active_tab, page_num) @@ -580,7 +594,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end - local skin = mcl_skins.player_skins[player] + local skin = get_player_skins(player) if not skin then return true end if fields.next_page then