-- Dynmap 3d & 2d Overlay -- hugeblank, May 2023 -- Displays the owner, name and color of the claim you're currently in. -- Extends functionality of dynoverlay.lua by adding the ability to view the claims as bounding boxes on a 3d canvas. -- Partailly uses dead reckoning to keep location up to date instead of spamming gps calls. -- Settings: -- dynoverlay.canvas.x - The x coordinate that the 2d overlay displays on (default: 8) -- dynoverlay.canvas.y - The y coordinate that the 2d overlay displays on (default: 16) -- dynoverlay.cuboid.pollRate - The frequency at which to poll gps servers in seconds (default: 5) -- dynoverlay.cuboid.renderDistance - The boundary at which claims no longer render (default: 64) -- dynoverlay.cuboid.opacity - The opacity of the claim cuboid overlays (default: 32) -- dynoverlay.cuboid.enable - Whether to enable the cuboid view on program start (default: false) -- dynoverlay.cuboid.shaders - Whether to enable shader mode. Divides the colors of claims by 8. (default: false) assert(chatbox, "Chatbox required") local dynmap = require("dynmap") -- Get the dynmap API from: https://p.sc3.io/hxHMUvEx8y local mods = peripheral.wrap("back") assert(mods, "Must be used on a Neural Interface") assert(peripheral.find("modem"), "Modem required") assert(mods.canvas, "Overlay Glasses required") -- If you do not have an introspection module, an entity sensor can suffice. Uncomment out the following line, and comment out the one below it. --local getMeta = assert(function() return mods.getMetaByName() end, "Entity sensor required") local getMeta = assert(mods.getMetaOwner, "Introspection Module & Entity Sensor required") local canvas = mods.canvas3d() local infocanvas, blockcanvas = mods.canvas().addGroup({settings.get("dynoverlay.canvas.x", 8),settings.get("dynoverlay.canvas.y", 16)}), canvas.create() local name, owner, status = infocanvas.addText({0,0}, ""), infocanvas.addText({0,9}, ""), infocanvas.addText({0,17}, "") local pollRate = settings.get("dynoverlay.cuboid.pollRate", 5) local renderDistance = settings.get("dynoverlay.cuboid.renderDistance", 64) local opacity = settings.get("dynoverlay.cuboid.opacity", 32) local enabled = settings.get("dynoverlay.cuboid.enable", false) local shaders = settings.get("dynoverlay.cuboid.shaders", false) name.setScale(1) owner.setScale(0.8) status.setScale(0.8) local _, claims, meta, refreshed local x, y, z = gps.locate() local rx, ry, rz = x, y, z local function setClaimColor(element, color, shadersOverride) local c = tonumber(color:sub(2, -1), 16) local rgb = {} for i = 3, 1, -1 do rgb[i] = c%256 if shaders and not shadersOverride then rgb[i] = rgb[i]/8 end c = math.floor(c/256) end element.setColor(table.unpack(rgb)) end local function place(claim, xoff, zoff) local box = blockcanvas.addBox(claim.xmin-xoff+0.5, -64, claim.zmin-zoff+0.5) setClaimColor(box, claim.color) box.setDepthTested(true) box.setSize(claim.xmax-claim.xmin-1, 320, claim.zmax-claim.zmin-1) box.setAlpha(opacity) claim.box = box end local poll = math.floor(30/pollRate) local resetClaims = 0 local dimension = "overworld" local function refreshClaims() local ok, results = dynmap.getClaims(true, nil, dimension) if ok then for _, claim in ipairs(results) do claim.label = claim.label:gsub("&", "&"):gsub("'", "'"):gsub(""", '"') end claims = results end refreshed = true resetClaims = 0 end local function refresh() while true do if resetClaims == poll then refreshClaims() else resetClaims = resetClaims+1 end sleep(pollRate) local dx, dy, dz = gps.locate() if dx then x, y, z = dx, dy, dz if claims and enabled then rx, ry, rz = dx, dy, dz blockcanvas.recenter(0-meta.deltaPosX,0,0-meta.deltaPosZ) for _, claim in ipairs(claims) do if claim.box then local xminOff, zminOff = claim.xmin-dx+0.5, claim.zmin-dz+0.5 claim.box.setPosition(xminOff, -64, zminOff) end end end end end end local function getClaimInfo() while true do if x and claims then local found = false for _, claim in ipairs(claims) do if claim.xmin < x and claim.zmin < z and claim.xmax > x and claim.zmax > z then setClaimColor(name, claim.color, true) setClaimColor(owner, claim.color, true) setClaimColor(status, claim.color, true) name.setText(claim.label) owner.setText(claim.owner) found = true break end end if not found then name.setText("") owner.setText("") end end sleep() end end local function velocity() while true do meta = getMeta() x, z = x+meta.deltaPosX, z+meta.deltaPosZ end end local function testOffsetPair(xoff, zoff, orr) if orr then return xoff <= renderDistance or zoff <= renderDistance else return xoff <= renderDistance and zoff <= renderDistance end end local function replace() while true do if x and claims and enabled then if refreshed then blockcanvas.clear() end for _, claim in ipairs(claims) do if refreshed and claim.box then claim.box.remove() claim.box = nil end local xminOff, zminOff, xmaxOff, zmaxOff = math.abs(claim.xmin-x), math.abs(claim.zmin-z), math.abs(claim.xmax-x), math.abs(claim.zmax-z) -- Test x edges Test z edges Test -x -z corner Test -x +z corner Test +x +z corner Test +x -z corner if ((claim.xmin < x and claim.xmax > x) and testOffsetPair(zminOff, zmaxOff, true)) or ((claim.zmin < z and claim.zmax > z) and testOffsetPair(xminOff, xmaxOff, true)) or (testOffsetPair(xminOff, zminOff) or testOffsetPair(xminOff, zmaxOff) or testOffsetPair(xmaxOff, zmaxOff) or testOffsetPair(xmaxOff, zminOff)) then if not claim.box then place(claim, rx, rz) end if claim.xmin < x and claim.zmin < z and claim.xmax >= x and claim.zmax >= z then claim.box.setAlpha(0) else claim.box.setAlpha(opacity) end elseif claim.box then claim.box.remove() claim.box = nil end end if refreshed then refreshed = false end end sleep() end end local function keybind() local ctrl = false while true do local e, key = os.pullEvent() if e == "key" then if keys.leftCtrl == key then ctrl = true elseif keys.c == key and ctrl then enabled = not enabled for _, claim in ipairs(claims) do if claim.box then claim.box.remove() claim.box = nil end end blockcanvas.clear() end elseif e == "key_up" then if keys.leftCtrl == key then ctrl = false end end end end local function renderstatus() local prevenabled = enabled local hold, fade = 0, 0 while true do if prevenabled ~= enabled then if enabled then status.setText("Claim rendering enabled") status.setAlpha(255) hold, fade = 20, 20 else status.setText("Claim rendering disabled") status.setAlpha(255) hold, fade = 20, 20 end prevenabled = enabled end if hold == 0 and fade ~= 0 then status.setAlpha(255*(fade/20)) fade = fade-1 if fade == 0 then hold, fade = 0, 0 end elseif fade ~= 0 then hold = hold-1 end sleep() end end local function worldcheck() local username = getMeta().name local players = chatbox.getPlayers() for _, player in ipairs(players) do if player.name == username then dimension = player.world:gsub("minecraft:", "") end end refreshClaims() while true do local _, name, _, destination = os.pullEvent("world_change") if name == username then dimension = destination:gsub("minecraft:", "") refreshClaims() end end end parallel.waitForAny(worldcheck, refresh, getClaimInfo, velocity, replace, keybind, renderstatus)