local blocks_cache = { [0] = {}, [1] = {} } local connections = {} local computationActive = false local lastPlayerPos = { x = 0, y = 0, z = 0 } local lastComputationTime = 0 local scanParity = 0 local COMPUTATION_INTERVAL = 400 local MAX_RANGE = 22 local SEARCH_RANGE = 25 local SEARCH_HEIGHT = 7 local pendingUpdate = nil local t_insert = table.insert local m_floor = math.floor local m_max = math.max local m_min = math.min local world = require("world") local player = require("player") local threads = require("threads") local creator = require("creator") local function findBlocksInParity(centerX, centerY, centerZ, horizontal, vertical, parity) local found = {} for dx = -horizontal, horizontal do for dz = -horizontal, horizontal do if (m_floor(centerX + dx) + m_floor(centerZ + dz)) % 2 == parity then local x, z = centerX + dx, centerZ + dz for dy = -vertical, vertical do local y = centerY + dy local blockInfo = world.getBlock(x, y, z) if blockInfo and blockInfo.name then local name = blockInfo.name if name == "block.minecraft.tripwire" then t_insert(found, { x = x, y = y, z = z, type = "tripwire" }) elseif name == "block.minecraft.tripwire_hook" then t_insert(found, { x = x, y = y, z = z, type = "hook", state = blockInfo }) end end end end end end return found end local function areHooksConnected(hook1, hook2) if hook1.y ~= hook2.y then return false end local dx, dz = hook2.x - hook1.x, hook2.z - hook1.z local absDx, absDz = dx < 0 and -dx or dx, dz < 0 and -dz or dz local steps = m_max(absDx, absDz) if steps < 2 or steps > MAX_RANGE then return false end if not (absDx == 0 or absDz == 0) then return false end local sx = (dx == 0 and 0 or dx / absDx) local sz = (dz == 0 and 0 or dz / absDz) for i = 1, steps - 1 do local b = world.getBlock(hook1.x + sx * i, hook1.y, hook1.z + sz * i) if not b or b.name ~= "block.minecraft.tripwire" then return false end end return true end local function computeInBackground(centerX, centerY, centerZ, parity) if computationActive then return end computationActive = true threads.startThread(function() local status, result = pcall(function() local found = findBlocksInParity(centerX, centerY, centerZ, SEARCH_RANGE, SEARCH_HEIGHT, parity) return { blocks = found, parity = parity } end) if status then pendingUpdate = result end computationActive = false end) end registerClientTick(function() local currentTime = os.clock() * 1000 if pendingUpdate then blocks_cache[pendingUpdate.parity] = pendingUpdate.blocks local all_hooks = {} for p = 0, 1 do local list = blocks_cache[p] for i = 1, #list do if list[i].type == "hook" then t_insert(all_hooks, list[i]) end end end local new_conns = {} for i = 1, #all_hooks do for j = i + 1, #all_hooks do local h1, h2 = all_hooks[i], all_hooks[j] if areHooksConnected(h1, h2) then local s1, s2 = h1.state, h2.state if s1.facing and s2.facing and s1.facing.opposite then if s1.facing.name == s2.facing.opposite.name then t_insert(new_conns, { hook1 = h1, hook2 = h2, boxes1 = world.getOutlineBoxes(h1.x, h1.y, h1.z, s1), boxes2 = world.getOutlineBoxes(h2.x, h2.y, h2.z, s2) }) end end end end end connections = new_conns pendingUpdate = nil end if computationActive or (currentTime - lastComputationTime < COMPUTATION_INTERVAL) then return end local pos = player.getPos() if pos then local cx, cy, cz = m_floor(pos.x), m_floor(pos.y), m_floor(pos.z) scanParity = (scanParity + 1) % 2 lastComputationTime = currentTime computeInBackground(cx, cy, cz, scanParity) end end) local filledColor = { red = 255, green = 255, blue = 85, alpha = 170 } local filledColor2 = { red = 255, green = 85, blue = 85, alpha = 170 } registerWorldRenderer(function(context) local currentConns = connections local count = #currentConns if count == 0 then return end local epsilon = 0.02 for i = 1, count do local connection = currentConns[i] local hook1, hook2 = connection.hook1, connection.hook2 local collisions_hook1 = connection.boxes1 local collisions_hook2 = connection.boxes2 local X1, Y, Z1 = hook1.x, hook1.y, hook1.z local X2, Z2 = hook2.x, hook2.z local isHorizontalX = (Z1 == Z2) local y_min = Y + 0.06 local y_max = Y + 0.17 local x1, x2, z1, z2 if isHorizontalX then local min_x_coord = m_min(X1 - collisions_hook1[1].getXSize() * 1.7, X2 + collisions_hook2[1].getXSize() * 1.7) local max_x_coord = m_max(X1 - collisions_hook1[1].getXSize() * 1.7, X2 + collisions_hook2[1].getXSize() * 1.7) x1 = min_x_coord + 1.0 + epsilon x2 = max_x_coord - epsilon z1 = Z1 + 0.02 z2 = Z1 + 0.98 else local min_z_coord = m_min(Z1 - collisions_hook1[1].getXSize() * 1.7, Z2 + collisions_hook2[1].getXSize() * 1.7) local max_z_coord = m_max(Z1 - collisions_hook1[1].getXSize() * 1.7, Z2 + collisions_hook2[1].getXSize() * 1.7) z1 = min_z_coord + 1.0 + epsilon z2 = max_z_coord - epsilon x1 = X1 + 0.02 x2 = X1 + 0.98 end local box2 = creator.createAABB(x1, y_min, z1, x2, y_max, z2) context.renderFilled(box2, filledColor2.red, filledColor2.green, filledColor2.blue, filledColor2.alpha, true) for i2 = 1, #collisions_hook1 do local box = collisions_hook1[i2] local bx1 = box.minX + hook1.x local by1 = box.minY + hook1.y local bz1 = box.minZ + hook1.z local bx2 = box.maxX + hook1.x local by2 = box.maxY + hook1.y local bz2 = box.maxZ + hook1.z local b = creator.createAABB(bx1, by1, bz1, bx2, by2, bz2) context.renderFilled(b, filledColor.red, filledColor.green, filledColor.blue, filledColor.alpha, true) end for i2 = 1, #collisions_hook2 do local box = collisions_hook2[i2] local bx1 = box.minX + hook2.x local by1 = box.minY + hook2.y local bz1 = box.minZ + hook2.z local bx2 = box.maxX + hook2.x local by2 = box.maxY + hook2.y local bz2 = box.maxZ + hook2.z local b = creator.createAABB(bx1, by1, bz1, bx2, by2, bz2) context.renderFilled(b, filledColor.red, filledColor.green, filledColor.blue, filledColor.alpha, true) end end end)