From ade84c374deee34e4f5d5bd419f9863bbb05d019 Mon Sep 17 00:00:00 2001 From: Hugues Ross Date: Sat, 28 Mar 2020 09:51:38 -0400 Subject: [PATCH] First draft marker editor in the map formspec --- init.lua | 2 + items.lua | 121 +++++++++++++++++++++++++++++++------------- map_api.lua | 4 ++ marker_formspec.lua | 26 ++++++++++ 4 files changed, 119 insertions(+), 34 deletions(-) create mode 100644 marker_formspec.lua diff --git a/init.lua b/init.lua index 52ebde1..bda3045 100644 --- a/init.lua +++ b/init.lua @@ -8,6 +8,7 @@ _cartographer = { CHUNK_SIZE = 16, biome_lookup = {}, + marker_count = 0, marker_lookup = {}, maps = minetest.deserialize(mod_storage:get_string("maps")) or {}, next_map_id = mod_storage:get_int("next_map_id"), @@ -54,6 +55,7 @@ dofile(modpath .. "/commands.lua"); dofile(modpath .. "/scanner.lua"); dofile(modpath .. "/map_api.lua"); dofile(modpath .. "/map_formspec.lua"); +dofile(modpath .. "/marker_formspec.lua"); dofile(modpath .. "/items.lua"); dofile(modpath .. "/table.lua"); diff --git a/items.lua b/items.lua index ebf1260..458a4be 100644 --- a/items.lua +++ b/items.lua @@ -1,4 +1,31 @@ -local function map_from_meta(meta, player_x, player_y) +-- The list of players looking at maps, and the map IDs that they're looking at +local player_maps = {}; + +-- Show a map to a player from the ID +-- id: The map ID +-- player_x: The X position (in map coordinates) +-- player_z: The Z position (in map coordinates) +-- player_name: The name of the player to show to +local function show_map_id_formspec(id, player_x, player_z, player_name) + cartographer.fill_local(id, player_x, player_z); + + player_maps[player_name] = id; + local map = cartographer.get_map(id); + + local formspec = cartographer.get_map_formspec_map(data, map, player_x, player_z); + if _cartographer.marker_count > 0 then + formspec = formspec .. string.format("style_type[button,image_button;noclip=true;border=true] container[%f,0.5]", map.w * 0.25) -- TODO: Don't assume map.w * 0.25 + .. _cartographer.generate_marker_formspec(cartographer.get_marker(map, player_x, player_z), map.detail) + .. "container_end[]"; + end + minetest.show_formspec(player_name, "cartographer:map", formspec); +end + +-- Create a map from metadata, and assign the ID to the metadata +-- meta: A metadata object containing the map ID +-- player_x: The X position (in map coordinates) +-- player_z: The Z position (in map coordinates) +local function map_from_meta(meta, player_x, player_z) local size = meta:get_int("cartographer:size") or 10; local detail = meta:get_int("cartographer:detail") or 1; local scale = meta:get_int("cartographer:scale") or 1; @@ -6,7 +33,7 @@ local function map_from_meta(meta, player_x, player_y) local total_size = size * scale; local map_x = math.floor((player_x + 10)/total_size) * total_size - 10 - local map_y = math.floor((player_y + 10)/total_size) * total_size - 10; + local map_y = math.floor((player_z + 10)/total_size) * total_size - 10; local id = cartographer.create_map(map_x, map_y, size, size, false, detail, scale); @@ -16,6 +43,51 @@ local function map_from_meta(meta, player_x, player_y) return id; end +-- Show a map to a player from metadata, creating it if possible +-- meta: A metadata object containing the map ID +-- player: The player to show the map to +local function show_map_meta(meta, player) + local pos = player:get_pos(); + local player_x = tochunk(pos.x); + local player_z = tochunk(pos.z); + + local id = meta:get_int("cartographer:map_id"); + if id == 0 then + id = map_from_meta(meta, player_x, player_z); + end + + show_map_id_formspec(id, player_x, player_z, player:get_player_name()); +end + +-- Called when a player sends input to the server from a formspec +-- This callback handles player input in the map formspec, for editing markers +-- player: The player who sent the input +-- name: The formspec name +-- fields: A table containing the input +minetest.register_on_player_receive_fields(function(player, name, fields) + if name == "cartographer:map" then + local map = cartographer.get_map(player_maps[player:get_player_name()]); + if not map then + return; + end + + for k,v in pairs(fields) do + local marker = k:match("marker%-(.+)"); + minetest.chat_send_all(k .. ": " .. tostring(marker)); + if marker or k == "clear_marker" then + local pos = player:get_pos(); + local player_x = tochunk(pos.x); + local player_z = tochunk(pos.z); + cartographer.set_marker(map, player_x, player_z, marker); + + show_map_id_formspec(player_maps[player:get_player_name()], player_x, player_z, player:get_player_name()); + elseif k == "quit" then + player_maps[player:get_player_name()] = nil; + end + end + end +end); + -- The map item/node minetest.register_node("cartographer:map", { description = "Map", @@ -33,25 +105,6 @@ minetest.register_node("cartographer:map", { {-0.5, -0.5, -0.5, 0.5, -7 / 16, 0.5}, }, }, - on_use = function(stack, player, _) - local pos = player:get_pos(); - local name = player:get_player_name(); - - local player_x = tochunk(pos.x); - local player_y = tochunk(pos.z); - - local meta = stack:get_meta(); - local id = meta:get_int("cartographer:map_id"); - if id == 0 then - id = map_from_meta(meta, player_x, player_y); - end - - cartographer.fill_local(id, player_x, player_y); - - minetest.show_formspec(player:get_player_name(), "map", cartographer.get_map_formspec_map(data, cartographer.get_map(id), player_x, player_y)); - - return stack; - end, -- Called when this node is placed in the world. Copies map data from the -- item to the node. @@ -68,20 +121,20 @@ minetest.register_node("cartographer:map", { return false; end, - on_rightclick = function(pos, node, player, itemstack, pointed_thing) - local meta = minetest.get_meta(pos); + -- Called when a player right-clicks this node. Display's the map's + -- content, creating it if it doesn't exist. + -- pos: The position of the node + -- player: The player that right-clicked the node + on_rightclick = function(pos, _, player) + show_map_meta(minetest.get_meta(pos), player); + end, - local player_x = tochunk(pos.x); - local player_y = tochunk(pos.z); - - local id = meta:get_int("cartographer:map_id"); - if id == 0 then - id = map_from_meta(meta, player_x, player_y); - end - - cartographer.fill_local(id, player_x, player_y); - - minetest.show_formspec(player:get_player_name(), "map", cartographer.get_map_formspec_map(data, cartographer.get_map(id), player_x, player_y)); + -- Called when a player uses this item. Displays the map's content, + -- creating it if it doesn't exist. + -- stack: The itemstack + -- player: The player that used the item + on_use = function(stack, player) + show_map_meta(stack:get_meta(), player); end, }); diff --git a/map_api.lua b/map_api.lua index 09f3e84..3df2911 100644 --- a/map_api.lua +++ b/map_api.lua @@ -141,6 +141,10 @@ end -- These should correspond with detail levels, -- any detail level past the length of the table will return the last texture function cartographer.register_marker(id, name, textures) + if not _cartographer.marker_lookup then + _cartographer.marker_count = _cartographer.marker_count + 1; + end + _cartographer.marker_lookup[id] = { name = name, textures = textures, diff --git a/marker_formspec.lua b/marker_formspec.lua new file mode 100644 index 0000000..04e0de4 --- /dev/null +++ b/marker_formspec.lua @@ -0,0 +1,26 @@ +-- Generates formspec data for the map marker editor +-- selected_id: The id of the currently selected marker, or nil if no marker is +-- selected +-- detail: The map's detail level +-- +-- Returns a formspec string for use in containers +function _cartographer.generate_marker_formspec(selected_id, detail) + local fs = "button[0,0;0.5,0.5;clear_marker;x]"; + + if selected_id then + fs = fs .. string.format("style[marker-%s;bgcolor=blue]", selected_id); + end + + -- TODO: Support pagination if _cartographer.marker_count is too high + local i = 0; + for id in pairs(_cartographer.marker_lookup) do + fs = fs .. string.format("image_button[%f,%f;0.5,0.5;%s.png;marker-%s;]", + i % 5 * 0.5, + math.floor(i / 5) * 0.5 + 0.5, + cartographer.get_marker_texture(id, detail), + id); + + i = i + 1; + end + return fs; +end