Add wieldable maps (like mcl_maps)
This commit is contained in:
parent
67c75b061c
commit
ead238c376
|
@ -25,3 +25,25 @@ local pixels = {
|
||||||
{ K, K, K, K, K, K, _ },
|
{ K, K, K, K, K, K, _ },
|
||||||
}
|
}
|
||||||
tga_encoder.image(pixels):save("textures/maps_arrow_diagonal.tga")
|
tga_encoder.image(pixels):save("textures/maps_arrow_diagonal.tga")
|
||||||
|
|
||||||
|
local pixels = {
|
||||||
|
{ _, _, K, K, K, _, _ },
|
||||||
|
{ _, K, W, W, W, K, _ },
|
||||||
|
{ K, W, W, W, W, W, K },
|
||||||
|
{ K, W, W, W, W, W, K },
|
||||||
|
{ K, W, W, W, W, W, K },
|
||||||
|
{ _, K, W, W, W, K, _ },
|
||||||
|
{ _, _, K, K, K, _, _ },
|
||||||
|
}
|
||||||
|
tga_encoder.image(pixels):save("textures/maps_dot_large.tga")
|
||||||
|
|
||||||
|
local pixels = {
|
||||||
|
{ _, _, _, _, _, _, _ },
|
||||||
|
{ _, _, K, K, K, _, _ },
|
||||||
|
{ _, K, W, W, W, K, _ },
|
||||||
|
{ _, K, W, W, W, K, _ },
|
||||||
|
{ _, K, W, W, W, K, _ },
|
||||||
|
{ _, _, K, K, K, _, _ },
|
||||||
|
{ _, _, _, _, _, _, _ },
|
||||||
|
}
|
||||||
|
tga_encoder.image(pixels):save("textures/maps_dot_small.tga")
|
||||||
|
|
433
init.lua
433
init.lua
|
@ -47,14 +47,17 @@ function tga_encoder.image:blit_icon(icon, pos, stop_colors)
|
||||||
end
|
end
|
||||||
|
|
||||||
maps = {}
|
maps = {}
|
||||||
maps.dots = {}
|
|
||||||
maps.maps = {}
|
maps.dark = {} -- key: player name; value: is it dark?
|
||||||
maps.minp = {}
|
maps.huds = {} -- key: player name; value: player huds
|
||||||
maps.maxp = {}
|
maps.maps = {} -- key: player name; value: map texture
|
||||||
maps.work = {}
|
maps.mark = {} -- key: player name; value: marker texture
|
||||||
maps.sent = {}
|
maps.marx = {} -- key: player name; value: marker x offset
|
||||||
maps.posx = {}
|
maps.mary = {} -- key: player name; value: marker y offset
|
||||||
maps.posz = {}
|
|
||||||
|
maps.load = {} -- maps loaded by players
|
||||||
|
maps.sent = {} -- maps sent to players
|
||||||
|
maps.work = {} -- maps being created
|
||||||
|
|
||||||
local size = 80
|
local size = 80
|
||||||
|
|
||||||
|
@ -62,41 +65,29 @@ local worldpath = minetest.get_worldpath()
|
||||||
local textures_dir = worldpath .. "/maps/"
|
local textures_dir = worldpath .. "/maps/"
|
||||||
minetest.mkdir(textures_dir)
|
minetest.mkdir(textures_dir)
|
||||||
|
|
||||||
maps.create_map = function(pos, player_name)
|
maps.get_map_filename = function(map_id)
|
||||||
|
return "maps_map_texture_" .. map_id .. ".tga"
|
||||||
|
end
|
||||||
|
|
||||||
|
maps.create_map = function(pos)
|
||||||
|
local itemstack = ItemStack("maps:map")
|
||||||
|
local meta = itemstack:get_meta()
|
||||||
|
|
||||||
|
local map_id = tostring(os.time() + math.random())
|
||||||
|
meta:set_string("maps:id", map_id)
|
||||||
|
|
||||||
local minp = vector.multiply(vector.floor(vector.divide(pos, size)), size)
|
local minp = vector.multiply(vector.floor(vector.divide(pos, size)), size)
|
||||||
|
meta:set_string("maps:minp", minetest.pos_to_string(minp))
|
||||||
|
|
||||||
local maxp = vector.add(minp, vector.new(size - 1, size - 1, size - 1))
|
local maxp = vector.add(minp, vector.new(size - 1, size - 1, size - 1))
|
||||||
|
meta:set_string("maps:maxp", minetest.pos_to_string(maxp))
|
||||||
|
|
||||||
local prefix, _ = minetest.pos_to_string(maxp)
|
local xpos = vector.round(pos)
|
||||||
prefix, _ = prefix:gsub("%(", "")
|
meta:set_string("maps:xpos", minetest.pos_to_string(xpos))
|
||||||
prefix, _ = prefix:gsub("%)", "")
|
|
||||||
prefix, _ = prefix:gsub(",", "_")
|
|
||||||
local filename = prefix .. ".tga"
|
|
||||||
|
|
||||||
if maps.work[filename] then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local player = minetest.get_player_by_name(player_name)
|
|
||||||
|
|
||||||
if maps.sent[filename] then
|
|
||||||
maps.minp[player_name] = minp
|
|
||||||
maps.maxp[player_name] = maxp
|
|
||||||
player:hud_change(
|
|
||||||
maps.maps[player_name],
|
|
||||||
"text",
|
|
||||||
filename
|
|
||||||
)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
|
local filename = maps.get_map_filename(map_id)
|
||||||
maps.work[filename] = true
|
maps.work[filename] = true
|
||||||
|
|
||||||
player:hud_change(
|
|
||||||
maps.maps[player_name],
|
|
||||||
"text",
|
|
||||||
"blank.png"
|
|
||||||
)
|
|
||||||
|
|
||||||
local emerge_callback = function(
|
local emerge_callback = function(
|
||||||
blockpos,
|
blockpos,
|
||||||
action,
|
action,
|
||||||
|
@ -377,29 +368,173 @@ maps.create_map = function(pos, player_name)
|
||||||
filepath,
|
filepath,
|
||||||
{ colormap=colormap }
|
{ colormap=colormap }
|
||||||
)
|
)
|
||||||
|
|
||||||
minetest.dynamic_add_media(
|
|
||||||
filepath,
|
|
||||||
function()
|
|
||||||
local player =minetest.get_player_by_name(player_name)
|
|
||||||
player:hud_change(
|
|
||||||
maps.maps[player_name],
|
|
||||||
"text",
|
|
||||||
filename
|
|
||||||
)
|
|
||||||
maps.minp[player_name] = minp
|
|
||||||
maps.maxp[player_name] = maxp
|
|
||||||
maps.sent[filename] = true
|
|
||||||
maps.work[filename] = false
|
maps.work[filename] = false
|
||||||
end
|
end
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.emerge_area(
|
minetest.emerge_area(
|
||||||
minp,
|
minp,
|
||||||
maxp,
|
maxp,
|
||||||
emerge_callback
|
emerge_callback
|
||||||
)
|
)
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
maps.load_map = function(map_id)
|
||||||
|
assert( nil ~= map_id )
|
||||||
|
if (
|
||||||
|
"" == map_id or
|
||||||
|
maps.work[map_id]
|
||||||
|
) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local filename = maps.get_map_filename(map_id)
|
||||||
|
|
||||||
|
if not maps.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
|
||||||
|
)
|
||||||
|
maps.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()
|
||||||
|
maps.load[map_id] = true
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
maps.sent[map_id] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if maps.load[map_id] then
|
||||||
|
return filename
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
maps.encode_map_item_meta = function(input)
|
||||||
|
return minetest.encode_base64(
|
||||||
|
minetest.compress(
|
||||||
|
input,
|
||||||
|
"deflate",
|
||||||
|
9
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
maps.decode_map_item_meta = function(input)
|
||||||
|
return minetest.decompress(
|
||||||
|
minetest.decode_base64(input),
|
||||||
|
"deflate",
|
||||||
|
9
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
result_original = "foo\0\01\02\x03\n\rbar"
|
||||||
|
result_roundtrip = maps.decode_map_item_meta(
|
||||||
|
maps.encode_map_item_meta(result_original)
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
result_original == result_roundtrip,
|
||||||
|
"maps: mismatch between maps.encode_map_item_meta() and maps.decode_map_item_meta()"
|
||||||
|
)
|
||||||
|
|
||||||
|
maps.load_map_item = function(itemstack)
|
||||||
|
local meta = itemstack:get_meta()
|
||||||
|
local map_id = meta:get_string("maps:id")
|
||||||
|
|
||||||
|
if (
|
||||||
|
not map_id or
|
||||||
|
"" == map_id or
|
||||||
|
maps.work[map_id]
|
||||||
|
) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if maps.load[map_id] then
|
||||||
|
return maps.load_map(map_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
local texture_file_name = maps.get_map_filename(map_id)
|
||||||
|
local texture_file_path = textures_dir .. texture_file_name
|
||||||
|
|
||||||
|
-- does the texture file exist?
|
||||||
|
local texture_file_handle_read = io.open(
|
||||||
|
texture_file_path,
|
||||||
|
"rb"
|
||||||
|
)
|
||||||
|
local texture_file_exists = true
|
||||||
|
local texture_data_from_file
|
||||||
|
if nil == texture_file_handle_read then
|
||||||
|
texture_file_exists = false
|
||||||
|
else
|
||||||
|
texture_data_from_file = texture_file_handle_read:read("*a")
|
||||||
|
texture_file_handle_read:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- does the texture item meta exist?
|
||||||
|
local tga_deflate_base64 = meta:get_string("maps:tga_deflate_base64")
|
||||||
|
local texture_item_meta_exists = true
|
||||||
|
if "" == tga_deflate_base64 then
|
||||||
|
texture_item_meta_exists = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if texture_file_exists and nil ~= texture_data_from_file then
|
||||||
|
if texture_item_meta_exists then
|
||||||
|
-- sanity check: do we have the same textures?
|
||||||
|
-- if server-side texture has changed, take it
|
||||||
|
if maps.decode_map_item_meta(tga_deflate_base64) ~= texture_data_from_file then
|
||||||
|
minetest.log(
|
||||||
|
"action",
|
||||||
|
"maps: update item meta from file content for map " .. map_id
|
||||||
|
)
|
||||||
|
meta:set_string(
|
||||||
|
"maps:tga_deflate_base64",
|
||||||
|
maps.encode_map_item_meta(texture_data_from_file)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- map items without meta should not exist, so
|
||||||
|
-- we now write the file contents to item meta
|
||||||
|
minetest.log(
|
||||||
|
"action",
|
||||||
|
"maps: create item meta from file content for map " .. map_id
|
||||||
|
)
|
||||||
|
meta:set_string(
|
||||||
|
"maps:tga_deflate_base64",
|
||||||
|
maps.encode_map_item_meta(texture_data_from_file)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- no texture file → could be a world download
|
||||||
|
-- so we look for missing texture in item meta
|
||||||
|
-- and write that to the map texture file here
|
||||||
|
if texture_item_meta_exists then
|
||||||
|
minetest.log(
|
||||||
|
"action",
|
||||||
|
"maps: create file content from item meta for map " .. map_id
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
minetest.safe_file_write(
|
||||||
|
texture_file_path,
|
||||||
|
decode_item_meta(tga_deflate_base64)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else
|
||||||
|
minetest.log(
|
||||||
|
"error",
|
||||||
|
"no data for map " .. map_id
|
||||||
|
)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return maps.load_map(map_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_joinplayer(
|
minetest.register_on_joinplayer(
|
||||||
|
@ -413,62 +548,114 @@ minetest.register_on_joinplayer(
|
||||||
offset = { x = 0, y = 0 },
|
offset = { x = 0, y = 0 },
|
||||||
scale = { x = 4, y = 4 }
|
scale = { x = 4, y = 4 }
|
||||||
}
|
}
|
||||||
local dot_def = table.copy(map_def)
|
local pos_def = table.copy(map_def)
|
||||||
maps.maps[player_name] = player:hud_add(map_def)
|
maps.huds[player_name] = {
|
||||||
maps.dots[player_name] = player:hud_add(dot_def)
|
map = player:hud_add(map_def),
|
||||||
maps.minp[player_name] = { x=-32000, y=0, z=0 }
|
pos = player:hud_add(pos_def),
|
||||||
maps.maxp[player_name] = { x=-32000, y=0, z=0 }
|
}
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
local time_elapsed = 0
|
maps.show_map_hud = function(player)
|
||||||
|
local wield_item = player:get_wielded_item()
|
||||||
minetest.register_globalstep(
|
local texture = maps.load_map_item(wield_item)
|
||||||
function(dtime)
|
local player_pos = player:get_pos()
|
||||||
time_elapsed = time_elapsed + dtime
|
|
||||||
if time_elapsed < ( 1 / 30 ) then
|
|
||||||
return -- fps limiter
|
|
||||||
end
|
|
||||||
local players = minetest.get_connected_players()
|
|
||||||
for _, player in pairs(players) do
|
|
||||||
local pos = vector.round(player:get_pos())
|
|
||||||
local player_name = player:get_player_name()
|
local player_name = player:get_player_name()
|
||||||
|
|
||||||
|
if not player_pos or not texture then
|
||||||
|
if maps.maps[player_name] then
|
||||||
|
player:hud_change(
|
||||||
|
maps.huds[player_name].map,
|
||||||
|
"text",
|
||||||
|
"blank.png"
|
||||||
|
)
|
||||||
|
player:hud_change(
|
||||||
|
maps.huds[player_name].pos,
|
||||||
|
"text",
|
||||||
|
"blank.png"
|
||||||
|
)
|
||||||
|
maps.maps[player_name] = nil
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos = vector.round(player_pos)
|
||||||
|
local meta = wield_item:get_meta()
|
||||||
|
|
||||||
|
local meta_minp = meta:get_string("maps:minp")
|
||||||
|
assert( "" ~= meta_minp )
|
||||||
|
local minp = minetest.string_to_pos(meta_minp)
|
||||||
|
|
||||||
|
local meta_maxp = meta:get_string("maps:maxp")
|
||||||
|
assert( "" ~= meta_maxp )
|
||||||
|
local maxp = minetest.string_to_pos(meta_maxp)
|
||||||
|
|
||||||
|
local meta_xpos = meta:get_string("maps:xpos")
|
||||||
|
if "" ~= meta_xpos then
|
||||||
|
local xpos = minetest.string_to_pos(meta_xpos)
|
||||||
|
local x_x = xpos.x - minp.x - 4
|
||||||
|
local x_z = maxp.z - xpos.z - 4
|
||||||
|
local x_overlay = "^[combine:" ..
|
||||||
|
size .. "x" .. size .. ":" ..
|
||||||
|
x_x .. "," .. x_z .. "=maps_x.tga"
|
||||||
|
texture = texture .. x_overlay
|
||||||
|
end
|
||||||
|
|
||||||
|
local light_level = minetest.get_node_light(pos) or 0
|
||||||
|
local darkness = 255 - (light_level * 17)
|
||||||
|
local light_level_overlay = "^[colorize:black:" .. darkness
|
||||||
if (
|
if (
|
||||||
pos.x == maps.posx[player_name] and
|
texture ~= maps.maps[player_name] or
|
||||||
pos.z == maps.posz[player_name]
|
darkness ~= maps.dark[player_name]
|
||||||
) then
|
) then
|
||||||
-- continue
|
player:hud_change(
|
||||||
else
|
maps.huds[player_name].map,
|
||||||
local minp = maps.minp[player_name]
|
"text",
|
||||||
local maxp = maps.maxp[player_name]
|
texture .. light_level_overlay
|
||||||
|
)
|
||||||
|
maps.dark[player_name] = darkness
|
||||||
|
maps.maps[player_name] = texture
|
||||||
|
end
|
||||||
|
|
||||||
|
local marker
|
||||||
|
local dot_large = "maps_dot_large.tga" .. "^[makealpha:1,1,1"
|
||||||
|
local dot_small = "maps_dot_small.tga" .. "^[makealpha:1,1,1"
|
||||||
|
|
||||||
if pos.x < minp.x then
|
if pos.x < minp.x then
|
||||||
maps.create_map(pos, player_name)
|
if minp.x - pos.x < size then
|
||||||
|
marker = dot_large
|
||||||
|
else
|
||||||
|
marker = dot_small
|
||||||
|
end
|
||||||
|
pos.x = minp.x
|
||||||
elseif pos.x > maxp.x then
|
elseif pos.x > maxp.x then
|
||||||
maps.create_map(pos, player_name)
|
if pos.x - maxp.x < size then
|
||||||
|
marker = dot_large
|
||||||
|
else
|
||||||
|
marker = dot_small
|
||||||
|
end
|
||||||
|
pos.x = maxp.x
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- we never override the small marker
|
||||||
|
-- yes, this is a literal corner case
|
||||||
if pos.z < minp.z then
|
if pos.z < minp.z then
|
||||||
maps.create_map(pos, player_name)
|
if minp.z - pos.z < 256 and marker ~= dot_small then
|
||||||
|
marker = dot_large
|
||||||
|
else
|
||||||
|
marker = dot_small
|
||||||
|
end
|
||||||
|
pos.z = minp.z
|
||||||
elseif pos.z > maxp.z then
|
elseif pos.z > maxp.z then
|
||||||
maps.create_map(pos, player_name)
|
if pos.z - maxp.z < 256 and marker ~= dot_small then
|
||||||
|
marker = dot_large
|
||||||
|
else
|
||||||
|
marker = dot_small
|
||||||
|
end
|
||||||
|
pos.z = maxp.z
|
||||||
end
|
end
|
||||||
|
|
||||||
local x = (pos.x - minp.x - (size/2)) * 4
|
if nil == marker then
|
||||||
local y = (minp.z - pos.z) * 4 - 2
|
|
||||||
player:hud_change(
|
|
||||||
maps.dots[player_name],
|
|
||||||
"offset",
|
|
||||||
{
|
|
||||||
x = x,
|
|
||||||
y = y,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
maps.posx[player_name] = pos.x
|
|
||||||
maps.posz[player_name] = pos.z
|
|
||||||
end
|
|
||||||
local marker
|
|
||||||
local yaw = (
|
local yaw = (
|
||||||
math.floor(
|
math.floor(
|
||||||
player:get_look_horizontal()
|
player:get_look_horizontal()
|
||||||
|
@ -496,13 +683,71 @@ minetest.register_globalstep(
|
||||||
"^[transformR" ..
|
"^[transformR" ..
|
||||||
(yaw - 45)
|
(yaw - 45)
|
||||||
end
|
end
|
||||||
if marker then
|
end
|
||||||
|
|
||||||
|
if marker and marker ~= maps.mark[player_name] then
|
||||||
player:hud_change(
|
player:hud_change(
|
||||||
maps.dots[player_name],
|
maps.huds[player_name].pos,
|
||||||
"text",
|
"text",
|
||||||
marker
|
marker
|
||||||
)
|
)
|
||||||
|
maps.mark[player_name] = marker
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local marker_x = (pos.x - minp.x - (size/2)) * 4
|
||||||
|
local marker_y = (maxp.z - pos.z - size + 3) * 4
|
||||||
|
if (
|
||||||
|
marker_x ~= maps.marx[player_name] or
|
||||||
|
marker_y ~= maps.mary[player_name]
|
||||||
|
) then
|
||||||
|
player:hud_change(
|
||||||
|
maps.huds[player_name].pos,
|
||||||
|
"offset",
|
||||||
|
{
|
||||||
|
x = marker_x,
|
||||||
|
y = marker_y,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
maps.marx[player_name] = marker_x
|
||||||
|
maps.mary[player_name] = marker_y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local time_elapsed = 0
|
||||||
|
|
||||||
|
minetest.register_globalstep(
|
||||||
|
function(dtime)
|
||||||
|
time_elapsed = time_elapsed + dtime
|
||||||
|
if time_elapsed < ( 1 / 30 ) then
|
||||||
|
return -- fps limiter
|
||||||
|
end
|
||||||
|
local players = minetest.get_connected_players()
|
||||||
|
for _, player in pairs(players) do
|
||||||
|
maps.show_map_hud(player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
|
maps.create_map_item = function(itemstack, player, pointed_thing)
|
||||||
|
local pos = player:get_pos()
|
||||||
|
if pos then
|
||||||
|
local map = maps.create_map(pos)
|
||||||
|
return map
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.override_item(
|
||||||
|
"map:mapping_kit",
|
||||||
|
{
|
||||||
|
on_place = maps.create_map_item,
|
||||||
|
on_secondary_use = maps.create_map_item,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
minetest.register_craftitem(
|
||||||
|
"maps:map",
|
||||||
|
{
|
||||||
|
description = "Map",
|
||||||
|
inventory_image = "maps_map.tga"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
1
mod.conf
1
mod.conf
|
@ -1,3 +1,4 @@
|
||||||
depends = tga_encoder
|
depends = tga_encoder
|
||||||
description = Shows maps in the player HUD
|
description = Shows maps in the player HUD
|
||||||
name = maps
|
name = maps
|
||||||
|
depends = map
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue