Compare commits

...

7 Commits

Author SHA1 Message Date
teknomunk 25b04a7084 Fix another comment typo 2024-05-02 06:59:51 +00:00
teknomunk c0e553fb40 Fix typo in comment 2024-05-02 09:25:08 +00:00
teknomunk 7cd25616d5 Use mcl_util.use_item_durability to add wear to shears 2024-05-02 09:25:08 +00:00
teknomunk fb985a7ef3 Fix syntax error 2024-05-02 09:25:08 +00:00
teknomunk b916ea67b7 Add wear to shears used to harvest comb from a beehive, add comments 2024-05-02 09:25:08 +00:00
nixnoxus 3975449ad2 fix mcl_beds: ignore players in other dimensions than overwold (#4257)
beds ignore players in other dimensions than "overworld" (because players can only sleep in the "overworld")

Reviewed-on: https://git.minetest.land/MineClone2/MineClone2/pulls/4257
Reviewed-by: the-real-herowl <the-real-herowl@noreply.git.minetest.land>
Co-authored-by: nixnoxus <nixnoxus@web.de>
Co-committed-by: nixnoxus <nixnoxus@web.de>
2024-05-02 03:13:27 +00:00
teknomunk 6756658ee9 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 <the-real-herowl@noreply.git.minetest.land>
Co-authored-by: teknomunk <teknomunk@protonmail.com>
Co-committed-by: teknomunk <teknomunk@protonmail.com>
2024-05-02 03:01:43 +00:00
8 changed files with 217 additions and 126 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ local is_sp = minetest.is_singleplayer()
local weather_mod = minetest.get_modpath("mcl_weather")
local explosions_mod = minetest.get_modpath("mcl_explosions")
local spawn_mod = minetest.get_modpath("mcl_spawn")
local worlds_mod = minetest.get_modpath("mcl_worlds")
local pos_to_dim = minetest.get_modpath("mcl_worlds") and mcl_worlds.pos_to_dimension or function(pos) return "overworld" end
local function mcl_log (message)
mcl_util.mcl_log (message, "[Beds]")
@ -38,6 +38,16 @@ local function is_night_skip_enabled()
return players_in_bed_setting() <= 100
end
local function players_in_overworld(players)
local count = 0
for _, player in pairs(players) do
if player and pos_to_dim(player:get_pos()) == "overworld" then
count = count +1
end
end
return count
end
local function check_in_beds(players)
if not players then
players = minetest.get_connected_players()
@ -45,7 +55,7 @@ local function check_in_beds(players)
if player_in_bed <= 0 then
return false
end
return players_in_bed_setting() <= (player_in_bed * 100) / #players
return players_in_bed_setting() <= (player_in_bed * 100) / players_in_overworld(players)
end
-- These monsters do not prevent sleep
@ -206,10 +216,10 @@ local function lay_down(player, pos, bed_pos, state, skip)
return true
end
local function update_formspecs(finished, ges)
local ges = ges or #minetest.get_connected_players()
local function update_formspecs(finished, players)
local ges = players_in_overworld(players or minetest.get_connected_players())
local form_n = "size[12,5;true]"
local all_in_bed = players_in_bed_setting() <= (player_in_bed * 100) / ges
local all_in_bed = ges and players_in_bed_setting() <= (player_in_bed * 100) / ges or 0
local night_skip = is_night_skip_enabled()
local button_leave = "button_exit[4,3;4,0.75;leave;"..F(S("Leave bed")).."]"
local button_abort = "button_exit[4,3;4,0.75;leave;"..F(S("Abort sleep")).."]"
@ -349,25 +359,36 @@ function mcl_beds.get_bed_bottom (pos)
return bed_bottom
end
local function recheck_in_beds()
if check_in_beds() then
update_formspecs(is_night_skip_enabled())
mcl_beds.sleep()
end
-- check again (a player can change the dimension)
if player_in_bed > 0 then
update_formspecs(false)
minetest.after(5, recheck_in_beds)
end
end
function mcl_beds.on_rightclick(pos, player, is_top)
-- Anti-Inception: Don't allow to sleep while you're sleeping
if player:get_meta():get_string("mcl_beds:sleeping") == "true" then
return
end
if worlds_mod then
local dim = mcl_worlds.pos_to_dimension(pos)
if dim == "nether" or dim == "end" then
-- Bed goes BOOM in the Nether or End.
local node = minetest.get_node(pos)
local dir = minetest.facedir_to_dir(node.param2)
local dim = pos_to_dim(pos)
if dim == "nether" or dim == "end" then
-- Bed goes BOOM in the Nether or End.
local node = minetest.get_node(pos)
local dir = minetest.facedir_to_dir(node.param2)
minetest.remove_node(pos)
minetest.remove_node(string.sub(node.name, -4) == "_top" and vector.subtract(pos, dir) or vector.add(pos, dir))
if explosions_mod then
mcl_explosions.explode(pos, 5, {drop_chance = 1.0, fire = true})
end
return
minetest.remove_node(pos)
minetest.remove_node(string.sub(node.name, -4) == "_top" and vector.subtract(pos, dir) or vector.add(pos, dir))
if explosions_mod then
mcl_explosions.explode(pos, 5, {drop_chance = 1.0, fire = true})
end
return
end
local name = player:get_player_name()
local ppos = player:get_pos()
@ -385,10 +406,13 @@ function mcl_beds.on_rightclick(pos, player, is_top)
mcl_title.set(player, "actionbar", {text=message, color="white", stay=60})
else -- someone just successfully entered a bed
local connected_players = minetest.get_connected_players()
local sleep_hud_message = S("@1/@2 players currently in bed.", player_in_bed, math.ceil(players_in_bed_setting() * #connected_players / 100))
local ges = players_in_overworld(connected_players)
local sleep_hud_message = S("@1/@2 players currently in bed.", player_in_bed, math.ceil(players_in_bed_setting() * ges / 100))
for _, player in pairs(connected_players) do
if not mcl_beds.player[player:get_player_name()] then -- only send message to players not sleeping.
if mcl_title.params_get(player) then mcl_title.clear(player) end -- clear, old message is still being displayed
-- only send message to players not sleeping and in the "overworld"
if not mcl_beds.player[player:get_player_name()] and pos_to_dim(player:get_pos()) == "overworld" then
-- clear, old message is still being displayed
if mcl_title.params_get(player) then mcl_title.clear(player) end
mcl_title.set(player, "actionbar", {text=sleep_hud_message, color="white", stay=60})
end
end
@ -400,13 +424,8 @@ function mcl_beds.on_rightclick(pos, player, is_top)
update_formspecs(false)
-- skip the night and let all players stand up
if check_in_beds() then
minetest.after(5, function()
if check_in_beds() then
update_formspecs(is_night_skip_enabled())
mcl_beds.sleep()
end
end)
if player_in_bed > 0 then
minetest.after(5, recheck_in_beds)
end
end
@ -433,15 +452,10 @@ minetest.register_on_leaveplayer(function(player)
break
end
end
if check_in_beds(players) then
minetest.after(5, function()
if check_in_beds() then
update_formspecs(is_night_skip_enabled())
mcl_beds.sleep()
end
end)
if player_in_bed > 0 then
minetest.after(5, recheck_in_beds)
end
update_formspecs(false, #players)
update_formspecs(false, players)
end)
local message_rate_limit = tonumber(minetest.settings:get("chat_message_limit_per_10sec")) or 8 --NEVER change this! if this was java, i would've declared it as final

View File

@ -8,36 +8,60 @@ local S = minetest.get_translator(minetest.get_current_modname())
-- Function to allow harvesting honey and honeycomb from the beehive and bee nest.
local honey_harvest = function(pos, node, player, itemstack, pointed_thing)
local inv = player:get_inventory()
local shears = minetest.get_item_group(player:get_wielded_item():get_name(), "shears") > 0
local bottle = player:get_wielded_item():get_name() == "mcl_potions:glass_bottle"
local beehive = "mcl_beehives:beehive"
local item = player:get_wielded_item()
local is_creative = minetest.is_creative_enabled(player:get_player_name())
-- Determine the node name to replace the beehive with if harvest is successful
local beehive = "mcl_beehives:beehive"
if node.name == "mcl_beehives:beehive_5" then
beehive = "mcl_beehives:beehive"
elseif node.name == "mcl_beehives:bee_nest_5" then
beehive = "mcl_beehives:bee_nest"
end
-- Check for a campfire within 5 blocks below the beehive
local campfire_area = vector.offset(pos, 0, -5, 0)
local campfire = minetest.find_nodes_in_area(pos, campfire_area, "group:lit_campfire")
if bottle then
-- Player used a bottle
if item:get_name() == "mcl_potions:glass_bottle" then
local honey = "mcl_honey:honey_bottle"
if inv:room_for_item("main", honey) then
-- Replace the beehive with the version without honey or comb
node.name = beehive
minetest.set_node(pos, node)
-- Give honey bottle and take the empty bottle if survival mode
inv:add_item("main", "mcl_honey:honey_bottle")
if not is_creative then
itemstack:take_item()
end
if not campfire[1] then mcl_util.deal_damage(player, 10) else awards.unlock(player:get_player_name(), "mcl:bee_our_guest") end
-- Hurt the player if there was no campfire, or give award if there was
if not campfire[1] then
mcl_util.deal_damage(player, 10)
else
awards.unlock(player:get_player_name(), "mcl:bee_our_guest")
end
end
elseif shears then
-- Player used shears
elseif minetest.get_item_group(item:get_name(), "shears") > 0 then
-- Give honeycomb
minetest.add_item(pos, "mcl_honey:honeycomb 3")
-- Replace the beehive with the version without honey or comb
node.name = beehive
minetest.set_node(pos, node)
-- Hurt the player if there was no campfire
if not campfire[1] then mcl_util.deal_damage(player, 10) end
-- Add wear to the shears
if not is_creative then
mcl_util.use_item_durability(item, 1)
return item
end
end
end

View File

@ -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 <https://minecraft.gamepedia.com/Options#Video_settings>>>>

View File

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