From 33f883ecb73263cb5ab0ea3be2acf184d4d4211c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikita=20Wi=C5=9Bniewski?= <rudzik8@protonmail.com> Date: Sun, 2 Mar 2025 15:23:55 +0700 Subject: [PATCH] mcl_maps: Code clean-up, localize more functions --- mods/ITEMS/mcl_maps/init.lua | 104 ++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/mods/ITEMS/mcl_maps/init.lua b/mods/ITEMS/mcl_maps/init.lua index 9f0245c3f..c82e9593a 100644 --- a/mods/ITEMS/mcl_maps/init.lua +++ b/mods/ITEMS/mcl_maps/init.lua @@ -7,7 +7,7 @@ -- Check for engine updates that allow improvements mcl_maps = {} -mcl_maps.max_zoom = (tonumber(core.settings:get("vl_maps_max_zoom")) or 3) +mcl_maps.max_zoom = tonumber(core.settings:get("vl_maps_max_zoom")) or 3 mcl_maps.enable_maps = core.settings:get_bool("enable_real_maps", true) mcl_maps.allow_nether_maps = core.settings:get_bool("vl_maps_allow_nether", true) mcl_maps.map_allow_overlap = core.settings:get_bool("vl_maps_allow_overlap", true) -- 50% overlap allowed in each level @@ -20,8 +20,9 @@ local S = core.get_translator(modname) local vector = vector local table = table local pairs = pairs -local min, max, round, floor, ceil = math.min, math.max, math.round, math.floor, math.ceil -local HALF_PI = math.pi * 0.5 +local min, max, round, floor, ceil, abs, pi = math.min, math.max, math.round, math.floor, math.ceil, math.abs, math.pi +local char = string.char +local concat = table.concat local pos_to_string = core.pos_to_string local string_to_pos = core.string_to_pos @@ -49,8 +50,8 @@ local texture_colors = load_json_file("colors") local maps_generating, maps_loading = {}, {} -- Main map generation function, called from emerge -local function do_generate_map(id, minp, maxp, callback, t1) - local t2 = os.clock() +local function do_generate_map(id, minp, maxp, callback--[[, t1]]) + --local t2 = os.clock() -- Generate a (usually) 128x128 linear array for the image local pixels = {} local xsize, zsize = maxp.x - minp.x + 1, maxp.z - minp.z + 1 @@ -61,14 +62,14 @@ local function do_generate_map(id, minp, maxp, callback, t1) local last_height for x = 1, xsize, xstep do local map_x = minp.x + x - 1 - -- color aggregate and height information (for 3D effect) + -- Color aggregate and height information (for 3D effect) local cagg, height = {0, 0, 0, 0}, nil local solid_under_air = -1 -- anything but air, actually for map_y = maxp.y, minp.y, -1 do local nodename, _, param2 = get_node_name_raw(map_x, map_y, map_z) if nodename ~= "air" then local color = texture_colors[nodename] - -- use param2 if available: + -- Use param2 if available: if color and type(color[1]) == "table" then color = color[param2 + 1] or color[1] end @@ -89,10 +90,10 @@ local function do_generate_map(id, minp, maxp, callback, t1) cagg[4] = alpha end - -- ground estimate with transparent blocks + -- Ground estimate with transparent blocks if alpha > 140 and not height then height = map_y end if alpha >= 250 and solid_under_air > 0 then - -- adjust color to give a 3d effect + -- Adjust color to give a 3D effect if last_height and height then local dheight = max(-48, min((height - last_height) * 8, 48)) cagg[1] = cagg[1] + dheight @@ -107,21 +108,21 @@ local function do_generate_map(id, minp, maxp, callback, t1) solid_under_air = 0 -- first air end end - -- clamp colors values to 0:255 for PNG - -- because 3d height effect may exceed this range + -- Clamp colors values to 0..255 for PNG + -- (because 3D height effect may exceed this range) cagg[1] = max(0, min(round(cagg[1]), 255)) cagg[2] = max(0, min(round(cagg[2]), 255)) cagg[3] = max(0, min(round(cagg[3]), 255)) cagg[4] = max(0, min(round(cagg[4]), 255)) - pixels[#pixels + 1] = string.char(cagg[1], cagg[2], cagg[3], cagg[4]) + pixels[#pixels + 1] = char(cagg[1], cagg[2], cagg[3], cagg[4]) last_height = height end end -- Save as png texture - local t3 = os.clock() + --local t3 = os.clock() local filename = map_textures_path .. "mcl_maps_map_" .. id .. ".png" - core.safe_file_write(filename, core.encode_png(xsize / xstep, zsize / zstep, table.concat(pixels))) - local t4 = os.clock() + core.safe_file_write(filename, core.encode_png(xsize / xstep, zsize / zstep, concat(pixels))) + --local t4 = os.clock() --core.log("action", string.format("Completed map %s after %.2fms (%.2fms emerge, %.2fms map, %.2fms png)", id, (os.clock()-t1)*1000, (t2-t1)*1000, (t3-t2)*1000, (t4-t3)*1000)) maps_generating[id] = nil if callback then callback(id, filename) end @@ -131,13 +132,13 @@ end local function emerge_generate_map(id, minp, maxp, callback) if maps_generating[id] then return end maps_generating[id] = true - local t1 = os.clock() + --local t1 = os.clock() core.emerge_area(minp, maxp, function(blockpos, action, calls_remaining) if calls_remaining > 0 then return end - -- do a DOUBLE emerge to give mapgen the chance to place structures triggered by the initial emerge + -- Do a DOUBLE emerge to give mapgen the chance to place structures triggered by the initial emerge core.emerge_area(minp, maxp, function(blockpos, action, calls_remaining) if calls_remaining > 0 then return end - do_generate_map(id, minp, maxp, callback, t1) + do_generate_map(id, minp, maxp, callback--[[, t1]]) end) end) end @@ -148,8 +149,8 @@ function mcl_maps.convert_legacy_map(itemstack, meta) local minp = string_to_pos(meta:get_string("mcl_maps:minp")) local maxp = string_to_pos(meta:get_string("mcl_maps:maxp")) - cx = minp.x + 64 - cz = minp.z + 64 + local cx = minp.x + 64 + local cz = minp.z + 64 meta:set_int("mcl_maps:cx", cx) meta:set_int("mcl_maps:cz", cz) meta:set_int("mcl_maps:zoom", 1) @@ -161,7 +162,7 @@ end local function configure_map(itemstack, cx, dim, cz, zoom, callback) zoom = max(zoom or 1, 1) -- Texture size is 128 - local size = 64 * (2^zoom) + local size = 64 * (2 ^ zoom) local halfsize = size / 2 local meta = itemstack:get_meta() @@ -176,7 +177,7 @@ local function configure_map(itemstack, cx, dim, cz, zoom, callback) cz = minp.z + halfsize end - -- If enabled, round to halfsize grid, otherwise to size grid. + -- If enabled, round to halfsize grid, otherwise to size grid if mcl_maps.map_allow_overlap then cx, cz = (floor(cx / halfsize) + 0.5) * halfsize, (floor(cz / halfsize) + 0.5) * halfsize else @@ -204,7 +205,7 @@ local function configure_map(itemstack, cx, dim, cz, zoom, callback) -- File name conventions, including a unique number in case someone maps the same area twice (old and new) local seq = storage:get_int("next_id") storage:set_int("next_id", seq + 1) - local id = table.concat({cx, dim, cz, zoom, seq}, "_") + local id = concat({cx, dim, cz, zoom, seq}, "_") local minp = vector.new(cx - halfsize, miny, cz - halfsize) local maxp = vector.new(cx + halfsize - 1, maxy, cz + halfsize - 1) @@ -224,7 +225,7 @@ end function mcl_maps.load_map(id, callback) if id == "" or maps_generating[id] then return false end - -- Use a legacy tga map texture if present + -- Use a legacy TGA map texture if present local texture = "mcl_maps_map_texture_"..id..".tga" local f = io.open(map_textures_path .. texture, "r") if f then @@ -238,7 +239,7 @@ function mcl_maps.load_map(id, callback) return texture end - -- core.dynamic_add_media() never blocks in Minetest 5.5, callback runs after load + -- core.dynamic_add_media() never blocks in Luanti 5.5, callback runs after load -- TODO: send only to the player that needs it! dynamic_add_media(map_textures_path .. texture, function() if not maps_loading[id] then -- avoid repeated callbacks @@ -276,10 +277,10 @@ local function fill_map(itemstack, placer, pointed_thing) if mcl_maps.enable_maps then mcl_title.set(placer, "actionbar", {text=S("It may take a moment for the map to be ready."), color="gold", stay=5*20}) - local callback = function(id, filename) + local new_map = mcl_maps.create_map(placer:get_pos(), 0, function(id, filename) mcl_title.set(placer, "actionbar", {text=S("The new map is now ready."), color="green", stay=3*20}) - end - local new_map = mcl_maps.create_map(placer:get_pos(), 0, callback) + end) + itemstack:take_item() if itemstack:is_empty() then return new_map end local inv = placer:get_inventory() @@ -299,7 +300,15 @@ core.register_craftitem("mcl_maps:empty_map", { inventory_image = "mcl_maps_map_empty.png", on_place = fill_map, on_secondary_use = fill_map, - stack_max = 64, +}) + +core.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"}, + } }) local filled_def = { @@ -308,12 +317,13 @@ local filled_def = { _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."), inventory_image = "mcl_maps_map_filled.png^(mcl_maps_map_filled_markings.png^[colorize:#000000)", - stack_max = 64, groups = {not_in_creative_inventory = 1, filled_map = 1, tool = 1}, } core.register_craftitem("mcl_maps:filled_map", filled_def) +-- Only nodes can have meshes, which means that all player hands are nodes +-- Thus, to render a map over a player hand, we have to register nodes for this too local filled_wield_def = table.copy(filled_def) filled_wield_def.use_texture_alpha = core.features.use_texture_alpha_string_modes and "opaque" or false filled_wield_def.visual_scale = 1 @@ -325,7 +335,6 @@ filled_wield_def.on_place = mcl_util.call_on_rightclick filled_wield_def._mcl_wieldview_item = "mcl_maps:filled_map" local mcl_skins_enabled = core.global_exists("mcl_skins") - if mcl_skins_enabled then -- Generate a node for every skin local list = mcl_skins.get_skin_list() @@ -351,10 +360,11 @@ else core.register_node("mcl_maps:filled_map_hand", filled_wield_def) end +-- Avoid dropping detached hands with held maps local old_add_item = core.add_item function core.add_item(pos, stack) if not pos then - core.log("warning", "Trying to add item with missing pos: " .. tostring(stack)) + core.log("warning", "Trying to add item with missing pos: " .. dump(stack)) return end stack = ItemStack(stack) @@ -364,6 +374,7 @@ function core.add_item(pos, stack) return old_add_item(pos, stack) end +-- Zoom level tooltip tt.register_priority_snippet(function(itemstring, _, itemstack) if itemstack and get_item_group(itemstring, "filled_map") > 0 then local zoom = itemstack:get_meta():get_string("mcl_maps:zoom") @@ -373,15 +384,7 @@ tt.register_priority_snippet(function(itemstring, _, itemstack) end end) -core.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"}, - } -}) - +-- Support copying maps as a crafting recipe core.register_craft({ type = "shapeless", output = "mcl_maps:filled_map 2", @@ -402,6 +405,7 @@ end core.register_on_craft(on_craft) core.register_craft_predict(on_craft) +-- Render handheld maps as part of HUD overlay local maps = {} local huds = {} @@ -451,7 +455,7 @@ core.register_globalstep(function(dtime) local pos = player:get_pos() -- was: vector.round(player:get_pos()) local light = get_node_light(vector.offset(pos, 0, 0.5, 0)) or 0 - -- change map only when necessary + -- Change map only when necessary if not maps[player] or texture ~= maps[player][1] or light ~= maps[player][4] then local light_overlay = "^[colorize:black:" .. 255 - (light * 17) player:hud_change(hud.map, "text", "[combine:140x140:0,0=mcl_maps_map_background.png:6,6=" .. texture .. light_overlay) @@ -461,33 +465,33 @@ core.register_globalstep(function(dtime) maps[player] = {texture, minp, maxp, light} end - -- map overlay with player position + -- Map overlay with player position local minp, maxp = maps[player][2], maps[player][3] -- Use dots when outside of map, indicate direction local marker if pos.x < minp.x then - marker = math.abs(minp.x - pos.x) < 256 and "mcl_maps_player_dot_large.png" or "mcl_maps_player_dot.png" + marker = abs(minp.x - pos.x) < 256 and "mcl_maps_player_dot_large.png" or "mcl_maps_player_dot.png" pos.x = minp.x elseif pos.x > maxp.x then - marker = math.abs(pos.x - maxp.x) < 256 and "mcl_maps_player_dot_large.png" or "mcl_maps_player_dot.png" + marker = abs(pos.x - maxp.x) < 256 and "mcl_maps_player_dot_large.png" or "mcl_maps_player_dot.png" pos.x = maxp.x end - -- we never override the small marker - -- yes, this is a literal corner case + -- Never override the small marker if pos.z < minp.z then - marker = (math.abs(minp.z - pos.z) < 256 and marker ~= "mcl_maps_player_dot.png") + marker = (abs(minp.z - pos.z) < 256 and marker ~= "mcl_maps_player_dot.png") and "mcl_maps_player_dot_large.png" or "mcl_maps_player_dot.png" pos.z = minp.z elseif pos.z > maxp.z then - marker = (math.abs(pos.z - maxp.z) < 256 and marker ~= "mcl_maps_player_dot.png") + marker = (abs(pos.z - maxp.z) < 256 and marker ~= "mcl_maps_player_dot.png") and "mcl_maps_player_dot_large.png" or "mcl_maps_player_dot.png" pos.z = maxp.z end + -- Default to yaw-based player arrow if not marker then - local yaw = (math.floor(player:get_look_horizontal() * 180 / math.pi / 45 + 0.5) % 8) * 45 + local yaw = (floor(player:get_look_horizontal() * 180 / pi / 45 + 0.5) % 8) * 45 if yaw == 0 or yaw == 90 or yaw == 180 or yaw == 270 then marker = "mcl_maps_player_arrow.png^[transformR" .. yaw else