Fix dynamic media race condition
Wait for *all* players to receive the texture before using it. Previously this would wait for *any* player to receive the texture. This works fine in singleplayer (or on pre-5.5, where dynamic_add_media would block until all players have received the texture), but it may fail otherwise: Either entity textures won't be available in time, or, even worse, the HUD texture is unavailable. Both produce an error in chat for clients.
This commit is contained in:
parent
4fa5c94515
commit
df5bd3c4ec
|
@ -0,0 +1,63 @@
|
|||
local on_leaves = {} -- functions(name)
|
||||
local timeout = 5 -- seconds
|
||||
xmaps.dynamic_add_media_all = function(path, on_all_received)
|
||||
if not minetest.features.dynamic_add_media_table then
|
||||
-- minetest.dynamic_add_media() blocks in
|
||||
-- Minetest 5.3 and 5.4 until media loads
|
||||
minetest.dynamic_add_media(path, function() end)
|
||||
on_all_received()
|
||||
return
|
||||
end
|
||||
-- minetest.dynamic_add_media() never blocks
|
||||
-- in Minetest 5.5, callback runs *for each client*
|
||||
-- who has received & loaded the media
|
||||
-- all players currently online must still receive it
|
||||
local to_receive = {}
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
local name = player:get_player_name()
|
||||
-- Only clients with protocol version >= 39 can receive dynamic media.
|
||||
if minetest.get_player_information(name).protocol_version >= 39 then
|
||||
to_receive[name] = true
|
||||
end
|
||||
end
|
||||
local function remove_to_receive(name)
|
||||
to_receive[name] = nil
|
||||
if next(to_receive) == nil then
|
||||
on_leaves[remove_to_receive] = nil
|
||||
on_all_received()
|
||||
end
|
||||
end
|
||||
on_leaves[remove_to_receive] = true
|
||||
minetest.dynamic_add_media(
|
||||
{filepath = path},
|
||||
function(name)
|
||||
assert(name)
|
||||
if not to_receive[name] then
|
||||
minetest.log("warning", ("xmaps: %s received media despite not being connected"):format(name))
|
||||
return
|
||||
end
|
||||
remove_to_receive(name)
|
||||
end
|
||||
)
|
||||
minetest.after(timeout, function()
|
||||
if next(to_receive) ~= nil then
|
||||
local names = {}
|
||||
for name in pairs(to_receive) do
|
||||
table.insert(names, name)
|
||||
end
|
||||
table.sort(names)
|
||||
minetest.log("warning", ("xmaps: sending media to %s timed out"):format(table.concat(names, ", ")))
|
||||
end
|
||||
on_leaves[remove_to_receive] = nil
|
||||
on_all_received()
|
||||
end)
|
||||
end
|
||||
|
||||
minetest.register_on_leaveplayer(
|
||||
function(player)
|
||||
local player_name = player:get_player_name()
|
||||
for on_leave in pairs(on_leaves) do
|
||||
on_leave(player_name)
|
||||
end
|
||||
end
|
||||
)
|
22
init.lua
22
init.lua
|
@ -48,6 +48,8 @@ end
|
|||
|
||||
xmaps = {}
|
||||
|
||||
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/dynamic_add_media_all.lua")
|
||||
|
||||
xmaps.dark = {} -- key: player name; value: is it dark?
|
||||
xmaps.huds = {} -- key: player name; value: player huds
|
||||
xmaps.maps = {} -- key: player name; value: map texture
|
||||
|
@ -393,26 +395,12 @@ xmaps.load_map = function(map_id)
|
|||
end
|
||||
|
||||
local filename = xmaps.get_map_filename(map_id)
|
||||
local path = textures_dir .. filename
|
||||
|
||||
if not xmaps.sent[map_id] then
|
||||
if not minetest.features.dynamic_add_media_table then
|
||||
-- minetest.dynamic_add_media() blocks in
|
||||
-- Minetest 5.3 and 5.4 until media loads
|
||||
minetest.dynamic_add_media(
|
||||
textures_dir .. filename,
|
||||
function() end
|
||||
)
|
||||
xmaps.dynamic_add_media_all(path, function()
|
||||
xmaps.load[map_id] = true
|
||||
else
|
||||
-- minetest.dynamic_add_media() never blocks
|
||||
-- in Minetest 5.5, callback runs after load
|
||||
minetest.dynamic_add_media(
|
||||
textures_dir .. filename,
|
||||
function()
|
||||
xmaps.load[map_id] = true
|
||||
end
|
||||
)
|
||||
end
|
||||
end)
|
||||
xmaps.sent[map_id] = true
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue