return function() local playerLookVector = nil local function getEntityLookVector(entity) -- yaw: -- 0 => positive Z -- 90 => negative X -- pitch: -- 0 => forward -- 90 => down if entity == nil or entity.yaw == nil or entity.pitch == nil then return {0, 0, 0, x = 0, y = 0, z = 0} end local yawr = math.rad(entity.yaw) local pitchr = math.rad(entity.pitch) local cosPitch = math.cos(pitchr) local x = cosPitch * -math.sin(yawr) local z = cosPitch * math.cos(yawr) local y = -math.sin(pitchr) return {x, y, z, x = x, y = y, z = z} end local function updateLookVector() playerLookVector = getEntityLookVector(player) return playerLookVector end local function dotProduct3(u, v) return u.x * v.x + u.y * v.y + u.z * v.z end local function vec3Scale(k, v) return {x = k * v.x, y = k * v.y, z = k * v.z} end local function vec3Add(u, v) return {x = u.x + v.x, y = u.y + v.y, z = u.z + v.z} end local function vec3Abs(v) return math.sqrt(dotProduct3(v, v)) end local function toFrontCoords(entity) local dotResult = dotProduct3(entity, playerLookVector) if dotResult >= 0.0 then return {x = entity.x, y = entity.y, z = entity.z, flipped = false} end local result = vec3Add(entity, vec3Scale(-2 * dotResult, playerLookVector)) result.flipped = true return result end while _G.player == nil do os.sleep(0.05) end local cache = {} while _G._running do updateLookVector() for id, entry in pairs(cache) do if nearbyEntitiesByUUID[id] == nil then entry.cube.remove() entry.frame.remove() cache[id] = nil end end for id, entity in pairs(nearbyEntitiesByUUID) do if id ~= player.id then if cache[id] == nil then cache[id] = {} cache[id].cube = canvas3d.addBox(0, 0, 0) cache[id].cube.setSize(0.5, 0.5, 0.5) cache[id].frame = canvas3d.addFrame({ 0, 0, 0 }) cache[id].text = cache[id].frame.addText({ 0, 0 }, "") cache[id].lookLine = canvas3d.addLine({ 0, 0, 0 }, { 0, 0, 0 }, 2, 0) end local entityFront = toFrontCoords(entity) local entityLook = getEntityLookVector(entity) local entityLookEnd = vec3Add(entityFront, entityLook) if entityFront.flipped then cache[id].cube.setColor(0x004040FF) cache[id].lookLine.setColor(0x004040FF) else cache[id].cube.setColor(0xFFC0C0FF) cache[id].lookLine.setColor(0xFFC0C0FF) end cache[id].cube.setAlpha(0x20) cache[id].lookLine.setAlpha(0x10) cache[id].cube.setDepthTested(false) cache[id].frame.setDepthTested(false) cache[id].lookLine.setDepthTested(false) cache[id].cube.setPosition(entityFront.x - 0.25, entityFront.y - 0.25, entityFront.z - 0.25) cache[id].frame.setPosition(entityFront.x, entityFront.y, entityFront.z) cache[id].lookLine.setPoint(1, entityFront.x, entityFront.y, entityFront.z) cache[id].lookLine.setPoint(2, entityLookEnd.x, entityLookEnd.y, entityLookEnd.z) cache[id].text.setAlpha(0xFF) if player.isSneaking then cache[id].text.setText(entity.name .. "\n" .. textutils.serialize(entity)) else cache[id].text.setText(("%s\n|{%.2f, %.2f, %.2f}| = %.2f"):format(entity.name, entity.x, entity.y, entity.z, vec3Abs(entity))) end if entityFront.flipped then cache[id].text.setColor(0x00FFFFFF) else cache[id].text.setColor(0xFF0000FF) end end end os.sleep(0.05) end end