forked from MineClone5/MineClone5
263 lines
7.7 KiB
Lua
263 lines
7.7 KiB
Lua
mcl_maps = {}
|
|
|
|
local S = minetest.get_translator("mcl_maps")
|
|
local storage = minetest.get_mod_storage()
|
|
local modpath = minetest.get_modpath("mcl_maps")
|
|
local worldpath = minetest.get_worldpath()
|
|
local map_textures_path = worldpath .. "/mcl_maps/"
|
|
local last_finished_id = storage:get_int("next_id") - 1
|
|
|
|
minetest.mkdir(map_textures_path)
|
|
|
|
local function load_json_file(name)
|
|
local file = assert(io.open(modpath .. "/" .. name .. ".json", "r"))
|
|
local data = minetest.parse_json(file:read())
|
|
file:close()
|
|
return data
|
|
end
|
|
|
|
local texture_colors = load_json_file("colors")
|
|
local palettes = load_json_file("palettes")
|
|
|
|
local color_cache = {}
|
|
|
|
local creating_maps = {}
|
|
local loading_maps = {}
|
|
local loaded_maps = {}
|
|
|
|
local c_air = minetest.get_content_id("air")
|
|
|
|
function mcl_maps.create_map(pos)
|
|
local itemstack = ItemStack("mcl_maps:filled_map")
|
|
local meta = itemstack:get_meta()
|
|
local id = storage:get_int("next_id")
|
|
storage:set_int("next_id", id + 1)
|
|
local texture_file = "mcl_maps_map_texture_" .. id .. ".tga"
|
|
local texture_path = map_textures_path .. texture_file
|
|
local texture = "[combine:140x140:0,0=mcl_maps_map_background.png:6,6=" .. texture_file
|
|
meta:set_int("mcl_maps:id", id)
|
|
meta:set_string("mcl_maps:texture", texture)
|
|
meta:set_string("mcl_maps:texture_path", texture_path)
|
|
tt.reload_itemstack_description(itemstack)
|
|
creating_maps[texture] = true
|
|
local minp = vector.multiply(vector.floor(vector.divide(pos, 128)), 128)
|
|
local maxp = vector.add(minp, vector.new(127, 127, 127))
|
|
minetest.emerge_area(minp, maxp, function(blockpos, action, calls_remaining)
|
|
if calls_remaining > 0 then
|
|
return
|
|
end
|
|
local vm = minetest.get_voxel_manip()
|
|
local emin, emax = vm:read_from_map(minp, maxp)
|
|
local data = vm:get_data()
|
|
local param2data = vm:get_param2_data()
|
|
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
|
local pixels = {}
|
|
local last_heightmap
|
|
for x = 1, 128 do
|
|
local map_x = minp.x - 1 + x
|
|
local heightmap = {}
|
|
for z = 1, 128 do
|
|
local map_z = minp.z - 1 + z
|
|
local color
|
|
for map_y = maxp.y, minp.y, -1 do
|
|
local index = area:index(map_x, map_y, map_z)
|
|
local c_id = data[index]
|
|
if c_id ~= c_air then
|
|
color = color_cache[c_id]
|
|
if color == nil then
|
|
local nodename = minetest.get_name_from_content_id(c_id)
|
|
local def = minetest.registered_nodes[nodename]
|
|
if def then
|
|
local texture
|
|
if def.palette then
|
|
texture = def.palette
|
|
elseif def.tiles then
|
|
texture = def.tiles[1]
|
|
if type(texture) == "table" then
|
|
texture = texture.name
|
|
end
|
|
end
|
|
if texture then
|
|
texture = texture:match("([^=^%^]-([^.]+))$"):split("^")[1]
|
|
end
|
|
if def.palette then
|
|
local palette = palettes[texture]
|
|
color = palette and {palette = palette}
|
|
else
|
|
color = texture_colors[texture]
|
|
end
|
|
end
|
|
end
|
|
|
|
if color and color.palette then
|
|
color = color.palette[param2data[index] + 1]
|
|
else
|
|
color_cache[c_id] = color or false
|
|
end
|
|
|
|
if color and last_heightmap then
|
|
local last_height = last_heightmap[z]
|
|
if last_height < map_y then
|
|
color = {
|
|
math.min(255, color[1] + 16),
|
|
math.min(255, color[2] + 16),
|
|
math.min(255, color[3] + 16),
|
|
}
|
|
elseif last_height > map_y then
|
|
color = {
|
|
math.max(0, color[1] - 16),
|
|
math.max(0, color[2] - 16),
|
|
math.max(0, color[3] - 16),
|
|
}
|
|
end
|
|
end
|
|
height = map_y
|
|
break
|
|
end
|
|
end
|
|
heightmap[z] = height
|
|
pixels[z] = pixels[z] or {}
|
|
pixels[z][x] = color or {0, 0, 0}
|
|
end
|
|
last_heightmap = heightmap
|
|
end
|
|
tga_encoder.image(pixels):save(texture_path)
|
|
creating_maps[texture] = false
|
|
end)
|
|
return itemstack
|
|
end
|
|
|
|
-- Turn empty map into filled map by rightclick
|
|
local make_filled_map = function(itemstack, placer, pointed_thing)
|
|
if minetest.settings:get_bool("enable_real_maps", true) then
|
|
local new_map = mcl_maps.create_map(placer:get_pos())
|
|
itemstack:take_item()
|
|
if itemstack:is_empty() then
|
|
return new_map
|
|
else
|
|
local inv = placer:get_inventory()
|
|
if inv:room_for_item("main", new_map) then
|
|
inv:add_item("main", new_map)
|
|
else
|
|
minetest.add_item(placer:get_pos(), new_map)
|
|
end
|
|
return itemstack
|
|
end
|
|
end
|
|
end
|
|
|
|
minetest.register_craftitem("mcl_maps: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_usagehelp = S("Rightclick to create a filled map (which can't be stacked anymore)."),
|
|
inventory_image = "mcl_maps_map_empty.png",
|
|
on_place = make_filled_map,
|
|
on_secondary_use = make_filled_map,
|
|
stack_max = 64,
|
|
})
|
|
|
|
minetest.register_craftitem("mcl_maps:filled_map", {
|
|
description = S("Map"),
|
|
_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_usagehelp = S("Hold the map in your hand. This will display a map on your screen."),
|
|
groups = {tool = 1, not_in_creative_inventory = 1},
|
|
inventory_image = "mcl_maps_map_filled.png^(mcl_maps_map_filled_markings.png^[colorize:#000000)",
|
|
stack_max = 64,
|
|
})
|
|
|
|
tt.register_priority_snippet(function(itemstring, _, itemstack)
|
|
if itemstack and itemstring == "mcl_maps:filled_map" then
|
|
local id = itemstack:get_meta():get_string("mcl_maps:id")
|
|
if id ~= "" then
|
|
return "#" .. id, mcl_colors.GRAY
|
|
end
|
|
end
|
|
end)
|
|
|
|
minetest.register_craft({
|
|
output = "mcl_maps:empty_map",
|
|
recipe = {
|
|
{ "mcl_core:paper", "mcl_core:paper", "mcl_core:paper" },
|
|
{ "mcl_core:paper", "group:compass", "mcl_core:paper" },
|
|
{ "mcl_core:paper", "mcl_core:paper", "mcl_core:paper" },
|
|
}
|
|
})
|
|
|
|
minetest.register_craft({
|
|
type = "shapeless",
|
|
output = "mcl_maps:filled_map 2",
|
|
recipe = {"mcl_maps:filled_map", "mcl_maps:empty_map"},
|
|
})
|
|
|
|
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
|
|
if itemstack:get_name() == "mcl_maps:filled_map" then
|
|
for _, stack in pairs(old_craft_grid) do
|
|
if stack:get_name() == "mcl_maps:filled_map" then
|
|
itemstack:get_meta():from_table(stack:get_meta():to_table())
|
|
return itemstack
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
local maps = {}
|
|
local huds = {}
|
|
|
|
minetest.register_on_joinplayer(function(player)
|
|
huds[player] = player:hud_add({
|
|
hud_elem_type = "image",
|
|
text = "blank.png",
|
|
position = {x = 1, y = 1},
|
|
alignment = {x = -1, y = -1},
|
|
offset = {x = -125, y = -50},
|
|
scale = {x = 2, y = 2},
|
|
})
|
|
end)
|
|
|
|
minetest.register_on_leaveplayer(function(player)
|
|
maps[player] = nil
|
|
huds[player] = nil
|
|
end)
|
|
|
|
local function is_holding_map(player)
|
|
local wield = player:get_wielded_item()
|
|
if wield:get_name() ~= "mcl_maps:filled_map" then
|
|
return
|
|
end
|
|
local meta = wield:get_meta()
|
|
local texture = meta:get_string("mcl_maps:texture")
|
|
if texture == "" then
|
|
return
|
|
end
|
|
if loaded_maps[texture] then
|
|
return texture
|
|
end
|
|
local path = meta:get_string("mcl_maps:texture_path")
|
|
if not creating_maps[texture] and not loading_maps[texture] then
|
|
loading_maps[texture] = true
|
|
local player_name = player:get_player_name()
|
|
minetest.dynamic_add_media(path, function(finished_name)
|
|
if player_name == finished_name then
|
|
loading_maps[texture] = false
|
|
loaded_maps[texture] = true
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
|
|
minetest.register_globalstep(function(dtime)
|
|
for _, player in pairs(minetest.get_connected_players()) do
|
|
local texture = is_holding_map(player)
|
|
if texture then
|
|
if texture ~= maps[player] then
|
|
player:hud_change(huds[player], "text", texture)
|
|
maps[player] = texture
|
|
end
|
|
elseif maps[player] then
|
|
player:hud_change(huds[player], "text", "blank.png")
|
|
maps[player] = nil
|
|
end
|
|
end
|
|
end)
|