1333 lines
32 KiB
Lua
1333 lines
32 KiB
Lua
-- a mod for displaying Minetest maps
|
|
-- David Mckenzie 2014
|
|
-- License: WTFPL v2
|
|
--
|
|
-- updateInterval for automatic regeneration of maps can be changed on line 53 (updateInterval = x)
|
|
|
|
local mapitFormspecBasic = ""
|
|
local mapitFormspecTP = ""
|
|
local mapitFormspecMouse = ""
|
|
local mapitPlayerName = ""
|
|
local mapitMapState = ""
|
|
local mapitwFormFu = 0
|
|
|
|
local curLine = 0
|
|
local mapitMapState = ""
|
|
local butX=0
|
|
local butZ=0
|
|
local worldStepWuX = 0
|
|
local worldStepWuZ = 0
|
|
local pngMinWuX = 0
|
|
local pngMaxWuZ = 0
|
|
|
|
local inv_mod = nil
|
|
|
|
function file_exists(name)
|
|
local f=io.open(name,"r")
|
|
if f~=nil then io.close(f) return true else return false end
|
|
end
|
|
|
|
function file_copy(source, target)
|
|
local infile = io.open(source, "r")
|
|
local instr = infile:read("*a")
|
|
infile:close()
|
|
|
|
local outfile = io.open(target, "w")
|
|
outfile:write(instr)
|
|
outfile:close()
|
|
end
|
|
|
|
local updateMap = function(forceUpdate)
|
|
if forceUpdate == nil then forceUpdate = false end
|
|
|
|
-- GET NAMES AND PATHS TO ENSURE CORRECT MAP IS USED
|
|
local worldPath = minetest.get_worldpath()
|
|
local worldName = string.gsub(worldPath, "(.*worlds.)(.*)", "%2")
|
|
local worldsqlName = worldPath.. "/map.sqlite"
|
|
if not file_exists(worldsqlName) then return 0 end
|
|
|
|
local curModPath = minetest.get_modpath('mapit')
|
|
local texPath = curModPath.. "/textures/"
|
|
local dummyFilePName = texPath.. "mapit.png"
|
|
local mapFileName = worldName:gsub("%s+", "_").. ".png"
|
|
local thumbFileName = worldName:gsub("%s+", "_").. "_thumb.png"
|
|
local mapFilePName = texPath.. mapFileName
|
|
local thumbFilePName = texPath.. thumbFileName
|
|
local mapitHistoryPName = texPath.. "mapitHistory.txt"
|
|
|
|
|
|
--this should never be required
|
|
--os.execute("mkdir \"" .. texPath "\"") --create directory if it does not already exist
|
|
|
|
-- if there's a failure of the python script, at least there'll be a dummy file
|
|
if not file_exists(mapFilePName) then file_copy(dummyFilePName, mapFilePName) end
|
|
if not file_exists(thumbFilePName) then file_copy(dummyFilePName, thumbFilePName) end
|
|
|
|
local updateInterval = 7*24*60*60 -- number of seconds between updates
|
|
|
|
-- update the history to save the generation date
|
|
local lastUpdateTime = 0
|
|
local fh = io.open(mapitHistoryPName, "r")
|
|
local fileStr = ""
|
|
while true do
|
|
curLine = fh.read(fh)
|
|
if not curLine then break end
|
|
local cWN, lUT = curLine:match("(%w+)%s=%s(%d+)")
|
|
-- if cWN == nil then cWN = ""
|
|
-- if lUT == nil then lUT = 0
|
|
-- print(cWN)
|
|
-- print(lUT)
|
|
if cWN == (worldName) then
|
|
lastUpdateTime = tonumber(lUT)
|
|
else
|
|
fileStr = fileStr.. curLine
|
|
end
|
|
-- print (line)
|
|
end
|
|
|
|
-- get last modified time direct from the file
|
|
--for this to work, you will need to have installed luaFileSystem
|
|
--sudo luarocks install luafilesystem
|
|
--sudo apt-get install luarocks
|
|
-- local lfsExists, lfs = pcall(function () require "lfs" end)
|
|
local lfsExists, lfs = pcall(require, "lfs")
|
|
if lfsExists then
|
|
-- local lfs = require "lfs"
|
|
local lastUpdateTime = lfs.attributes( mapFilePName ).modification
|
|
end
|
|
|
|
if (lastUpdateTime < os.time()-updateInterval) or forceUpdate then
|
|
fileStr = fileStr.. worldName.. " = ".. os.time().. "\r\n"
|
|
fh:close()
|
|
|
|
-- run the python script to generate the map (could be run in background by appending an '&' to the string, but texture might be corrupted or out of date for current load)
|
|
local osx = "python \"".. curModPath.. "/".. "minetestmapper-numpy.py\" --pixelspernode 1 --drawscale \"".. worldPath.. "\" \"".. mapFilePName.. "\""
|
|
os.execute(osx)
|
|
print("mapit: Updated map for ".. worldName)
|
|
|
|
fh = io.open(mapitHistoryPName, "w")
|
|
fh:write(fileStr)
|
|
else
|
|
print("mapit: Map update not required for ".. worldName)
|
|
end
|
|
fh:close()
|
|
-- print (fileStr)
|
|
return
|
|
end
|
|
|
|
updateMap()
|
|
|
|
minetest.register_node('mapit:mapblock', {
|
|
-- ideally would have an automatic way of creating a face for the block which was correctly dimensions and aspect ratio
|
|
-- currently using a large .png introduces sig delay due to time drawing the faces
|
|
description = "Map Block",
|
|
tiles = { string.gsub(string.gsub(minetest.get_worldpath(), "(.*worlds.)(.*)", "%2"),"%s+", "_").."_thumb.png",
|
|
string.gsub(string.gsub(minetest.get_worldpath(), "(.*worlds.)(.*)", "%2"),"%s+", "_").."_thumb.png",
|
|
string.gsub(string.gsub(minetest.get_worldpath(), "(.*worlds.)(.*)", "%2"),"%s+", "_").."_thumb.png",
|
|
string.gsub(string.gsub(minetest.get_worldpath(), "(.*worlds.)(.*)", "%2"),"%s+", "_").."_thumb.png",
|
|
string.gsub(string.gsub(minetest.get_worldpath(), "(.*worlds.)(.*)", "%2"),"%s+", "_").."_thumb.png",
|
|
string.gsub(string.gsub(minetest.get_worldpath(), "(.*worlds.)(.*)", "%2"),"%s+", "_").."_thumb.png",
|
|
},
|
|
sunlight_propagates = false,
|
|
paramtype = "light",
|
|
walkable = true,
|
|
groups = {cracky=3},
|
|
})
|
|
|
|
|
|
minetest.register_node('mapit:teleportWaypoint', {
|
|
description = "Teleport Point",
|
|
drawtype = "plantlike",
|
|
inventory_image = "apophysisFlame.png",
|
|
wield_image = "apophysisFlame.png",
|
|
tiles = { "apophysisFlame.png" },
|
|
sunlight_propagates = false,
|
|
paramtype = "light",
|
|
walkable = true,
|
|
-- sounds = default.node_sound_leaves_defaults(),
|
|
groups = {cracky=3},
|
|
})
|
|
|
|
|
|
minetest.register_tool("mapit:maptool", {
|
|
description = "Map Tool",
|
|
inventory_image = string.gsub(string.gsub(minetest.get_worldpath(), "(.*worlds.)(.*)", "%2"),"%s+", "_")..".png",
|
|
on_use = function(itemstack, user, pointed_thing)
|
|
map_handler_maptool(itemstack,user,pointed_thing)
|
|
end,
|
|
})
|
|
function map_handler_maptool (itemstack, user, pointed_thing)
|
|
mapitPlayerName=user:get_player_name()
|
|
generateMapStrings(mapitPlayerName)
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecBasic)
|
|
end
|
|
|
|
function generateMapStrings()
|
|
-- suffixes: Fu = form units; Wu = world units; Pp = porportion; Px = pixels
|
|
print(name)
|
|
|
|
local player = minetest.get_player_by_name(mapitPlayerName)
|
|
print(mapitPlayerName)
|
|
print(player)
|
|
|
|
|
|
local posWu = player:getpos()
|
|
local map
|
|
local yaw
|
|
local rotate = 0
|
|
local facing = "Not set" -- direction player is facing (NSEW)
|
|
local wFormFu
|
|
local hFormFu
|
|
local width, height
|
|
|
|
-- globals
|
|
mapitMapState = ""
|
|
butX=-1
|
|
butZ=-1
|
|
local wPNGPx, hPNGPx, pngRegionWu, borderPx, pixPerNodePx
|
|
|
|
|
|
-- posWu.y = posWu.y + 1
|
|
yaw = player:get_look_yaw()
|
|
if yaw ~= nil then
|
|
-- Find angle player facing to enable rotation of position arrow based on yaw.
|
|
yaw = math.deg(yaw)
|
|
yaw = math.fmod (yaw, 360)
|
|
if yaw<0 then yaw = 360 + yaw end
|
|
if yaw>360 then yaw = yaw - 360 end
|
|
if yaw < 90 then
|
|
rotate = 90
|
|
elseif yaw < 180 then
|
|
rotate = 180
|
|
elseif yaw < 270 then
|
|
rotate = 270
|
|
else
|
|
rotate = 0
|
|
end
|
|
if yaw>315 or yaw<=45 then
|
|
facing="East"
|
|
elseif yaw>45 and yaw<=135 then
|
|
facing="South"
|
|
elseif yaw>135 and yaw<=225 then
|
|
facing="West"
|
|
elseif yaw>225 and yaw<=315 then
|
|
facing="North"
|
|
end
|
|
|
|
yaw = math.fmod(yaw, 90)
|
|
yaw = math.floor(yaw / 10) * 10
|
|
end
|
|
|
|
-- Bizarrely yaw seems to vary with world, so direction is incorrect (and the pos values are listed anyway so unnecessary).
|
|
-- minetest.chat_send_player(mapitPlayerName, "mapit: Current Loc: X: ".. math.floor(posWu.x).. ", Y:".. math.floor(posWu.y).. ", Z:".. math.floor(posWu.z).. ", Facing:".. facing, false)
|
|
|
|
|
|
-- GET NAMES AND PATHS TO ENSURE CORRECT MAP IS USED
|
|
local worldPath = minetest.get_worldpath()
|
|
local worldName = string.gsub(worldPath, "(.*worlds.)(.*)", "%2")
|
|
|
|
local curModPath = minetest.get_modpath('mapit')
|
|
local mapFileName = curModPath.. "/textures/".. worldName:gsub("%s+", "_").. ".png"
|
|
|
|
-- PARSE THE PNG TO EXTRACT MAP LOCATIONS
|
|
wPNGPx, hPNGPx, pngRegionWu, pngMinWuX, pngMaxWuZ, borderPx, pixPerNodePx = parse_png (mapFileName)
|
|
|
|
|
|
-- CALCULATE WORLD AND FORM DIMENSIONS AND PROPORTIONS
|
|
local wWorldWu=(wPNGPx-borderPx)/pixPerNodePx
|
|
local hWorldWu=(hPNGPx-borderPx)/pixPerNodePx
|
|
local wWorldUnitPp= pixPerNodePx/wPNGPx
|
|
local hWorldUnitPp= pixPerNodePx/hPNGPx
|
|
local lBorderPp = borderPx/(wPNGPx-borderPx)
|
|
local tBorderPp = borderPx/(hPNGPx-borderPx)
|
|
|
|
-- determine required form width to maintain PNG aspect ratio (known z/height)
|
|
local aspectRatio = wPNGPx/hPNGPx
|
|
-- print(aspectRatio)
|
|
if aspectRatio > 1.35 then
|
|
wFormFu = 16
|
|
hFormFu = (wFormFu-1)/aspectRatio
|
|
else
|
|
hFormFu = 11 -- height of the form
|
|
wFormFu = hFormFu*aspectRatio +1
|
|
end
|
|
local wMapFu = hFormFu*aspectRatio
|
|
local hMapFu = hFormFu
|
|
local lBorderFu =wMapFu * lBorderPp
|
|
local tBorderFu = hMapFu * tBorderPp
|
|
|
|
|
|
-- SCALE AND LOCATE ARROW
|
|
local arrowSizeFuZ=0.4
|
|
local arrowSizeFuX=0.4 --*aspectRatio
|
|
-- Distance from world location at PNG origin to player current location (in WORLD UNITS)
|
|
local pngOriginToPlayerWuX = posWu.x - pngMinWuX -- x axis is more POSITIVE away from origin
|
|
local pngOriginToPlayerWuZ = pngMaxWuZ - posWu.z -- z axis is more NEGATIVE away from origin
|
|
-- Distance from world location at PNG origin to player current location (in PIXELS)
|
|
local playerLocFuX = wMapFu*pngOriginToPlayerWuX*wWorldUnitPp -- location for middle of arrow icon (in pixels)
|
|
local playerLocFuZ = hMapFu*pngOriginToPlayerWuZ*hWorldUnitPp -- location for middle of arrow icon (in pixels)
|
|
-- location of arrow (in form units)
|
|
local ArrowLocFuX = playerLocFuX + lBorderFu - arrowSizeFuX/2
|
|
local ArrowLocFuZ = playerLocFuZ + tBorderFu
|
|
-- generate the appropriate string for the arrow (to ensure rotation is correct)
|
|
local imstr
|
|
if rotate ~= 0 then
|
|
imstr = "image["..ArrowLocFuX..","..ArrowLocFuZ..";"..arrowSizeFuX..","..arrowSizeFuZ..";d" .. yaw .. ".png^[transformFYR".. rotate .."]"
|
|
else
|
|
imstr = "image["..ArrowLocFuX..","..ArrowLocFuZ..";"..arrowSizeFuX..","..arrowSizeFuZ..";d" .. yaw .. ".png^[transformFY]"
|
|
end
|
|
|
|
-- button[X,Y;W,H;name;label]
|
|
local buttons = ""
|
|
buttons = buttons.."button["..(wFormFu-0.8)..",0;0.8,0.8;zoomIn;z+]"
|
|
buttons = buttons.."button["..(wFormFu-0.8)..",1;0.8,0.8;zoomOut;z-]"
|
|
buttons = buttons.."button["..(wFormFu-0.8)..",2;0.8,0.8;updateMap;reMap]"
|
|
buttons = buttons.."image_button["..(wFormFu-0.8)..",3;0.8,0.8;logo.png;teleport;T]"
|
|
if minetest.get_modpath("travelpoints") then
|
|
buttons = buttons.."image_button["..(wFormFu-0.8)..",4;0.8,0.8;teleport.png;TP;TP]"
|
|
end
|
|
|
|
local mapMouseButtons = ""
|
|
worldStepWuX = wWorldWu/10
|
|
worldStepWuZ = hWorldWu/10
|
|
|
|
-- CREATE LIST OF BUTTONS TO OVERLAY MAP (FOR MOUSE CLICKS)
|
|
for iy = 0,9 do
|
|
for ix = 0,9 do
|
|
mapMouseButtons = mapMouseButtons.."image_button["..((wMapFu-lBorderFu)/10*ix+lBorderFu)..","..((hMapFu-tBorderFu)/10*iy+tBorderFu)..";"..((wMapFu-lBorderFu)/8)..","..((hMapFu-tBorderFu)/8)..";blank.png;map"..ix..iy..";;true;false]"
|
|
--"..true..";"..true.."]"
|
|
end
|
|
end
|
|
|
|
-- print(minetest.get_modpath("mapit"))
|
|
-- print(minetest.get_modpath("travelpoints"))
|
|
if minetest.get_modpath("travelpoints") then
|
|
-- CREATE LIST OF TRAVELPOINT LOCATIONS TO OVERLAY ON MAP
|
|
|
|
-- This code largely taken from travelpoints functions.lua
|
|
-- Get travelpoints_array.
|
|
local travelpoints_table = travelpoints.get_travelpoints_table(mapitPlayerName)
|
|
local travelpoints_array = travelpoints.get_travelpoints_array(mapitPlayerName)
|
|
-- print(dump(travelpoints_array))
|
|
-- print("+++")
|
|
-- print(dump(travelpoints_table))
|
|
|
|
-- Get travelpoint count.
|
|
local tp_count = #travelpoints_array - 1
|
|
local mapitTPButtons = ""
|
|
-- Check if player has any travelpoints.
|
|
if tp_count > 0 then
|
|
-- Step through travelpoints_array.
|
|
for index, value in ipairs(travelpoints_array) do
|
|
-- Omit first index (used for travelpoints:transporter_pad/_active's formspec)
|
|
if index > 1 and index <= 50 then
|
|
-- Extract title from value: "<title> (<x>, <y>, <z>)"
|
|
local title = string.match(value, "^([^ ]+)%s+")
|
|
-- Output lines.
|
|
-- <n>. <title> (<x>, <y>, <z>). Saved on <date> at <time>. Descripton: <desc>
|
|
tPPos = travelpoints_table[title].pos
|
|
|
|
-- SCALE AND LOCATE TRAVEL POINT
|
|
local tPSizeFuZ=0.4
|
|
local tPSizeFuX=0.4 --*aspectRatio
|
|
-- Distance from world location at PNG origin to player current location (in WORLD UNITS)
|
|
local pngOriginToTPWuX = travelpoints_table[title].pos.x - pngMinWuX -- x axis is more POSITIVE away from origin
|
|
local pngOriginToTPWuZ = pngMaxWuZ - travelpoints_table[title].pos.z -- z axis is more NEGATIVE away from origin
|
|
-- Distance from world location at PNG origin to player current location (in PIXELS)
|
|
local tPLocFuX = wMapFu*pngOriginToTPWuX*wWorldUnitPp -- location for middle of arrow icon (in pixels)
|
|
local tPLocFuZ = hMapFu*pngOriginToTPWuZ*hWorldUnitPp -- location for middle of arrow icon (in pixels)
|
|
-- location of arrow (in form units)
|
|
local tPLocFuX = tPLocFuX + lBorderFu - tPSizeFuX/2
|
|
local tPLocFuZ = tPLocFuZ + tBorderFu
|
|
-- generate the appropriate string for the travelpoint
|
|
mapitTPButtons = mapitTPButtons.. "image_button[".. tPLocFuX.. ",".. tPLocFuZ.. ";".. tPSizeFuX.. ",".. tPSizeFuZ.. ";teleport.png;TP".. (index-2).. ";".. (index-2).. ";true;false]"
|
|
|
|
mapitTPButtons = mapitTPButtons.. "button[".. wFormFu.. ",".. ((index-2)/2).. ";3,".. tPSizeFuZ.. ";TP".. (index-2).. ";".. (index-2).. " ".. title.. "]"
|
|
elseif index > 50 then
|
|
minetest.chat_send_player(mapitPlayerName, "Sorry: mapit can only fit 50 travelpoints on the map", false)
|
|
break
|
|
end
|
|
end
|
|
else
|
|
-- minetest.chat_send_player(mapitPlayerName, "You have no saved travelpoints.", false)
|
|
end
|
|
|
|
-- GENERATE THE STRING FOR TRAVELPOINTS FORM
|
|
mapitwFormFu = wFormFu + 3
|
|
mapitFormspecTP = "size["..mapitwFormFu..","..hFormFu.."]"..
|
|
imstr..
|
|
"background[0,0;"..wMapFu..","..hMapFu..";"..worldName:gsub("%s+", "_")..".png]"..
|
|
buttons..
|
|
mapitTPButtons
|
|
end
|
|
|
|
-- GENERATE THE FORM AND DISPLAY IT
|
|
mapitFormspecBasic = "size["..wFormFu..","..hFormFu.."]"..
|
|
imstr..
|
|
"background[0,0;"..wMapFu..","..hMapFu..";"..worldName:gsub("%s+", "_")..".png]"..
|
|
buttons
|
|
-- print(mapitFormspecBasic)
|
|
-- generate the string for the mousebuttons form
|
|
mapitFormspecMouse = mapitFormspecBasic.. mapMouseButtons
|
|
|
|
print (mapitFormspecBasic)
|
|
return mapitFormspecBasic
|
|
end
|
|
|
|
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
mapitPlayerName=player:get_player_name()
|
|
|
|
butX=-1
|
|
-- print()
|
|
-- print("basic:".. mapitFormspecBasic)
|
|
-- print()
|
|
-- print("with multibutton:".. mapitFormspecMouse)
|
|
-- print()
|
|
-- print("--------")
|
|
-- print("map state:".. mapitMapState)
|
|
|
|
|
|
if fields.uI then
|
|
generateMapStrings()
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecBasic)
|
|
mapitMapState = ""
|
|
end
|
|
if fields.zoomIn then
|
|
minetest.chat_send_player(mapitPlayerName, "Zoom In not implemented", false)
|
|
if mapitMapState == "+" then
|
|
mapitMapState=""
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecBasic)
|
|
else
|
|
mapitMapState="+"
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecMouse)
|
|
end
|
|
end
|
|
if fields.zoomOut then
|
|
minetest.chat_send_player(mapitPlayerName, "Zoom Out not implemented", false)
|
|
if mapitMapState == "-" then
|
|
mapitMapState=""
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecBasic)
|
|
else
|
|
mapitMapState="-"
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecMouse)
|
|
end
|
|
end
|
|
|
|
if fields.updateMap then
|
|
minetest.chat_send_player(mapitPlayerName, "Updating Map, please be patient...", false)
|
|
updateMap()
|
|
minetest.chat_send_player(mapitPlayerName, "Map Updated. Please exit and re-enter world to reload the texture", false)
|
|
end
|
|
|
|
if fields.teleport then
|
|
if mapitMapState == "t" then
|
|
mapitMapState=""
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecBasic)
|
|
else
|
|
mapitMapState="t"
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecMouse)
|
|
end
|
|
end
|
|
|
|
if minetest.get_modpath("travelpoints") then
|
|
local travelpoints_table = travelpoints.get_travelpoints_table(mapitPlayerName)
|
|
local travelpoints_array = travelpoints.get_travelpoints_array(mapitPlayerName)
|
|
local tPIndex = -1
|
|
|
|
if fields.TP then
|
|
if mapitMapState == "tp" then
|
|
mapitMapState=""
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecBasic)
|
|
else
|
|
-- Only display the form if there is at least one travelpoint
|
|
local travelpoints_table = travelpoints.get_travelpoints_table(mapitPlayerName)
|
|
local travelpoints_array = travelpoints.get_travelpoints_array(mapitPlayerName)
|
|
local tp_count = #travelpoints_array - 1
|
|
if tp_count > 0 then
|
|
mapitMapState="tp"
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecTP)
|
|
else
|
|
minetest.chat_send_player(mapitPlayerName, "You have no saved travelpoints.", false)
|
|
end
|
|
end
|
|
end
|
|
if fields.TP0 then
|
|
tPIndex = 2
|
|
end
|
|
if fields.TP1 then
|
|
tPIndex = 3
|
|
end
|
|
if fields.TP2 then
|
|
tPIndex = 4
|
|
end
|
|
if fields.TP3 then
|
|
tPIndex =5
|
|
end
|
|
if fields.TP4 then
|
|
tPIndex =6
|
|
end
|
|
if fields.TP5 then
|
|
tPIndex =7
|
|
end
|
|
if fields.TP6 then
|
|
tPIndex =8
|
|
end
|
|
if fields.TP7 then
|
|
tPIndex =9
|
|
end
|
|
if fields.TP8 then
|
|
tPIndex =10
|
|
end
|
|
if fields.TP9 then
|
|
tPIndex =11
|
|
end
|
|
if fields.TP10 then
|
|
tPIndex =12
|
|
end
|
|
if fields.TP11 then
|
|
tPIndex =13
|
|
end
|
|
if fields.TP12 then
|
|
tPIndex =14
|
|
end
|
|
if fields.TP13 then
|
|
tPIndex =15
|
|
end
|
|
if fields.TP14 then
|
|
tPIndex =16
|
|
end
|
|
if fields.TP15 then
|
|
tPIndex =17
|
|
end
|
|
if fields.TP16 then
|
|
tPIndex =18
|
|
end
|
|
if fields.TP17 then
|
|
tPIndex =19
|
|
end
|
|
if fields.TP18 then
|
|
tPIndex =20
|
|
end
|
|
if fields.TP19 then
|
|
tPIndex =21
|
|
end
|
|
if fields.TP20 then
|
|
tPIndex =22
|
|
end
|
|
if fields.TP21 then
|
|
tPIndex =23
|
|
end
|
|
if fields.TP22 then
|
|
tPIndex =24
|
|
end
|
|
if fields.TP23 then
|
|
tPIndex =25
|
|
end
|
|
if fields.TP24 then
|
|
tPIndex =26
|
|
end
|
|
if fields.TP25 then
|
|
tPIndex =27
|
|
end
|
|
if fields.TP26 then
|
|
tPIndex =28
|
|
end
|
|
if fields.TP27 then
|
|
tPIndex =29
|
|
end
|
|
if fields.TP28 then
|
|
tPIndex =30
|
|
end
|
|
if fields.TP29 then
|
|
tPIndex =31
|
|
end
|
|
if fields.TP30 then
|
|
tPIndex =32
|
|
end
|
|
if fields.TP31 then
|
|
tPIndex =33
|
|
end
|
|
if fields.TP32 then
|
|
tPIndex =34
|
|
end
|
|
if fields.TP33 then
|
|
tPIndex =35
|
|
end
|
|
if fields.TP34 then
|
|
tPIndex =36
|
|
end
|
|
if fields.TP35 then
|
|
tPIndex =37
|
|
end
|
|
if fields.TP36 then
|
|
tPIndex =38
|
|
end
|
|
if fields.TP37 then
|
|
tPIndex =39
|
|
end
|
|
if fields.TP38 then
|
|
tPIndex =40
|
|
end
|
|
if fields.TP39 then
|
|
tPIndex =41
|
|
end
|
|
if fields.TP40 then
|
|
tPIndex =42
|
|
end
|
|
if fields.TP41 then
|
|
tPIndex =43
|
|
end
|
|
if fields.TP42 then
|
|
tPIndex =44
|
|
end
|
|
if fields.TP43 then
|
|
tPIndex =45
|
|
end
|
|
if fields.TP44 then
|
|
tPIndex =46
|
|
end
|
|
if fields.TP45 then
|
|
tPIndex =47
|
|
end
|
|
if fields.TP46 then
|
|
tPIndex =48
|
|
end
|
|
if fields.TP47 then
|
|
tPIndex =49
|
|
end
|
|
if fields.TP48 then
|
|
tPIndex =50
|
|
end
|
|
if fields.TP49 then
|
|
tPIndex =51
|
|
end
|
|
if fields.TP50 then
|
|
tPIndex =52
|
|
end
|
|
|
|
if tPIndex >=0 then
|
|
for index, value in ipairs(travelpoints_array) do
|
|
-- Omit first index (used for travelpoints:transporter_pad/_active's formspec)
|
|
if index == tPIndex then
|
|
-- Extract title from value: "<title> (<x>, <y>, <z>)"
|
|
local title = string.match(value, "^([^ ]+)%s+")
|
|
player:setpos(travelpoints_table[title].pos)
|
|
end
|
|
end
|
|
generateMapStrings()
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecTP)
|
|
mapitMapState = "tp"
|
|
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- There seems to be no way to hook the mouse click directly, so make a 10x10 grid of transparent buttons and use these to approximate location
|
|
if fields.map00 then
|
|
butX=0
|
|
butZ=0
|
|
end
|
|
if fields.map01 then
|
|
butX=0
|
|
butZ=1
|
|
end
|
|
if fields.map02 then
|
|
butX=0
|
|
butZ=2
|
|
end
|
|
if fields.map03 then
|
|
butX=0
|
|
butZ=3
|
|
end
|
|
if fields.map04 then
|
|
butX=0
|
|
butZ=4
|
|
end
|
|
if fields.map05 then
|
|
butX=0
|
|
butZ=5
|
|
end
|
|
if fields.map06 then
|
|
butX=0
|
|
butZ=6
|
|
end
|
|
if fields.map07 then
|
|
butX=0
|
|
butZ=7
|
|
end
|
|
if fields.map08 then
|
|
butX=0
|
|
butZ=8
|
|
end
|
|
if fields.map09 then
|
|
butX=0
|
|
butZ=9
|
|
end
|
|
if fields.map10 then
|
|
butX=1
|
|
butZ=0
|
|
end
|
|
if fields.map11 then
|
|
butX=1
|
|
butZ=1
|
|
end
|
|
if fields.map12 then
|
|
butX=1
|
|
butZ=2
|
|
end
|
|
if fields.map13 then
|
|
butX=1
|
|
butZ=3
|
|
end
|
|
if fields.map14 then
|
|
butX=1
|
|
butZ=4
|
|
end
|
|
if fields.map15 then
|
|
butX=1
|
|
butZ=5
|
|
end
|
|
if fields.map16 then
|
|
butX=1
|
|
butZ=6
|
|
end
|
|
if fields.map17 then
|
|
butX=1
|
|
butZ=7
|
|
end
|
|
if fields.map18 then
|
|
butX=1
|
|
butZ=8
|
|
end
|
|
if fields.map19 then
|
|
butX=1
|
|
butZ=9
|
|
end
|
|
if fields.map20 then
|
|
butX=2
|
|
butZ=0
|
|
end
|
|
if fields.map21 then
|
|
butX=2
|
|
butZ=1
|
|
end
|
|
if fields.map22 then
|
|
butX=2
|
|
butZ=2
|
|
end
|
|
if fields.map23 then
|
|
butX=2
|
|
butZ=3
|
|
end
|
|
if fields.map24 then
|
|
butX=2
|
|
butZ=4
|
|
end
|
|
if fields.map25 then
|
|
butX=2
|
|
butZ=5
|
|
end
|
|
if fields.map26 then
|
|
butX=2
|
|
butZ=6
|
|
end
|
|
if fields.map27 then
|
|
butX=2
|
|
butZ=7
|
|
end
|
|
if fields.map28 then
|
|
butX=2
|
|
butZ=8
|
|
end
|
|
if fields.map29 then
|
|
butX=2
|
|
butZ=9
|
|
end
|
|
if fields.map30 then
|
|
butX=3
|
|
butZ=0
|
|
end
|
|
if fields.map31 then
|
|
butX=3
|
|
butZ=1
|
|
end
|
|
if fields.map32 then
|
|
butX=3
|
|
butZ=2
|
|
end
|
|
if fields.map33 then
|
|
butX=3
|
|
butZ=3
|
|
end
|
|
if fields.map34 then
|
|
butX=3
|
|
butZ=4
|
|
end
|
|
if fields.map35 then
|
|
butX=3
|
|
butZ=5
|
|
end
|
|
if fields.map36 then
|
|
butX=3
|
|
butZ=6
|
|
end
|
|
if fields.map37 then
|
|
butX=3
|
|
butZ=7
|
|
end
|
|
if fields.map38 then
|
|
butX=3
|
|
butZ=8
|
|
end
|
|
if fields.map39 then
|
|
butX=3
|
|
butZ=9
|
|
end
|
|
if fields.map40 then
|
|
butX=4
|
|
butZ=0
|
|
end
|
|
if fields.map41 then
|
|
butX=4
|
|
butZ=1
|
|
end
|
|
if fields.map42 then
|
|
butX=4
|
|
butZ=2
|
|
end
|
|
if fields.map43 then
|
|
butX=4
|
|
butZ=3
|
|
end
|
|
if fields.map44 then
|
|
butX=4
|
|
butZ=4
|
|
end
|
|
if fields.map45 then
|
|
butX=4
|
|
butZ=5
|
|
end
|
|
if fields.map46 then
|
|
butX=4
|
|
butZ=6
|
|
end
|
|
if fields.map47 then
|
|
butX=4
|
|
butZ=7
|
|
end
|
|
if fields.map48 then
|
|
butX=4
|
|
butZ=8
|
|
end
|
|
if fields.map49 then
|
|
butX=4
|
|
butZ=9
|
|
end
|
|
if fields.map50 then
|
|
butX=5
|
|
butZ=0
|
|
end
|
|
if fields.map51 then
|
|
butX=5
|
|
butZ=1
|
|
end
|
|
if fields.map52 then
|
|
butX=5
|
|
butZ=2
|
|
end
|
|
if fields.map53 then
|
|
butX=5
|
|
butZ=3
|
|
end
|
|
if fields.map54 then
|
|
butX=5
|
|
butZ=4
|
|
end
|
|
if fields.map55 then
|
|
butX=5
|
|
butZ=5
|
|
end
|
|
if fields.map56 then
|
|
butX=5
|
|
butZ=6
|
|
end
|
|
if fields.map57 then
|
|
butX=5
|
|
butZ=7
|
|
end
|
|
if fields.map58 then
|
|
butX=5
|
|
butZ=8
|
|
end
|
|
if fields.map59 then
|
|
butX=5
|
|
butZ=9
|
|
end
|
|
if fields.map60 then
|
|
butX=6
|
|
butZ=0
|
|
end
|
|
if fields.map61 then
|
|
butX=6
|
|
butZ=1
|
|
end
|
|
if fields.map62 then
|
|
butX=6
|
|
butZ=2
|
|
end
|
|
if fields.map63 then
|
|
butX=6
|
|
butZ=3
|
|
end
|
|
if fields.map64 then
|
|
butX=6
|
|
butZ=4
|
|
end
|
|
if fields.map65 then
|
|
butX=6
|
|
butZ=5
|
|
end
|
|
if fields.map66 then
|
|
butX=6
|
|
butZ=6
|
|
end
|
|
if fields.map67 then
|
|
butX=6
|
|
butZ=7
|
|
end
|
|
if fields.map68 then
|
|
butX=6
|
|
butZ=8
|
|
end
|
|
if fields.map69 then
|
|
butX=6
|
|
butZ=9
|
|
end
|
|
if fields.map70 then
|
|
butX=7
|
|
butZ=0
|
|
end
|
|
if fields.map71 then
|
|
butX=7
|
|
butZ=1
|
|
end
|
|
if fields.map72 then
|
|
butX=7
|
|
butZ=2
|
|
end
|
|
if fields.map73 then
|
|
butX=7
|
|
butZ=3
|
|
end
|
|
if fields.map74 then
|
|
butX=7
|
|
butZ=4
|
|
end
|
|
if fields.map75 then
|
|
butX=7
|
|
butZ=5
|
|
end
|
|
if fields.map76 then
|
|
butX=7
|
|
butZ=6
|
|
end
|
|
if fields.map77 then
|
|
butX=7
|
|
butZ=7
|
|
end
|
|
if fields.map78 then
|
|
butX=7
|
|
butZ=8
|
|
end
|
|
if fields.map79 then
|
|
butX=7
|
|
butZ=9
|
|
end
|
|
if fields.map80 then
|
|
butX=8
|
|
butZ=0
|
|
end
|
|
if fields.map81 then
|
|
butX=8
|
|
butZ=1
|
|
end
|
|
if fields.map82 then
|
|
butX=8
|
|
butZ=2
|
|
end
|
|
if fields.map83 then
|
|
butX=8
|
|
butZ=3
|
|
end
|
|
if fields.map84 then
|
|
butX=8
|
|
butZ=4
|
|
end
|
|
if fields.map85 then
|
|
butX=8
|
|
butZ=5
|
|
end
|
|
if fields.map86 then
|
|
butX=8
|
|
butZ=6
|
|
end
|
|
if fields.map87 then
|
|
butX=8
|
|
butZ=7
|
|
end
|
|
if fields.map88 then
|
|
butX=8
|
|
butZ=8
|
|
end
|
|
if fields.map89 then
|
|
butX=8
|
|
butZ=9
|
|
end
|
|
if fields.map90 then
|
|
butX=9
|
|
butZ=0
|
|
end
|
|
if fields.map91 then
|
|
butX=9
|
|
butZ=1
|
|
end
|
|
if fields.map92 then
|
|
butX=9
|
|
butZ=2
|
|
end
|
|
if fields.map93 then
|
|
butX=9
|
|
butZ=3
|
|
end
|
|
if fields.map94 then
|
|
butX=9
|
|
butZ=4
|
|
end
|
|
if fields.map95 then
|
|
butX=9
|
|
butZ=5
|
|
end
|
|
if fields.map96 then
|
|
butX=9
|
|
butZ=6
|
|
end
|
|
if fields.map97 then
|
|
butX=9
|
|
butZ=7
|
|
end
|
|
if fields.map98 then
|
|
butX=9
|
|
butZ=8
|
|
end
|
|
if fields.map99 then
|
|
butX=9
|
|
butZ=9
|
|
end
|
|
|
|
if butX ~= -1 then
|
|
|
|
if mapitMapState == "t" then
|
|
teleportTargetWuX = pngMinWuX + butX*worldStepWuX + 0.5*worldStepWuX
|
|
teleportTargetWuZ = pngMaxWuZ - butZ*worldStepWuZ - 0.5*worldStepWuZ
|
|
|
|
local manip = minetest.get_voxel_manip()
|
|
local groundLevel = nil
|
|
local i
|
|
-- This will fail if ground level is below 0 (but this doesn't happen very often)
|
|
for i = 96, -100, -1 do
|
|
p = {x=teleportTargetWuX, y=i, z=teleportTargetWuZ}
|
|
manip:read_from_map(p, p)
|
|
-- player:setpos(p)
|
|
|
|
if minetest.get_node(p).name ~= "air" and minetest.get_node(p).name ~= "ignore" then
|
|
groundLevel = i
|
|
break
|
|
end
|
|
end
|
|
if groundLevel ~= nil then
|
|
print("mapit Teleport Successful")
|
|
player:setpos({x=teleportTargetWuX, y=(groundLevel+1), z=teleportTargetWuZ})
|
|
else
|
|
-- minetest failed to load the block within the loop, and never seems to no matter how many loops are executed
|
|
-- (even os.execute("sleep 10") doesn't give it time to do so)
|
|
-- However completing the function and having the player re-activate it seems to trigger the engine to load properly
|
|
-- Don't set player back to departure position, or the block will never be loaded
|
|
minetest.chat_send_player(mapitPlayerName, "mapit: Aaarrrgh Teleport Mistargeted (Please Try Again)", false)
|
|
|
|
print("mapit Teleport Failed")
|
|
|
|
end
|
|
end
|
|
generateMapStrings()
|
|
minetest.show_formspec(mapitPlayerName, "mapit:maptool", mapitFormspecMouse)
|
|
mapitMapState = "t"
|
|
end
|
|
|
|
butX=-1
|
|
butZ=-1
|
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local function getGroundLevel(x,z)
|
|
local low = -100
|
|
local high = 101
|
|
local maxLight = 15
|
|
local noon = 0.5
|
|
for y = high, low, -1 do
|
|
lightLevel = get_node_light({x,y,z}, noon)
|
|
if lightLevel < maxLight then
|
|
break
|
|
end
|
|
end
|
|
return y+1
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- PNG Processing
|
|
-- pngparse.lua
|
|
-- Simple example of parsing the main sections of a PNG file.
|
|
--
|
|
-- This is mostly just an example. Not intended to be complete,
|
|
-- robust, modular, or well tested.
|
|
--
|
|
-- (c) 2008 David Manura. Licensed under the same terms as Lua (MIT license).
|
|
-- [with some minor editing by David Mckenzie 2014 for use in the minetest mod]
|
|
|
|
|
|
-- Unpack 32-bit unsigned integer (most-significant-byte, MSB, first)
|
|
-- from byte string.
|
|
local function unpack_msb_uint32(s)
|
|
local a,b,c,d = s:byte(1,#s)
|
|
local num = (((a*256) + b) * 256 + c) * 256 + d
|
|
return num
|
|
end
|
|
|
|
-- Read 32-bit unsigned integer (most-significant-byte, MSB, first) from file.
|
|
local function read_msb_uint32(fh)
|
|
return unpack_msb_uint32(fh:read(4))
|
|
end
|
|
|
|
-- Read unsigned byte (integer) from file
|
|
local function read_byte(fh)
|
|
return fh:read(1):byte()
|
|
end
|
|
|
|
|
|
local function parse_zlib(fh, len)
|
|
local byte1 = read_byte(fh)
|
|
local byte2 = read_byte(fh)
|
|
|
|
local compression_method = byte1 % 16
|
|
local compression_info = math.floor(byte1 / 16)
|
|
|
|
local fcheck = byte2 % 32
|
|
local fdict = math.floor(byte2 / 32) % 1
|
|
local flevel = math.floor(byte2 / 64)
|
|
|
|
-- print("compression_method=", compression_method)
|
|
-- print("compression_info=", compression_info)
|
|
-- print("fcheck=", fcheck)
|
|
-- print("fdict=", fdict)
|
|
-- print("flevel=", flevel)
|
|
|
|
fh:read(len - 6)
|
|
-- print("(deflate data not displayed)")
|
|
|
|
local checksum = read_msb_uint32(fh)
|
|
-- print("checksum=", checksum)
|
|
end
|
|
|
|
local function parse_IHDR(fh, len)
|
|
assert(len == 13, 'format error')
|
|
local width = read_msb_uint32(fh)
|
|
local height = read_msb_uint32(fh)
|
|
local bit_depth = read_byte(fh)
|
|
local color_type = read_byte(fh)
|
|
local compression_method = read_byte(fh)
|
|
local filter_method = read_byte(fh)
|
|
local interlace_method = read_byte(fh)
|
|
|
|
-- print("width=", width)
|
|
-- print("height=", height)
|
|
-- print("bit_depth=", bit_depth)
|
|
-- print("color_type=", color_type)
|
|
-- print("compression_method=", compression_method)
|
|
-- print("filter_method=", filter_method)
|
|
-- print("interlace_method=", interlace_method)
|
|
|
|
return compression_method, width, height
|
|
end
|
|
|
|
local function parse_sRGB(fh, len)
|
|
assert(len == 1, 'format error')
|
|
local rendering_intent = read_byte(fh)
|
|
-- print("rendering_intent=", rendering_intent)
|
|
end
|
|
|
|
local function parse_gAMA(fh, len)
|
|
assert(len == 4, 'format error')
|
|
local rendering_intent = read_msb_uint32(fh)
|
|
-- print("rendering_intent=", rendering_intent)
|
|
end
|
|
|
|
local function parse_cHRM(fh, len)
|
|
assert(len == 32, 'format error')
|
|
|
|
local white_x = read_msb_uint32(fh)
|
|
local white_y = read_msb_uint32(fh)
|
|
local red_x = read_msb_uint32(fh)
|
|
local red_y = read_msb_uint32(fh)
|
|
local green_x = read_msb_uint32(fh)
|
|
local green_y = read_msb_uint32(fh)
|
|
local blue_x = read_msb_uint32(fh)
|
|
local blue_y = read_msb_uint32(fh)
|
|
-- print('white_x=', white_x)
|
|
-- print('white_y=', white_y)
|
|
-- print('red_x=', red_x)
|
|
-- print('red_y=', red_y)
|
|
-- print('green_x=', green_x)
|
|
-- print('green_y=', green_y)
|
|
-- print('blue_x=', blue_x)
|
|
-- print('blue_y=', blue_y)
|
|
end
|
|
|
|
local function parse_IDAT(fh, len, compression_method)
|
|
if compression_method == 0 then
|
|
-- fh:read(len)
|
|
parse_zlib(fh, len)
|
|
else
|
|
-- print('(unrecognized compression method)')
|
|
end
|
|
end
|
|
|
|
function parse_png(filename)
|
|
local fh = assert(io.open(filename, 'rb'))
|
|
local keyword
|
|
local text
|
|
local i
|
|
local pngRegionWu
|
|
local borderPx
|
|
local pixPerNodePx
|
|
local pngMinWuX
|
|
local pngMaxWuZ
|
|
local height, width
|
|
|
|
|
|
-- parse PNG header
|
|
local bytes = fh:read(8)
|
|
local expect = "\137\080\078\071\013\010\026\010"
|
|
if bytes ~= expect then
|
|
minetest.chat_send_player(mapitPlayerName, "mapit: fatal error: not a PNG file" .. filename, false)
|
|
print("mapit: fatal error: not a PNG file" .. filename)
|
|
else
|
|
-- minetest.chat_send_player(mapitPlayerName, "mapit: valid PNG file" .. filename, false)
|
|
end
|
|
|
|
|
|
-- parse chunks
|
|
local compression_method
|
|
while 1 do
|
|
local len = read_msb_uint32(fh)
|
|
local stype = fh:read(4)
|
|
-- print("chunk:", "type=", stype, "len=", len)
|
|
|
|
if stype == 'IHDR' then
|
|
compression_method, width, height = parse_IHDR(fh, len)
|
|
elseif stype == 'sRGB' then
|
|
parse_sRGB(fh, len)
|
|
elseif stype == 'gAMA' then
|
|
parse_gAMA(fh, len)
|
|
elseif stype == 'cHRM' then
|
|
parse_cHRM(fh, len)
|
|
elseif stype == 'IDAT' then
|
|
parse_IDAT(fh, len, compression_method)
|
|
elseif stype == 'tEXt' then
|
|
local data = fh:read(len)
|
|
for i = 1, len do
|
|
if data:byte(i)== 0 then
|
|
keyword = data:sub(1, i-1)
|
|
text = data:sub(i+1,len)
|
|
break
|
|
end
|
|
end
|
|
|
|
-- print ("mapit: tEXt data=" .. data)
|
|
-- print ("mapit: tEXt len=" .. len)
|
|
-- print ("mapit: tEXt keyword=".. keyword)
|
|
-- print ("mapit: tEXt text=" .. text)
|
|
if keyword == "pngRegion" then
|
|
pngRegionWu = text
|
|
elseif keyword == "pngMinX" then
|
|
pngMinWuX = tonumber(text)
|
|
elseif keyword == "pngMaxZ" then
|
|
pngMaxWuZ = tonumber(text)
|
|
elseif keyword == "border" then
|
|
borderPx = tonumber(text)
|
|
elseif keyword == "pixPerNode" then
|
|
pixPerNodePx = tonumber(text)
|
|
end
|
|
|
|
-- print("data=", len == 0 and "(empty)" or "(not displayed)")
|
|
else
|
|
local data = fh:read(len)
|
|
-- print ("mapit: Unknown data=" .. data)
|
|
-- print("data=", len == 0 and "(empty)" or "(not displayed)")
|
|
end
|
|
|
|
local crc = read_msb_uint32(fh)
|
|
-- print("crc=", crc)
|
|
|
|
if stype == 'IEND' then
|
|
break
|
|
end
|
|
end
|
|
-- print ("mapit: tEXt pngRegionWu=".. pngRegionWu)
|
|
-- print ("mapit: tEXt pngMinWuX=" .. pngMinWuX)
|
|
-- print ("mapit: tEXt pngMaxWuZ=" .. pngMaxWuZ)
|
|
-- print ("mapit: tEXt borderPx=" .. borderPx)
|
|
-- print ("mapit: tEXt pixPerNodePx=" .. pixPerNodePx)
|
|
|
|
return width, height, pngRegionWu, pngMinWuX, pngMaxWuZ, borderPx, pixPerNodePx
|
|
end
|
|
|
|
if minetest.get_modpath("unified_inventory") then
|
|
inv_mod = "unified_inventory"
|
|
unified_inventory.register_button("mapit", {
|
|
type = "image",
|
|
image = "unified_inventory_mapit.png",
|
|
})
|
|
unified_inventory.register_page("mapit", {
|
|
get_formspec = function(player)
|
|
mapitPlayerName= player:get_player_name()
|
|
|
|
-- GET NAMES AND PATHS TO ENSURE CORRECT MAP IS USED
|
|
local worldPath = minetest.get_worldpath()
|
|
local worldName = string.gsub(worldPath, "(.*worlds.)(.*)", "%2")
|
|
|
|
local mapFileName = worldName:gsub("%s+", "_").. ".png"
|
|
|
|
local formspec = "image_button[0.06,0.99;7.92,7.52;"..mapFileName..";uI;click here for map]"
|
|
print ('mapit')
|
|
print (formspec)
|
|
|
|
return {formspec=formspec}
|
|
end,
|
|
})
|
|
end
|
|
|
|
|