xmaps/init.lua

949 lines
21 KiB
Lua
Raw Permalink Normal View History

2022-05-17 06:49:56 +02:00
--[[
xmaps Minetest mod that adds map items that show terrain in HUD
2022-05-17 06:49:56 +02:00
Copyright © 2022 Nils Dagsson Moskopp (erlehmann)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Dieses Programm hat das Ziel, die Medienkompetenz der Leser zu
steigern. Gelegentlich packe ich sogar einen handfesten Buffer
Overflow oder eine Format String Vulnerability zwischen die anderen
Codezeilen und schreibe das auch nicht dran.
]]--
2022-05-19 03:19:25 +02:00
-- blit an icon into the image unless its rect overlaps pixels that
-- have any of the stop_colors, treating a nil pixel as transparent
function tga_encoder.image:blit_icon(icon, pos, stop_colors)
local x = pos.x
local z = pos.z
local overlap = false
for i_z = 1,#icon do
for i_x = 1,#icon[i_z] do
local color = self.pixels[z + i_z][x + i_x][1]
if stop_colors[color] then
overlap = true
break
end
end
if overlap then
break
end
end
if overlap then
return
end
for i_z = 1,#icon do
for i_x = 1,#icon[i_z] do
local color = icon[i_z][i_x][1]
if color then
self.pixels[z + i_z][x + i_x] = { color }
end
end
end
end
xmaps = {}
2022-05-20 00:37:15 +02:00
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
xmaps.mark = {} -- key: player name; value: marker texture
xmaps.marx = {} -- key: player name; value: marker x offset
xmaps.mary = {} -- key: player name; value: marker y offset
2022-05-20 00:37:15 +02:00
xmaps.load = {} -- maps loaded by players
xmaps.sent = {} -- maps sent to players
xmaps.work = {} -- maps being created
2022-05-17 06:49:56 +02:00
2022-05-17 13:00:47 +02:00
local size = 80
2022-05-17 06:49:56 +02:00
local worldpath = minetest.get_worldpath()
local textures_dir = worldpath .. "/xmaps/"
2022-05-17 06:49:56 +02:00
minetest.mkdir(textures_dir)
xmaps.get_map_filename = function(map_id)
return "xmaps_map_texture_" .. map_id .. ".tga"
2022-05-20 00:37:15 +02:00
end
2022-05-17 06:49:56 +02:00
xmaps.create_map_item = function(pos, properties)
properties = properties or {}
local itemstack = ItemStack("xmaps:map")
2022-05-20 00:37:15 +02:00
local meta = itemstack:get_meta()
2022-05-17 06:49:56 +02:00
2022-05-20 00:37:15 +02:00
local map_id = tostring(os.time() + math.random())
meta:set_string("xmaps:id", map_id)
2022-05-17 06:49:56 +02:00
2022-05-20 00:37:15 +02:00
local minp = vector.multiply(vector.floor(vector.divide(pos, size)), size)
meta:set_string("xmaps:minp", minetest.pos_to_string(minp))
2022-05-17 06:49:56 +02:00
2022-05-20 00:37:15 +02:00
local maxp = vector.add(minp, vector.new(size - 1, size - 1, size - 1))
meta:set_string("xmaps:maxp", minetest.pos_to_string(maxp))
2022-05-17 06:49:56 +02:00
if properties.draw_x then
local xpos = vector.round(pos)
meta:set_string("xmaps:xpos", minetest.pos_to_string(xpos))
end
2022-05-17 06:49:56 +02:00
local filename = xmaps.get_map_filename(map_id)
xmaps.work[map_id] = true
2022-05-17 06:49:56 +02:00
local emerge_callback = function(
blockpos,
action,
calls_remaining
)
if calls_remaining > 0 then
return
end
local pixels = {}
local colormap = {
2022-05-19 14:20:28 +02:00
{ 195, 175, 140 }, -- background checkerboard light
{ 180, 160, 125 }, -- background checkerboard dark
2022-05-17 17:15:04 +02:00
{ 60, 35, 16 }, -- dark line
{ 210, 170, 130 }, -- liquid light
2022-05-17 20:31:14 +02:00
{ 135, 90, 40 }, -- liquid dark
{ 150, 105, 55 }, -- more liquid
{ 165, 120, 70 }, -- more liquid
{ 150, 105, 55 }, -- more liquid
2022-05-18 21:29:17 +02:00
{ 60, 35, 16 }, -- tree outline
{ 150, 105, 55 }, -- tree fill
2022-05-17 06:49:56 +02:00
}
2022-05-17 13:00:47 +02:00
for x = 1,size,1 do
for z = 1,size,1 do
2022-05-19 14:20:28 +02:00
local color = 0 + ( ( x + z ) % 2 )
2022-05-17 06:49:56 +02:00
pixels[z] = pixels[z] or {}
pixels[z][x] = { color }
2022-05-17 06:49:56 +02:00
end
end
2022-05-17 17:15:04 +02:00
local positions = minetest.find_nodes_in_area_under_air(
minp,
maxp,
"group:liquid"
)
for _, p in ipairs(positions) do
2022-05-19 06:05:33 +02:00
if 14 == minetest.get_node_light(p, 0.5) then
local z = p.z - minp.z + 1
local x = p.x - minp.x + 1
2022-05-19 14:20:28 +02:00
pixels[z][x] = { 3 }
2022-05-19 06:05:33 +02:00
end
2022-05-17 17:15:04 +02:00
end
-- draw coastline
for x = 1,size,1 do
for z = 1,size,1 do
2022-05-19 14:20:28 +02:00
if pixels[z][x][1] >= 3 then
pixels[z][x] = { 3 + ( z % 2 ) } -- stripes
if pixels[z][x][1] == 4 then
local color = 4 + ( ( math.floor( x / 7 ) + math.floor( 1.3 * z * z ) ) % 4 )
pixels[z][x] = { color }
2022-05-17 20:31:14 +02:00
end
2022-05-19 14:20:28 +02:00
if z > 1 and pixels[z-1][x][1] < 3 then
pixels[z-1][x] = { 2 }
pixels[z][x] = { 4 }
2022-05-17 17:15:04 +02:00
end
2022-05-19 14:20:28 +02:00
if z < size and pixels[z+1][x][1] < 3 then
pixels[z+1][x] = { 2 }
pixels[z][x] = { 4 }
2022-05-17 17:15:04 +02:00
end
2022-05-19 14:20:28 +02:00
if x > 1 and pixels[z][x-1][1] < 3 then
pixels[z][x-1] = { 2 }
pixels[z][x] = { 4 }
2022-05-17 17:15:04 +02:00
end
2022-05-19 14:20:28 +02:00
if x < size and pixels[z][x+1][1] < 3 then
pixels[z][x+1] = { 2 }
pixels[z][x] = { 4 }
2022-05-17 17:15:04 +02:00
end
end
2022-05-17 06:49:56 +02:00
end
end
2022-05-19 03:19:25 +02:00
local image = tga_encoder.image(pixels)
2022-05-19 15:09:08 +02:00
local positions = minetest.find_nodes_in_area(
minp,
maxp,
"group:door"
)
for _, p in ipairs(positions) do
local z = p.z - minp.z + 1
local x = p.x - minp.x + 1
local draw_house = (
z > 1 and
z < size - 7 and
x > 4 and
x < size - 4
)
if draw_house then
local _ = { nil } -- transparent
local O = { 8 } -- outline
local F = { 9 } -- filling
local house = {
{ _, _, _, _, _, _, _ },
{ _, O, O, O, O, O, _ },
{ _, O, F, F, F, O, _ },
{ _, O, F, F, F, O, _ },
{ _, O, F, F, F, O, _ },
{ _, _, O, F, O, _, _ },
{ _, _, _, O, _, _, _ },
{ _, _, _, _, _, _, _ },
}
image:blit_icon(
house,
{
x = x - 5,
z = z - 1,
},
{
[4] = true,
[5] = true,
[6] = true,
[7] = true,
[8] = true,
[9] = true,
}
)
end
end
2022-05-18 21:29:17 +02:00
local positions = minetest.find_nodes_in_area_under_air(
minp,
maxp,
{
"group:leaves",
"default:snow", -- snow-covered leaves
}
)
for _, p in ipairs(positions) do
local z = p.z - minp.z + 1
local x = p.x - minp.x + 1
local node = minetest.get_node({
x=p.x,
y=p.y - 4,
z=p.z,
})
local draw_tree = (
minetest.get_item_group(
node.name,
"tree"
) > 0 ) and (
2022-05-19 03:46:40 +02:00
z > 1 and
z < size - 7 and
x > 4 and
x < size - 4
2022-05-18 21:29:17 +02:00
)
if draw_tree then
local tree = {}
2022-05-19 03:19:25 +02:00
local _ = { nil } -- transparent
2022-05-19 14:20:28 +02:00
local O = { 8 } -- outline
local F = { 9 } -- filling
2022-05-18 21:29:17 +02:00
if nil ~= node.name:find("pine") then
tree = {
2022-05-19 03:46:40 +02:00
{ _, _, _, _, _, _, _ },
{ _, _, _, O, _, _, _ },
{ _, O, O, O, O, O, _ },
{ _, O, F, F, F, O, _ },
{ _, _, O, F, O, _, _ },
{ _, _, O, F, O, _, _ },
{ _, _, _, O, _, _, _ },
{ _, _, _, _, _, _, _ },
2022-05-18 21:29:17 +02:00
}
else
tree = {
2022-05-19 03:46:40 +02:00
{ _, _, _, _, _, _, _ },
{ _, _, _, O, _, _, _ },
{ _, _, _, O, _, _, _ },
{ _, _, O, O, O, _, _ },
{ _, O, F, F, F, O, _ },
{ _, O, F, F, F, O, _ },
{ _, _, O, O, O, _, _ },
{ _, _, _, _, _, _, _ },
2022-05-18 21:29:17 +02:00
}
end
2022-05-19 03:19:25 +02:00
image:blit_icon(
tree,
{
2022-05-19 03:46:40 +02:00
x = x - 4,
z = z - 1,
2022-05-19 03:19:25 +02:00
},
{
[4] = true,
[5] = true,
[6] = true,
[7] = true,
2022-05-19 14:20:28 +02:00
[8] = true,
[9] = true,
2022-05-19 03:19:25 +02:00
}
)
2022-05-18 21:29:17 +02:00
end
end
2022-05-19 03:35:26 +02:00
local positions = minetest.find_nodes_in_area_under_air(
minp,
maxp,
"group:grass"
)
for _, p in ipairs(positions) do
local z = p.z - minp.z + 1
local x = p.x - minp.x + 1
local draw_grass = (
z > 1 and
z < size - 4 and
x > 4 and
x < size - 4
)
if draw_grass then
local _ = { nil } -- transparent
2022-05-19 14:20:28 +02:00
local G = { 9 } -- line
2022-05-19 03:35:26 +02:00
local grass = {
{ _, _, _, _, _, _, _ },
{ _, G, _, G, _, G, _ },
{ _, G, _, G, _, G, _ },
{ _, _, _, G, _, _, _ },
{ _, _, _, _, _, _, _ },
}
image:blit_icon(
grass,
{
x = x - 5,
z = z - 1,
},
{
[4] = true,
[5] = true,
[6] = true,
[7] = true,
2022-05-19 14:20:28 +02:00
[8] = true,
[9] = true,
2022-05-19 03:35:26 +02:00
}
)
end
end
2022-05-19 19:32:47 +02:00
local positions = minetest.find_nodes_in_area_under_air(
minp,
maxp,
"group:flower"
)
for _, p in ipairs(positions) do
local z = p.z - minp.z + 1
local x = p.x - minp.x + 1
local draw_flower = (
z > 1 and
z < size - 3 and
x > 2 and
x < size - 2
)
if draw_flower then
local _ = { nil } -- transparent
local F = { 9 } -- line
local flower = {
{ _, _, _, },
{ _, F, _, },
{ _, F, _, },
{ _, _, _, },
}
image:blit_icon(
flower,
{
x = x - 2,
z = z - 1,
},
{
[4] = true,
[5] = true,
[6] = true,
[7] = true,
[8] = true,
[9] = true,
}
)
end
end
2022-05-17 06:49:56 +02:00
local filepath = textures_dir .. filename
2022-05-19 03:19:25 +02:00
image:save(
2022-05-17 06:49:56 +02:00
filepath,
{ colormap=colormap }
)
xmaps.work[map_id] = false
2022-05-17 06:49:56 +02:00
end
minetest.emerge_area(
minp,
maxp,
emerge_callback
)
2022-05-20 00:37:15 +02:00
return itemstack
end
xmaps.load_map = function(map_id)
2022-05-20 00:37:15 +02:00
assert( nil ~= map_id )
if (
"" == map_id or
xmaps.work[map_id]
2022-05-20 00:37:15 +02:00
) then
return
end
local filename = xmaps.get_map_filename(map_id)
2022-05-20 00:37:15 +02:00
if not xmaps.sent[map_id] then
2022-05-20 00:37:15 +02:00
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.load[map_id] = true
2022-05-20 00:37:15 +02:00
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
2022-05-20 00:37:15 +02:00
end
)
end
xmaps.sent[map_id] = true
2022-05-20 00:37:15 +02:00
end
if xmaps.load[map_id] then
2022-05-20 00:37:15 +02:00
return filename
end
end
xmaps.encode_map_item_meta = function(input)
2022-05-20 00:37:15 +02:00
return minetest.encode_base64(
minetest.compress(
input,
"deflate",
9
)
)
end
xmaps.decode_map_item_meta = function(input)
2022-05-20 00:37:15 +02:00
return minetest.decompress(
minetest.decode_base64(input),
"deflate",
9
)
end
result_original = "foo\0\01\02\x03\n\rbar"
result_roundtrip = xmaps.decode_map_item_meta(
xmaps.encode_map_item_meta(result_original)
2022-05-20 00:37:15 +02:00
)
assert(
result_original == result_roundtrip,
"xmaps: mismatch between xmaps.encode_map_item_meta() and xmaps.decode_map_item_meta()"
2022-05-20 00:37:15 +02:00
)
xmaps.load_map_item = function(itemstack)
2022-05-20 00:37:15 +02:00
local meta = itemstack:get_meta()
local map_id = meta:get_string("xmaps:id")
2022-05-20 00:37:15 +02:00
if (
not map_id or
"" == map_id or
xmaps.work[map_id]
2022-05-20 00:37:15 +02:00
) then
return
end
local texture_file_name = xmaps.get_map_filename(map_id)
2022-05-20 00:37:15 +02:00
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("xmaps:tga_deflate_base64")
2022-05-20 00:37:15 +02:00
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 xmaps.decode_map_item_meta(tga_deflate_base64) ~= texture_data_from_file then
2022-05-20 00:37:15 +02:00
minetest.log(
"action",
"xmaps: update item meta from file content for map " .. map_id
2022-05-20 00:37:15 +02:00
)
meta:set_string(
"xmaps:tga_deflate_base64",
xmaps.encode_map_item_meta(texture_data_from_file)
2022-05-20 00:37:15 +02:00
)
end
else
-- map items without meta should not exist, so
-- we now write the file contents to item meta
minetest.log(
"action",
"xmaps: create item meta from file content for map " .. map_id
2022-05-20 00:37:15 +02:00
)
meta:set_string(
"xmaps:tga_deflate_base64",
xmaps.encode_map_item_meta(texture_data_from_file)
2022-05-20 00:37:15 +02:00
)
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",
"xmaps: create file content from item meta for map " .. map_id
2022-05-20 00:37:15 +02:00
)
assert(
minetest.safe_file_write(
texture_file_path,
xmaps.decode_map_item_meta(tga_deflate_base64)
2022-05-20 00:37:15 +02:00
)
)
else
minetest.log(
"error",
"no data for map " .. map_id
)
return
end
end
local texture = xmaps.load_map(map_id)
2022-05-21 22:11:08 +02:00
2022-05-22 02:24:22 +02:00
local meta_xpos = meta:get_string("xmaps:xpos")
if texture and "" ~= meta_xpos then
local meta_minp = meta:get_string("xmaps:minp")
assert( "" ~= meta_minp )
local minp = minetest.string_to_pos(meta_minp)
2022-05-21 22:11:08 +02:00
2022-05-22 02:24:22 +02:00
local meta_maxp = meta:get_string("xmaps:maxp")
assert( "" ~= meta_maxp )
local maxp = minetest.string_to_pos(meta_maxp)
2022-05-21 22:11:08 +02:00
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 .. "=xmaps_x.tga"
texture = texture .. x_overlay
end
2022-05-20 15:33:40 +02:00
return texture, itemstack
2022-05-17 06:49:56 +02:00
end
minetest.register_on_joinplayer(
function(player)
local player_name = player:get_player_name()
local map_def = {
hud_elem_type = "image",
text = "blank.png",
position = { x = 0.15, y = 0.90 },
alignment = { x = 0, y = -1 },
offset = { x = 0, y = 0 },
scale = { x = 4, y = 4 }
}
2022-05-20 00:37:15 +02:00
local pos_def = table.copy(map_def)
xmaps.huds[player_name] = {
2022-05-20 00:37:15 +02:00
map = player:hud_add(map_def),
pos = player:hud_add(pos_def),
}
2022-05-17 06:49:56 +02:00
end
)
xmaps.show_map_hud = function(player)
2022-05-20 00:37:15 +02:00
local wield_item = player:get_wielded_item()
local texture, updated_wield_item = xmaps.load_map_item(wield_item)
2022-05-20 00:37:15 +02:00
local player_pos = player:get_pos()
local player_name = player:get_player_name()
if not player_pos or not texture then
if xmaps.maps[player_name] then
2022-05-20 00:37:15 +02:00
player:hud_change(
xmaps.huds[player_name].map,
2022-05-20 00:37:15 +02:00
"text",
"blank.png"
)
player:hud_change(
xmaps.huds[player_name].pos,
2022-05-20 00:37:15 +02:00
"text",
"blank.png"
)
xmaps.maps[player_name] = nil
xmaps.mark[player_name] = nil
2022-05-20 00:37:15 +02:00
end
return
end
2022-05-20 15:53:21 +02:00
if (
texture ~= xmaps.maps[player_name] and
2022-05-20 15:53:21 +02:00
updated_wield_item
) then
2022-05-20 15:33:40 +02:00
player:set_wielded_item(updated_wield_item)
end
2022-05-20 00:37:15 +02:00
local pos = vector.round(player_pos)
local meta = wield_item:get_meta()
local meta_minp = meta:get_string("xmaps:minp")
2022-05-20 00:37:15 +02:00
assert( "" ~= meta_minp )
local minp = minetest.string_to_pos(meta_minp)
local meta_maxp = meta:get_string("xmaps:maxp")
2022-05-20 00:37:15 +02:00
assert( "" ~= meta_maxp )
local maxp = minetest.string_to_pos(meta_maxp)
local light_level = minetest.get_node_light(pos) or 0
local darkness = 255 - (light_level * 17)
local light_level_overlay = "^[colorize:black:" .. darkness
if (
texture ~= xmaps.maps[player_name] or
darkness ~= xmaps.dark[player_name]
2022-05-20 00:37:15 +02:00
) then
player:hud_change(
xmaps.huds[player_name].map,
2022-05-20 00:37:15 +02:00
"text",
texture .. light_level_overlay
)
xmaps.maps[player_name] = texture
2022-05-20 00:37:15 +02:00
end
local marker
local dot_large = "xmaps_dot_large.tga" .. "^[makealpha:1,1,1"
local dot_small = "xmaps_dot_small.tga" .. "^[makealpha:1,1,1"
2022-05-22 15:54:25 +02:00
local dot_tiny = "xmaps_dot_tiny.tga" .. "^[makealpha:1,1,1"
2022-05-20 00:37:15 +02:00
if pos.x < minp.x then
2022-05-22 15:54:25 +02:00
if minp.x - pos.x < size * 2 then
2022-05-20 00:37:15 +02:00
marker = dot_large
2022-05-22 15:54:25 +02:00
elseif minp.x - pos.x < size * 4 then
2022-05-20 00:37:15 +02:00
marker = dot_small
2022-05-22 15:54:25 +02:00
else
marker = dot_tiny
2022-05-20 00:37:15 +02:00
end
pos.x = minp.x
elseif pos.x > maxp.x then
2022-05-22 15:54:25 +02:00
if pos.x - maxp.x < size * 2 then
2022-05-20 00:37:15 +02:00
marker = dot_large
2022-05-22 15:54:25 +02:00
elseif pos.x - maxp.x < size * 4 then
2022-05-20 00:37:15 +02:00
marker = dot_small
2022-05-22 15:54:25 +02:00
else
marker = dot_tiny
2022-05-20 00:37:15 +02:00
end
pos.x = maxp.x
end
2022-05-22 15:54:25 +02:00
-- we never override a smaller marker
2022-05-20 00:37:15 +02:00
-- yes, this is a literal corner case
if pos.z < minp.z then
2022-05-22 15:54:25 +02:00
if (
minp.z - pos.z < size * 2 and
marker ~= dot_small and
marker ~= dot_tiny
) then
2022-05-20 00:37:15 +02:00
marker = dot_large
2022-05-22 15:54:25 +02:00
elseif (
minp.z - pos.z < size * 4 and
marker ~= dot_tiny
) then
2022-05-20 00:37:15 +02:00
marker = dot_small
2022-05-22 15:54:25 +02:00
else
marker = dot_tiny
2022-05-20 00:37:15 +02:00
end
pos.z = minp.z
elseif pos.z > maxp.z then
2022-05-22 15:54:25 +02:00
if (
pos.z - maxp.z < size * 2 and
marker ~= dot_small and
marker ~= dot_tiny
) then
2022-05-20 00:37:15 +02:00
marker = dot_large
2022-05-22 15:54:25 +02:00
elseif (
pos.z - maxp.z < size * 4 and
marker ~= dot_tiny
) then
2022-05-20 00:37:15 +02:00
marker = dot_small
2022-05-22 15:54:25 +02:00
else
marker = dot_tiny
2022-05-20 00:37:15 +02:00
end
pos.z = maxp.z
end
if nil == marker then
local yaw = (
math.floor(
player:get_look_horizontal()
* 180 / math.pi / 45 + 0.5
) % 8
) * 45
if (
yaw == 0 or
yaw == 90 or
yaw == 180 or
yaw == 270
) then
marker = "xmaps_arrow.tga" ..
2022-05-20 00:37:15 +02:00
"^[makealpha:1,1,1" ..
"^[transformR" ..
yaw
elseif (
yaw == 45 or
yaw == 135 or
yaw == 225 or
yaw == 315
) then
marker = "xmaps_arrow_diagonal.tga" ..
2022-05-20 00:37:15 +02:00
"^[makealpha:1,1,1" ..
"^[transformR" ..
(yaw - 45)
end
end
if marker and (
marker ~= xmaps.mark[player_name] or
darkness ~= xmaps.dark[player_name]
) then
2022-05-20 00:37:15 +02:00
player:hud_change(
xmaps.huds[player_name].pos,
2022-05-20 00:37:15 +02:00
"text",
marker .. light_level_overlay
2022-05-20 00:37:15 +02:00
)
xmaps.mark[player_name] = marker
2022-05-20 00:37:15 +02:00
end
local marker_x = (pos.x - minp.x - (size/2)) * 4
local marker_y = (maxp.z - pos.z - size + 3) * 4
if (
marker_x ~= xmaps.marx[player_name] or
marker_y ~= xmaps.mary[player_name]
2022-05-20 00:37:15 +02:00
) then
player:hud_change(
xmaps.huds[player_name].pos,
2022-05-20 00:37:15 +02:00
"offset",
{
x = marker_x,
y = marker_y,
}
)
xmaps.marx[player_name] = marker_x
xmaps.mary[player_name] = marker_y
2022-05-20 00:37:15 +02:00
end
xmaps.dark[player_name] = darkness
2022-05-20 00:37:15 +02:00
end
2022-05-17 06:49:56 +02:00
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
xmaps.show_map_hud(player)
2022-05-17 06:49:56 +02:00
end
end
)
2022-05-20 00:37:15 +02:00
2022-05-21 21:42:46 +02:00
minetest.register_entity(
"xmaps:map",
{
visual = "upright_sprite",
visual_size = { x = 1, y = 1 },
physical = false,
collide_with_objects = false,
textures = { "xmaps_map.tga" },
on_activate = function(self, staticdata)
if (
staticdata and
"" ~= staticdata
) then
local data = minetest.deserialize(staticdata)
if not data then
return
end
self._wallmounted = data._wallmounted
assert( self._wallmounted )
self._itemstring = data._itemstring
assert( self._itemstring )
local min, max = -8/16, 8/16
local len = 1/64
local sbox
if 2 == self._wallmounted then
sbox = { -len, min, min, len, max, max }
elseif 3 == self._wallmounted then
sbox = { -len, min, min, len, max, max }
elseif 4 == self._wallmounted then
sbox = { min, min, -len, max, max, len }
elseif 5 == self._wallmounted then
sbox = { min, min, -len, max, max, len }
end
assert( sbox )
self.object:set_properties({
selectionbox = sbox,
textures = { "blank.png" },
2022-05-21 21:42:46 +02:00
})
local yaw = minetest.dir_to_yaw(
minetest.wallmounted_to_dir(
self._wallmounted
)
)
self.object:set_yaw(yaw)
end
end,
on_step = function(self)
if self._texture then
return
end
local itemstack = ItemStack(self._itemstring)
self._texture, itemstack = xmaps.load_map_item(itemstack)
self._itemstring = itemstack:to_string()
self.object:set_properties({
textures = { self._texture }
})
end,
2022-05-21 21:42:46 +02:00
get_staticdata = function(self)
return minetest.serialize(
{
_wallmounted = self._wallmounted,
_itemstring = self._itemstring,
}
)
end,
on_punch = function(self)
-- TODO: implement protection
local pos = self.object:get_pos()
local itemstring = self._itemstring
if pos and itemstring then
minetest.add_item(
pos,
itemstring
)
self.object:remove()
end
end
}
)
2022-05-20 00:37:15 +02:00
minetest.register_craftitem(
"xmaps:map",
2022-05-20 00:37:15 +02:00
{
description = "Map",
inventory_image = "xmaps_map.tga",
2022-05-20 01:19:17 +02:00
groups = { not_in_creative_inventory = 1 },
2022-05-21 21:42:46 +02:00
on_place = function(itemstack, player, pointed_thing)
if "node" ~= pointed_thing.type then
return
end
local player_pos = player:get_pos()
if not player_pos then
return
end
local node_pos = pointed_thing.under
local direction = vector.normalize(
vector.subtract(
node_pos,
player_pos
)
)
local wallmounted = minetest.dir_to_wallmounted(
direction
)
-- TODO: implement maps on floor or ceiling
if wallmounted < 2 then
return
end
direction = minetest.wallmounted_to_dir(
wallmounted
)
local pos = vector.subtract(
node_pos,
vector.multiply(
direction,
1/2 + 1/256 -- avoid z-fighting
)
)
local itemstring = itemstack:to_string()
if pos and "" ~= itemstring then
local staticdata = {
_wallmounted = wallmounted,
_itemstring = itemstring,
}
local obj = minetest.add_entity(
pos,
"xmaps:map",
minetest.serialize(staticdata)
)
if obj then
-- TODO: creative mode
itemstack:take_item()
end
end
return itemstack
end
2022-05-20 00:37:15 +02:00
}
)
2022-05-20 19:14:53 +02:00
if minetest.registered_items["map:mapping_kit"] then
minetest.override_item(
"map:mapping_kit",
{
on_place = function(itemstack, player, pointed_thing)
local pos = pointed_thing.under
if pos then
local map = xmaps.create_map_item(
2022-05-20 19:14:53 +02:00
pos,
{ draw_x = true }
)
return map
end
end,
on_secondary_use = function(itemstack, player, pointed_thing)
local pos = player:get_pos()
if pos then
local map = xmaps.create_map_item(pos)
2022-05-20 19:14:53 +02:00
return map
end
end,
}
)
end