1
-- Dynmap 3d & 2d Overlay
2
-- hugeblank, May 2023
3
-- Displays the owner, name and color of the claim you're currently in.
4
-- Extends functionality of dynoverlay.lua by adding the ability to view the claims as bounding boxes on a 3d canvas.
5
-- Partailly uses dead reckoning to keep location up to date instead of spamming gps calls.
6
7
-- Settings:
8
-- dynoverlay.canvas.x - The x coordinate that the 2d overlay displays on (default: 8)
9
-- dynoverlay.canvas.y - The y coordinate that the 2d overlay displays on (default: 16)
10
-- dynoverlay.cuboid.pollRate - The frequency at which to poll gps servers in seconds (default: 5)
11
-- dynoverlay.cuboid.renderDistance - The boundary at which claims no longer render (default: 64)
12
-- dynoverlay.cuboid.opacity - The opacity of the claim cuboid overlays (default: 32)
13
-- dynoverlay.cuboid.enable - Whether to enable the cuboid view on program start (default: false)
14
-- dynoverlay.cuboid.shaders - Whether to enable shader mode. Divides the colors of claims by 8. (default: false)
15
16
assert(chatbox, "Chatbox required")
17
local dynmap = require("dynmap") -- Get the dynmap API from: https://p.sc3.io/hxHMUvEx8y
18
local mods = peripheral.wrap("back")
19
assert(mods, "Must be used on a Neural Interface")
20
assert(peripheral.find("modem"), "Modem required")
21
assert(mods.canvas, "Overlay Glasses required")
22
-- 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.
23
--local getMeta = assert(function() return mods.getMetaByName(<USERNAME>) end, "Entity sensor required")
24
local getMeta = assert(mods.getMetaOwner, "Introspection Module & Entity Sensor required")
25
local canvas = mods.canvas3d()
26
local infocanvas, blockcanvas = mods.canvas().addGroup({settings.get("dynoverlay.canvas.x", 8),settings.get("dynoverlay.canvas.y", 16)}), canvas.create()
27
local name, owner, status = infocanvas.addText({0,0}, ""), infocanvas.addText({0,9}, ""), infocanvas.addText({0,17}, "")
28
local pollRate = settings.get("dynoverlay.cuboid.pollRate", 5)
29
local renderDistance = settings.get("dynoverlay.cuboid.renderDistance", 64)
30
local opacity = settings.get("dynoverlay.cuboid.opacity", 32)
31
local enabled = settings.get("dynoverlay.cuboid.enable", false)
32
local shaders = settings.get("dynoverlay.cuboid.shaders", false)
33
name.setScale(1)
34
owner.setScale(0.8)
35
status.setScale(0.8)
36
37
local _, claims, meta, refreshed
38
local x, y, z = gps.locate()
39
local rx, ry, rz = x, y, z
40
local function setClaimColor(element, color, shadersOverride)
41
local c = tonumber(color:sub(2, -1), 16)
42
local rgb = {}
43
for i = 3, 1, -1 do
44
rgb[i] = c%256
45
if shaders and not shadersOverride then
46
rgb[i] = rgb[i]/8
47
end
48
c = math.floor(c/256)
49
end
50
element.setColor(table.unpack(rgb))
51
end
52
53
local function place(claim, xoff, zoff)
54
local box = blockcanvas.addBox(claim.xmin-xoff+0.5, -64, claim.zmin-zoff+0.5)
55
56
setClaimColor(box, claim.color)
57
box.setDepthTested(true)
58
box.setSize(claim.xmax-claim.xmin-1, 320, claim.zmax-claim.zmin-1)
59
box.setAlpha(opacity)
60
claim.box = box
61
end
62
63
local poll = math.floor(30/pollRate)
64
local resetClaims = 0
65
local dimension = "overworld"
66
67
local function refreshClaims()
68
local ok, results = dynmap.getClaims(true, nil, dimension)
69
if ok then
70
for _, claim in ipairs(results) do
71
claim.label = claim.label:gsub("&", "&"):gsub("'", "'"):gsub(""", '"')
72
end
73
claims = results
74
end
75
refreshed = true
76
resetClaims = 0
77
end
78
79
local function refresh()
80
while true do
81
if resetClaims == poll then
82
refreshClaims()
83
else
84
resetClaims = resetClaims+1
85
end
86
sleep(pollRate)
87
local dx, dy, dz = gps.locate()
88
if dx then
89
x, y, z = dx, dy, dz
90
if claims and enabled then
91
rx, ry, rz = dx, dy, dz
92
blockcanvas.recenter(0-meta.deltaPosX,0,0-meta.deltaPosZ)
93
for _, claim in ipairs(claims) do
94
if claim.box then
95
local xminOff, zminOff = claim.xmin-dx+0.5, claim.zmin-dz+0.5
96
claim.box.setPosition(xminOff, -64, zminOff)
97
end
98
end
99
end
100
end
101
end
102
end
103
104
local function getClaimInfo()
105
while true do
106
if x and claims then
107
local found = false
108
for _, claim in ipairs(claims) do
109
if claim.xmin < x and claim.zmin < z and claim.xmax > x and claim.zmax > z then
110
setClaimColor(name, claim.color, true)
111
setClaimColor(owner, claim.color, true)
112
setClaimColor(status, claim.color, true)
113
name.setText(claim.label)
114
owner.setText(claim.owner)
115
found = true
116
break
117
end
118
end
119
if not found then
120
name.setText("")
121
owner.setText("")
122
end
123
124
end
125
sleep()
126
end
127
end
128
129
local function velocity()
130
while true do
131
meta = getMeta()
132
x, z = x+meta.deltaPosX, z+meta.deltaPosZ
133
end
134
end
135
136
local function testOffsetPair(xoff, zoff, orr)
137
if orr then
138
return xoff <= renderDistance or zoff <= renderDistance
139
else
140
return xoff <= renderDistance and zoff <= renderDistance
141
end
142
end
143
144
local function replace()
145
while true do
146
if x and claims and enabled then
147
if refreshed then
148
blockcanvas.clear()
149
end
150
for _, claim in ipairs(claims) do
151
if refreshed and claim.box then
152
claim.box.remove()
153
claim.box = nil
154
end
155
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)
156
-- Test x edges Test z edges Test -x -z corner Test -x +z corner Test +x +z corner Test +x -z corner
157
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
158
if not claim.box then
159
place(claim, rx, rz)
160
end
161
if claim.xmin < x and claim.zmin < z and claim.xmax >= x and claim.zmax >= z then
162
claim.box.setAlpha(0)
163
else
164
claim.box.setAlpha(opacity)
165
end
166
elseif claim.box then
167
claim.box.remove()
168
claim.box = nil
169
end
170
end
171
if refreshed then
172
refreshed = false
173
end
174
end
175
sleep()
176
end
177
end
178
179
local function keybind()
180
local ctrl = false
181
while true do
182
local e, key = os.pullEvent()
183
if e == "key" then
184
if keys.leftCtrl == key then
185
ctrl = true
186
elseif keys.c == key and ctrl then
187
enabled = not enabled
188
for _, claim in ipairs(claims) do
189
if claim.box then
190
claim.box.remove()
191
claim.box = nil
192
end
193
end
194
blockcanvas.clear()
195
end
196
elseif e == "key_up" then
197
if keys.leftCtrl == key then
198
ctrl = false
199
end
200
end
201
end
202
end
203
204
local function renderstatus()
205
local prevenabled = enabled
206
local hold, fade = 0, 0
207
while true do
208
if prevenabled ~= enabled then
209
if enabled then
210
status.setText("Claim rendering enabled")
211
status.setAlpha(255)
212
hold, fade = 20, 20
213
else
214
status.setText("Claim rendering disabled")
215
status.setAlpha(255)
216
hold, fade = 20, 20
217
end
218
prevenabled = enabled
219
end
220
if hold == 0 and fade ~= 0 then
221
status.setAlpha(255*(fade/20))
222
fade = fade-1
223
if fade == 0 then
224
hold, fade = 0, 0
225
end
226
elseif fade ~= 0 then
227
hold = hold-1
228
end
229
sleep()
230
end
231
end
232
233
local function worldcheck()
234
local username = getMeta().name
235
local players = chatbox.getPlayers()
236
for _, player in ipairs(players) do
237
if player.name == username then
238
dimension = player.world:gsub("minecraft:", "")
239
end
240
end
241
refreshClaims()
242
while true do
243
local _, name, _, destination = os.pullEvent("world_change")
244
if name == username then
245
dimension = destination:gsub("minecraft:", "")
246
refreshClaims()
247
end
248
end
249
250
end
251
252
parallel.waitForAny(worldcheck, refresh, getClaimInfo, velocity, replace, keybind, renderstatus)
253