Added a return code to load_maps

Added a return code to load_maps to check for if dynamic_add_media registers a fail.
Used by mcl_itemframes when reloading a map placed into an itemframe.
This commit is contained in:
Michieal 2022-11-01 00:57:04 +00:00 committed by cora
parent 1f5b92f7bf
commit 6d1b1b3c74
1 changed files with 283 additions and 267 deletions

View File

@ -22,11 +22,14 @@ local map_textures_path = worldpath .. "/mcl_maps/"
minetest.mkdir(map_textures_path) minetest.mkdir(map_textures_path)
-- overwrite the builtin tga_encoder
dofile(modpath .. "/tga_encoder_init.lua")
local function load_json_file(name) local function load_json_file(name)
local file = assert(io.open(modpath .. "/" .. name .. ".json", "r")) local file = assert(io.open(modpath .. "/" .. name .. ".json", "r"))
local data = minetest.parse_json(file:read()) local data = minetest.parse_json(file:read())
file:close() file:close()
return data return data
end end
local texture_colors = load_json_file("colors") local texture_colors = load_json_file("colors")
@ -40,180 +43,193 @@ local loaded_maps = {}
local c_air = minetest.get_content_id("air") local c_air = minetest.get_content_id("air")
function mcl_maps.create_map(pos) function mcl_maps.create_map(pos)
local minp = vector.multiply(vector.floor(vector.divide(pos, 128)), 128) local minp = vector.multiply(vector.floor(vector.divide(pos, 128)), 128)
local maxp = vector.add(minp, vector.new(127, 127, 127)) local maxp = vector.add(minp, vector.new(127, 127, 127))
local itemstack = ItemStack("mcl_maps:filled_map") local itemstack = ItemStack("mcl_maps:filled_map")
local meta = itemstack:get_meta() local meta = itemstack:get_meta()
local next_id = storage:get_int("next_id") local next_id = storage:get_int("next_id")
storage:set_int("next_id", next_id + 1) storage:set_int("next_id", next_id + 1)
local id = tostring(next_id) local id = tostring(next_id)
meta:set_string("mcl_maps:id", id) meta:set_string("mcl_maps:id", id)
meta:set_string("mcl_maps:minp", pos_to_string(minp)) meta:set_string("mcl_maps:minp", pos_to_string(minp))
meta:set_string("mcl_maps:maxp", pos_to_string(maxp)) meta:set_string("mcl_maps:maxp", pos_to_string(maxp))
tt.reload_itemstack_description(itemstack) tt.reload_itemstack_description(itemstack)
creating_maps[id] = true creating_maps[id] = true
minetest.emerge_area(minp, maxp, function(blockpos, action, calls_remaining) minetest.emerge_area(minp, maxp, function(blockpos, action, calls_remaining)
if calls_remaining > 0 then if calls_remaining > 0 then
return return
end end
local vm = minetest.get_voxel_manip() local vm = minetest.get_voxel_manip()
local emin, emax = vm:read_from_map(minp, maxp) local emin, emax = vm:read_from_map(minp, maxp)
local data = vm:get_data() local data = vm:get_data()
local param2data = vm:get_param2_data() local param2data = vm:get_param2_data()
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax}) local area = VoxelArea:new({ MinEdge = emin, MaxEdge = emax })
local pixels = {} local pixels = {}
local last_heightmap local last_heightmap
for x = 1, 128 do for x = 1, 128 do
local map_x = minp.x - 1 + x local map_x = minp.x - 1 + x
local heightmap = {} local heightmap = {}
for z = 1, 128 do for z = 1, 128 do
local map_z = minp.z - 1 + z local map_z = minp.z - 1 + z
local color, height local color, height
for map_y = maxp.y, minp.y, -1 do for map_y = maxp.y, minp.y, -1 do
local index = area:index(map_x, map_y, map_z) local index = area:index(map_x, map_y, map_z)
local c_id = data[index] local c_id = data[index]
if c_id ~= c_air then if c_id ~= c_air then
color = color_cache[c_id] color = color_cache[c_id]
if color == nil then if color == nil then
local nodename = minetest.get_name_from_content_id(c_id) local nodename = minetest.get_name_from_content_id(c_id)
local def = minetest.registered_nodes[nodename] local def = minetest.registered_nodes[nodename]
if def then if def then
local texture local texture
if def.palette then if def.palette then
texture = def.palette texture = def.palette
elseif def.tiles then elseif def.tiles then
texture = def.tiles[1] texture = def.tiles[1]
if type(texture) == "table" then if type(texture) == "table" then
texture = texture.name texture = texture.name
end end
end end
if texture then if texture then
texture = texture:match("([^=^%^]-([^.]+))$"):split("^")[1] texture = texture:match("([^=^%^]-([^.]+))$"):split("^")[1]
end end
if def.palette then if def.palette then
local palette = palettes[texture] local palette = palettes[texture]
color = palette and {palette = palette} color = palette and { palette = palette }
else else
color = texture_colors[texture] color = texture_colors[texture]
end end
end end
end end
if color and color.palette then if color and color.palette then
color = color.palette[param2data[index] + 1] color = color.palette[param2data[index] + 1]
else else
color_cache[c_id] = color or false color_cache[c_id] = color or false
end end
if color and last_heightmap then if color and last_heightmap then
local last_height = last_heightmap[z] local last_height = last_heightmap[z]
if last_height < map_y then if last_height < map_y then
color = { color = {
math.min(255, color[1] + 16), math.min(255, color[1] + 16),
math.min(255, color[2] + 16), math.min(255, color[2] + 16),
math.min(255, color[3] + 16), math.min(255, color[3] + 16),
} }
elseif last_height > map_y then elseif last_height > map_y then
color = { color = {
math.max(0, color[1] - 16), math.max(0, color[1] - 16),
math.max(0, color[2] - 16), math.max(0, color[2] - 16),
math.max(0, color[3] - 16), math.max(0, color[3] - 16),
} }
end end
end end
height = map_y height = map_y
break break
end end
end end
heightmap[z] = height or minp.y heightmap[z] = height or minp.y
pixels[z] = pixels[z] or {} pixels[z] = pixels[z] or {}
pixels[z][x] = color or {0, 0, 0} pixels[z][x] = color or { 0, 0, 0 }
end end
last_heightmap = heightmap last_heightmap = heightmap
end end
tga_encoder.image(pixels):save(map_textures_path .. "mcl_maps_map_texture_" .. id .. ".tga") tga_encoder.image(pixels):save(map_textures_path .. "mcl_maps_map_texture_" .. id .. ".tga")
creating_maps[id] = nil creating_maps[id] = nil
end) end)
return itemstack return itemstack
end end
function mcl_maps.load_map(id, callback) function mcl_maps.load_map(id, callback)
if id == "" or creating_maps[id] then if id == "" or creating_maps[id] then
return return false
end end
local texture = "mcl_maps_map_texture_" .. id .. ".tga" local texture = "mcl_maps_map_texture_" .. id .. ".tga"
if not loaded_maps[id] then local result = true
if not minetest.features.dynamic_add_media_table then
-- minetest.dynamic_add_media() blocks in
-- Minetest 5.3 and 5.4 until media loads
loaded_maps[id] = true
dynamic_add_media(map_textures_path .. texture, function() end)
if callback then callback(texture) end
else
-- minetest.dynamic_add_media() never blocks
-- in Minetest 5.5, callback runs after load
dynamic_add_media(map_textures_path .. texture, function()
loaded_maps[id] = true
if callback then callback(texture) end
end)
end
end
if loaded_maps[id] then if not loaded_maps[id] then
if callback then callback(texture) end if not minetest.features.dynamic_add_media_table then
return texture -- minetest.dynamic_add_media() blocks in
end -- Minetest 5.3 and 5.4 until media loads
loaded_maps[id] = true
result = dynamic_add_media(map_textures_path .. texture, function()
end)
if callback then
callback(texture)
end
else
-- minetest.dynamic_add_media() never blocks
-- in Minetest 5.5, callback runs after load
result = dynamic_add_media(map_textures_path .. texture, function()
loaded_maps[id] = true
if callback then
callback(texture)
end
end)
end
end
if result == false then
return false
end
if loaded_maps[id] then
if callback then
callback(texture)
end
return texture
end
end end
function mcl_maps.load_map_item(itemstack) function mcl_maps.load_map_item(itemstack)
return mcl_maps.load_map(itemstack:get_meta():get_string("mcl_maps:id")) return mcl_maps.load_map(itemstack:get_meta():get_string("mcl_maps:id"))
end end
local function fill_map(itemstack, placer, pointed_thing) local function fill_map(itemstack, placer, pointed_thing)
local new_stack = mcl_util.call_on_rightclick(itemstack, placer, pointed_thing) local new_stack = mcl_util.call_on_rightclick(itemstack, placer, pointed_thing)
if new_stack then if new_stack then
return new_stack return new_stack
end end
if minetest.settings:get_bool("enable_real_maps", true) then if minetest.settings:get_bool("enable_real_maps", true) then
local new_map = mcl_maps.create_map(placer:get_pos()) local new_map = mcl_maps.create_map(placer:get_pos())
itemstack:take_item() itemstack:take_item()
if itemstack:is_empty() then if itemstack:is_empty() then
return new_map return new_map
else else
local inv = placer:get_inventory() local inv = placer:get_inventory()
if inv:room_for_item("main", new_map) then if inv:room_for_item("main", new_map) then
inv:add_item("main", new_map) inv:add_item("main", new_map)
else else
minetest.add_item(placer:get_pos(), new_map) minetest.add_item(placer:get_pos(), new_map)
end end
return itemstack return itemstack
end end
end end
end end
minetest.register_craftitem("mcl_maps:empty_map", { minetest.register_craftitem("mcl_maps:empty_map", {
description = S("Empty Map"), description = S("Empty Map"),
_doc_items_longdesc = S("Empty maps are not useful as maps, but they can be stacked and turned to maps which can be used."), _doc_items_longdesc = S("Empty maps are not useful as maps, but they can be stacked and turned to maps which can be used."),
_doc_items_usagehelp = S("Rightclick to create a filled map (which can't be stacked anymore)."), _doc_items_usagehelp = S("Rightclick to create a filled map (which can't be stacked anymore)."),
inventory_image = "mcl_maps_map_empty.png", inventory_image = "mcl_maps_map_empty.png",
on_place = fill_map, on_place = fill_map,
on_secondary_use = fill_map, on_secondary_use = fill_map,
stack_max = 64, stack_max = 64,
}) })
local filled_def = { local filled_def = {
description = S("Map"), description = S("Map"),
_tt_help = S("Shows a map image."), _tt_help = S("Shows a map image."),
_doc_items_longdesc = S("When created, the map saves the nearby area as an image that can be viewed any time by holding the map."), _doc_items_longdesc = S("When created, the map saves the nearby area as an image that can be viewed any time by holding the map."),
_doc_items_usagehelp = S("Hold the map in your hand. This will display a map on your screen."), _doc_items_usagehelp = S("Hold the map in your hand. This will display a map on your screen."),
inventory_image = "mcl_maps_map_filled.png^(mcl_maps_map_filled_markings.png^[colorize:#000000)", inventory_image = "mcl_maps_map_filled.png^(mcl_maps_map_filled_markings.png^[colorize:#000000)",
stack_max = 64, stack_max = 64,
groups = {not_in_creative_inventory = 1, filled_map = 1, tool = 1}, groups = { not_in_creative_inventory = 1, filled_map = 1, tool = 1 },
} }
minetest.register_craftitem("mcl_maps:filled_map", filled_def) minetest.register_craftitem("mcl_maps:filled_map", filled_def)
@ -221,7 +237,7 @@ minetest.register_craftitem("mcl_maps:filled_map", filled_def)
local filled_wield_def = table.copy(filled_def) local filled_wield_def = table.copy(filled_def)
filled_wield_def.use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false filled_wield_def.use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false
filled_wield_def.visual_scale = 1 filled_wield_def.visual_scale = 1
filled_wield_def.wield_scale = {x = 1, y = 1, z = 1} filled_wield_def.wield_scale = { x = 1, y = 1, z = 1 }
filled_wield_def.paramtype = "light" filled_wield_def.paramtype = "light"
filled_wield_def.drawtype = "mesh" filled_wield_def.drawtype = "mesh"
filled_wield_def.node_placement_prediction = "" filled_wield_def.node_placement_prediction = ""
@ -232,72 +248,72 @@ filled_wield_def._mcl_wieldview_item = "mcl_maps:filled_map"
local mcl_skins_enabled = minetest.global_exists("mcl_skins") local mcl_skins_enabled = minetest.global_exists("mcl_skins")
if mcl_skins_enabled then if mcl_skins_enabled then
-- Generate a node for every skin -- Generate a node for every skin
local list = mcl_skins.get_skin_list() local list = mcl_skins.get_skin_list()
for _, skin in pairs(list) do for _, skin in pairs(list) do
if skin.slim_arms then if skin.slim_arms then
local female = table.copy(filled_wield_def) local female = table.copy(filled_wield_def)
female._mcl_hand_id = skin.id female._mcl_hand_id = skin.id
female.mesh = "mcl_meshhand_female.b3d" female.mesh = "mcl_meshhand_female.b3d"
female.tiles = {skin.texture} female.tiles = { skin.texture }
minetest.register_node("mcl_maps:filled_map_" .. skin.id, female) minetest.register_node("mcl_maps:filled_map_" .. skin.id, female)
else else
local male = table.copy(filled_wield_def) local male = table.copy(filled_wield_def)
male._mcl_hand_id = skin.id male._mcl_hand_id = skin.id
male.mesh = "mcl_meshhand.b3d" male.mesh = "mcl_meshhand.b3d"
male.tiles = {skin.texture} male.tiles = { skin.texture }
minetest.register_node("mcl_maps:filled_map_" .. skin.id, male) minetest.register_node("mcl_maps:filled_map_" .. skin.id, male)
end end
end end
else else
filled_wield_def._mcl_hand_id = "hand" filled_wield_def._mcl_hand_id = "hand"
filled_wield_def.mesh = "mcl_meshhand.b3d" filled_wield_def.mesh = "mcl_meshhand.b3d"
filled_wield_def.tiles = {"character.png"} filled_wield_def.tiles = { "character.png" }
minetest.register_node("mcl_maps:filled_map_hand", filled_wield_def) minetest.register_node("mcl_maps:filled_map_hand", filled_wield_def)
end end
local old_add_item = minetest.add_item local old_add_item = minetest.add_item
function minetest.add_item(pos, stack) function minetest.add_item(pos, stack)
stack = ItemStack(stack) stack = ItemStack(stack)
if get_item_group(stack:get_name(), "filled_map") > 0 then if get_item_group(stack:get_name(), "filled_map") > 0 then
stack:set_name("mcl_maps:filled_map") stack:set_name("mcl_maps:filled_map")
end end
return old_add_item(pos, stack) return old_add_item(pos, stack)
end end
tt.register_priority_snippet(function(itemstring, _, itemstack) tt.register_priority_snippet(function(itemstring, _, itemstack)
if itemstack and get_item_group(itemstring, "filled_map") > 0 then if itemstack and get_item_group(itemstring, "filled_map") > 0 then
local id = itemstack:get_meta():get_string("mcl_maps:id") local id = itemstack:get_meta():get_string("mcl_maps:id")
if id ~= "" then if id ~= "" then
return "#" .. id, mcl_colors.GRAY return "#" .. id, mcl_colors.GRAY
end end
end end
end) end)
minetest.register_craft({ minetest.register_craft({
output = "mcl_maps:empty_map", output = "mcl_maps:empty_map",
recipe = { recipe = {
{ "mcl_core:paper", "mcl_core:paper", "mcl_core:paper" }, { "mcl_core:paper", "mcl_core:paper", "mcl_core:paper" },
{ "mcl_core:paper", "group:compass", "mcl_core:paper" }, { "mcl_core:paper", "group:compass", "mcl_core:paper" },
{ "mcl_core:paper", "mcl_core:paper", "mcl_core:paper" }, { "mcl_core:paper", "mcl_core:paper", "mcl_core:paper" },
} }
}) })
minetest.register_craft({ minetest.register_craft({
type = "shapeless", type = "shapeless",
output = "mcl_maps:filled_map 2", output = "mcl_maps:filled_map 2",
recipe = {"group:filled_map", "mcl_maps:empty_map"}, recipe = { "group:filled_map", "mcl_maps:empty_map" },
}) })
local function on_craft(itemstack, player, old_craft_grid, craft_inv) local function on_craft(itemstack, player, old_craft_grid, craft_inv)
if itemstack:get_name() == "mcl_maps:filled_map" then if itemstack:get_name() == "mcl_maps:filled_map" then
for _, stack in pairs(old_craft_grid) do for _, stack in pairs(old_craft_grid) do
if get_item_group(stack:get_name(), "filled_map") > 0 then if get_item_group(stack:get_name(), "filled_map") > 0 then
itemstack:get_meta():from_table(stack:get_meta():to_table()) itemstack:get_meta():from_table(stack:get_meta():to_table())
return itemstack return itemstack
end end
end end
end end
end end
minetest.register_on_craft(on_craft) minetest.register_on_craft(on_craft)
@ -307,80 +323,80 @@ local maps = {}
local huds = {} local huds = {}
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
local map_def = { local map_def = {
hud_elem_type = "image", hud_elem_type = "image",
text = "blank.png", text = "blank.png",
position = {x = 0.75, y = 0.8}, position = { x = 0.75, y = 0.8 },
alignment = {x = 0, y = -1}, alignment = { x = 0, y = -1 },
offset = {x = 0, y = 0}, offset = { x = 0, y = 0 },
scale = {x = 2, y = 2}, scale = { x = 2, y = 2 },
} }
local marker_def = table.copy(map_def) local marker_def = table.copy(map_def)
marker_def.alignment = {x = 0, y = 0} marker_def.alignment = { x = 0, y = 0 }
huds[player] = { huds[player] = {
map = player:hud_add(map_def), map = player:hud_add(map_def),
marker = player:hud_add(marker_def), marker = player:hud_add(marker_def),
} }
end) end)
minetest.register_on_leaveplayer(function(player) minetest.register_on_leaveplayer(function(player)
maps[player] = nil maps[player] = nil
huds[player] = nil huds[player] = nil
end) end)
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
for _, player in pairs(get_connected_players()) do for _, player in pairs(get_connected_players()) do
local wield = player:get_wielded_item() local wield = player:get_wielded_item()
local texture = mcl_maps.load_map_item(wield) local texture = mcl_maps.load_map_item(wield)
local hud = huds[player] local hud = huds[player]
if texture then if texture then
local wield_def = wield:get_definition() local wield_def = wield:get_definition()
local hand_def = player:get_inventory():get_stack("hand", 1):get_definition() local hand_def = player:get_inventory():get_stack("hand", 1):get_definition()
if hand_def and wield_def and hand_def._mcl_hand_id ~= wield_def._mcl_hand_id then if hand_def and wield_def and hand_def._mcl_hand_id ~= wield_def._mcl_hand_id then
wield:set_name("mcl_maps:filled_map_" .. hand_def._mcl_hand_id) wield:set_name("mcl_maps:filled_map_" .. hand_def._mcl_hand_id)
player:set_wielded_item(wield) player:set_wielded_item(wield)
end end
if texture ~= maps[player] then if texture ~= maps[player] then
player:hud_change(hud.map, "text", "[combine:140x140:0,0=mcl_maps_map_background.png:6,6=" .. texture) player:hud_change(hud.map, "text", "[combine:140x140:0,0=mcl_maps_map_background.png:6,6=" .. texture)
maps[player] = texture maps[player] = texture
end end
local pos = vector.round(player:get_pos()) local pos = vector.round(player:get_pos())
local meta = wield:get_meta() local meta = wield:get_meta()
local minp = string_to_pos(meta:get_string("mcl_maps:minp")) local minp = string_to_pos(meta:get_string("mcl_maps:minp"))
local maxp = string_to_pos(meta:get_string("mcl_maps:maxp")) local maxp = string_to_pos(meta:get_string("mcl_maps:maxp"))
local marker = "mcl_maps_player_arrow.png" local marker = "mcl_maps_player_arrow.png"
if pos.x < minp.x then if pos.x < minp.x then
marker = "mcl_maps_player_dot.png" marker = "mcl_maps_player_dot.png"
pos.x = minp.x pos.x = minp.x
elseif pos.x > maxp.x then elseif pos.x > maxp.x then
marker = "mcl_maps_player_dot.png" marker = "mcl_maps_player_dot.png"
pos.x = maxp.x pos.x = maxp.x
end end
if pos.z < minp.z then if pos.z < minp.z then
marker = "mcl_maps_player_dot.png" marker = "mcl_maps_player_dot.png"
pos.z = minp.z pos.z = minp.z
elseif pos.z > maxp.z then elseif pos.z > maxp.z then
marker = "mcl_maps_player_dot.png" marker = "mcl_maps_player_dot.png"
pos.z = maxp.z pos.z = maxp.z
end end
if marker == "mcl_maps_player_arrow.png" then if marker == "mcl_maps_player_arrow.png" then
local yaw = (math.floor(player:get_look_horizontal() * 180 / math.pi / 90 + 0.5) % 4) * 90 local yaw = (math.floor(player:get_look_horizontal() * 180 / math.pi / 90 + 0.5) % 4) * 90
marker = marker .. "^[transformR" .. yaw marker = marker .. "^[transformR" .. yaw
end end
player:hud_change(hud.marker, "text", marker) player:hud_change(hud.marker, "text", marker)
player:hud_change(hud.marker, "offset", {x = (6 - 140 / 2 + pos.x - minp.x) * 2, y = (6 - 140 + maxp.z - pos.z) * 2}) player:hud_change(hud.marker, "offset", { x = (6 - 140 / 2 + pos.x - minp.x) * 2, y = (6 - 140 + maxp.z - pos.z) * 2 })
elseif maps[player] then elseif maps[player] then
player:hud_change(hud.map, "text", "blank.png") player:hud_change(hud.map, "text", "blank.png")
player:hud_change(hud.marker, "text", "blank.png") player:hud_change(hud.marker, "text", "blank.png")
maps[player] = nil maps[player] = nil
end end
end end
end) end)