Files
Waterpipes-FIxed/42/media/lua/shared/WaterpipesB42Patch.lua
2026-02-18 18:10:10 -05:00

888 lines
28 KiB
Lua

WaterpipesB42Patch = WaterpipesB42Patch or {}
local Patch = WaterpipesB42Patch
local Z_OFFSETS = {0, -1, 1, 2, 3}
local function parseSquareKey(tileKey)
local x, y, z = string.match(tileKey, "^(-?%d+),(-?%d+),(-?%d+)$")
if not x then
x, y, z = string.match(tileKey, "^(-?%d+)-(-?%d+)-(-?%d+)$")
end
if not x then
return nil, nil, nil
end
return tonumber(x), tonumber(y), tonumber(z)
end
local function getVerticalSearchSquares(square)
local squares = {}
if not square then
return squares
end
local cell = square:getCell()
local sx, sy, sz = square:getX(), square:getY(), square:getZ()
local seen = {}
for _, offset in ipairs(Z_OFFSETS) do
local z = sz + offset
local key = tostring(z)
if not seen[key] then
seen[key] = true
local sq = cell and cell:getGridSquare(sx, sy, z) or nil
if sq then
table.insert(squares, sq)
end
end
end
return squares
end
local function findNearbyLinkedBid(square, xyRadius, zRadius)
if not square or not GetWPModData or not WPUtils or not WPUtils.Coords2Id then
return nil
end
local gmd = GetWPModData()
if not gmd then
return nil
end
local sx, sy, sz = square:getX(), square:getY(), square:getZ()
local zr = zRadius or 1
local rr = xyRadius or 1
for dz = -zr, zr do
local z = sz + dz
for dy = -rr, rr do
for dx = -rr, rr do
local x = sx + dx
local y = sy + dy
local id = WPUtils.Coords2Id(x, y, z)
local buildingNode = gmd.Buildings and gmd.Buildings[id] or nil
if buildingNode and buildingNode.bid and buildingNode.bid ~= "" then
return buildingNode.bid
end
local barrelNode = gmd.Barrels and gmd.Barrels[id] or nil
if barrelNode and barrelNode.bid and barrelNode.bid ~= "" then
return barrelNode.bid
end
end
end
end
return nil
end
local function getBuildingBidFromDef(def)
if not def then
return nil
end
local bid = def:getIDString()
if bid and bid ~= "" then
return bid
end
return nil
end
local function getBuildingBidFromObject(building)
if not building then
return nil, nil
end
local def = building:getDef()
local bid = getBuildingBidFromDef(def)
if bid then
return bid, def
end
if building.getID then
local id = building:getID()
if id ~= nil then
return "WPBuilding_" .. tostring(id), nil
end
end
return nil, nil
end
local function getRoomSignature(room, square)
local rects = room and room.getRects and room:getRects()
if rects and rects:size() > 0 then
local minX, minY, minZ
local maxX, maxY, maxZ
for i = 0, rects:size() - 1 do
local rect = rects:get(i)
local rx1, ry1 = rect:getX(), rect:getY()
local rx2, ry2 = rect:getX2(), rect:getY2()
local rz = square:getZ()
if rect.getZ then
rz = rect:getZ()
end
if not minX then
minX, minY, minZ = rx1, ry1, rz
maxX, maxY, maxZ = rx2, ry2, rz
else
if rx1 < minX then minX = rx1 end
if ry1 < minY then minY = ry1 end
if rz < minZ then minZ = rz end
if rx2 > maxX then maxX = rx2 end
if ry2 > maxY then maxY = ry2 end
if rz > maxZ then maxZ = rz end
end
end
return tostring(minX) .. "_" .. tostring(minY) .. "_" .. tostring(minZ) .. "_" ..
tostring(maxX) .. "_" .. tostring(maxY) .. "_" .. tostring(maxZ)
end
return tostring(square:getX()) .. "_" .. tostring(square:getY()) .. "_" .. tostring(square:getZ())
end
local function getBuildingDescriptorFromPoweredSquares(square)
if not ModData or not ModData.getOrCreate then
return nil
end
local modData = ModData.getOrCreate("PoweredBuildings_Squares")
if not modData or not modData.PoweredSquares then
return nil
end
local searchSquares = getVerticalSearchSquares(square)
for _, sq in ipairs(searchSquares) do
local squareKey = sq:getX() .. "," .. sq:getY() .. "," .. sq:getZ()
local selectedGenKey, selectedSquares = nil, nil
for genKey, poweredSquares in pairs(modData.PoweredSquares) do
if poweredSquares and poweredSquares[squareKey] then
local genKeyStr = tostring(genKey)
if not selectedGenKey or genKeyStr < selectedGenKey then
selectedGenKey = genKeyStr
selectedSquares = poweredSquares
end
end
end
if selectedGenKey then
return {
bid = "WPGen_" .. selectedGenKey,
poweredSquares = selectedSquares,
}
end
end
return nil
end
local function getBuildingDescriptorFromRoom(square)
local searchSquares = getVerticalSearchSquares(square)
for _, sq in ipairs(searchSquares) do
local room = sq:getRoom()
if room then
return {
bid = "WPRoom_" .. getRoomSignature(room, sq),
room = room,
}
end
end
return nil
end
local function patchWPIso()
if not WPIso or not WPVirtual or not WPUtils then
return false
end
if WPIso.__WaterpipesB42PatchApplied then
return true
end
local function getBuildingDescriptorAtSquare(square)
if not square then
return nil
end
-- Prefer existing linked IDs to keep all taps in one network bid.
local linkedBid = findNearbyLinkedBid(square, 2, 1)
if linkedBid then
return { bid = linkedBid }
end
local searchSquares = getVerticalSearchSquares(square)
for _, sq in ipairs(searchSquares) do
local building = sq:getBuilding()
if building then
local bid, def = getBuildingBidFromObject(building)
if bid then
return {
bid = bid,
building = building,
def = def,
}
end
end
end
local poweredDescriptor = getBuildingDescriptorFromPoweredSquares(square)
if poweredDescriptor then
return poweredDescriptor
end
return getBuildingDescriptorFromRoom(square)
end
WPIso.GetBuildingDescriptor = function(square)
if not square then
return nil
end
local descriptor = getBuildingDescriptorAtSquare(square)
if descriptor then
return descriptor
end
-- Fallback for moveables/taps placed on edge or outside-flagged tiles:
-- scan neighboring squares and resolve against the nearest valid descriptor.
local cell = square:getCell()
local sx, sy, sz = square:getX(), square:getY(), square:getZ()
for dy = -1, 1 do
for dx = -1, 1 do
if not (dx == 0 and dy == 0) then
local nsq = cell and cell:getGridSquare(sx + dx, sy + dy, sz) or nil
if nsq then
descriptor = getBuildingDescriptorAtSquare(nsq)
if descriptor then
return descriptor
end
end
end
end
end
-- Final fallback: slightly wider linked-bid scan.
local linkedBid = findNearbyLinkedBid(square, 4, 2)
if linkedBid then
return { bid = linkedBid }
end
return nil
end
WPIso.GetBuildingBid = function(square)
local descriptor = WPIso.GetBuildingDescriptor(square)
if descriptor then
return descriptor.bid
end
return nil
end
WPIso.GetBuilding = function(square)
return WPIso.GetBuildingDescriptor(square)
end
WPIso.ConnectBuilding = function(square, building)
if not square then
return
end
local sx, sy, sz = square:getX(), square:getY(), square:getZ()
local cell = square:getCell()
local descriptor = building
if descriptor and descriptor.getDef then
local bid, def = getBuildingBidFromObject(descriptor)
descriptor = {
bid = bid,
building = descriptor,
def = def,
}
elseif not descriptor then
descriptor = WPIso.GetBuildingDescriptor(square)
end
if not descriptor or not descriptor.bid then
return
end
local bid = descriptor.bid
local traversed = {}
local function syncBarrelInSquare(sq)
if not sq then
return
end
local x, y, z = sq:getX(), sq:getY(), sq:getZ()
local key = WPUtils.Coords2Id(x, y, z)
if traversed[key] then
return
end
traversed[key] = true
local isoBarrel = WPIso.GetBarrel(sq)
if isoBarrel then
local _, wmax = WPIso.GetWaterStatus(isoBarrel)
WPVirtual.BarrelAdd(x, y, z, wmax * 100, bid)
end
end
if descriptor.def then
local def = descriptor.def
local bx1, bx2 = def:getX(), def:getX2()
local by1, by2 = def:getY(), def:getY2()
local bz1, bz2 = def:getMinLevel(), def:getMaxLevel()
for z = bz1, bz2 do
for y = by1, by2 do
for x = bx1, bx2 do
syncBarrelInSquare(cell:getGridSquare(x, y, z))
end
end
end
elseif descriptor.poweredSquares then
for tileKey, _ in pairs(descriptor.poweredSquares) do
local x, y, z = parseSquareKey(tileKey)
if x and y and z then
syncBarrelInSquare(cell:getGridSquare(x, y, z))
end
end
elseif descriptor.room then
local room = descriptor.room
local rects = room:getRects()
if rects then
for i = 0, rects:size() - 1 do
local rect = rects:get(i)
local rx1, ry1 = rect:getX(), rect:getY()
local rx2, ry2 = rect:getX2(), rect:getY2()
local rz = sz
if rect.getZ then
rz = rect:getZ()
end
for y = ry1, ry2 do
for x = rx1, rx2 do
local sq = cell:getGridSquare(x, y, rz)
if sq and sq:getRoom() == room then
syncBarrelInSquare(sq)
end
end
end
end
end
end
WPVirtual.BuildingAdd(sx, sy, sz, bid)
end
if not WPVirtual.__WaterpipesB42PatchApplied then
local originalBarrelAdd = WPVirtual.BarrelAdd
WPVirtual.BarrelAdd = function(x, y, z, wmax, bid)
if (not bid or bid == "") and WPIso and WPIso.GetBuildingBid and getCell then
local sq = getCell():getGridSquare(x, y, z)
if sq then
bid = WPIso.GetBuildingBid(sq)
end
end
return originalBarrelAdd(x, y, z, wmax, bid)
end
WPVirtual.__WaterpipesB42PatchApplied = true
end
WPIso.__WaterpipesB42PatchApplied = true
return true
end
local function tryApplyPatch()
if Patch.applied then
return
end
if patchWPIso() then
Patch.applied = true
end
end
local TRACE_MATRIX = {
ne = { n = {{x=1,y=0,z=0}}, e = {{x=0,y=-1,z=0}} },
se = { s = {{x=1,y=0,z=0}}, e = {{x=0,y=1,z=0}} },
sw = { s = {{x=-1,y=0,z=0}}, w = {{x=0,y=1,z=0}} },
nw = { n = {{x=-1,y=0,z=0}}, w = {{x=0,y=-1,z=0}} },
ns = { n = {{x=0,y=1,z=0}}, s = {{x=0,y=-1,z=0}} },
we = { w = {{x=1,y=0,z=0}}, e = {{x=-1,y=0,z=0}} },
nd = { n = {{x=0,y=0,z=-1}}, d = {{x=0,y=-1,z=0}} },
sd = { s = {{x=0,y=0,z=-1}}, d = {{x=0,y=1,z=0}} },
wd = { w = {{x=0,y=0,z=-1}}, d = {{x=-1,y=0,z=0}} },
ed = { e = {{x=0,y=0,z=-1}}, d = {{x=1,y=0,z=0}} },
nu = { n = {{x=0,y=0,z=1}}, u = {{x=0,y=-1,z=0}} },
su = { s = {{x=0,y=0,z=1}}, u = {{x=0,y=1,z=0}} },
wu = { w = {{x=0,y=0,z=1}}, u = {{x=-1,y=0,z=0}} },
eu = { e = {{x=0,y=0,z=1}}, u = {{x=1,y=0,z=0}} },
nsw = { n = {{x=-1,y=0,z=0},{x=0,y=1,z=0}}, s = {{x=-1,y=0,z=0},{x=0,y=-1,z=0}}, w = {{x=0,y=-1,z=0},{x=0,y=1,z=0}} },
swe = { s = {{x=-1,y=0,z=0},{x=1,y=0,z=0}}, w = {{x=1,y=0,z=0},{x=0,y=1,z=0}}, e = {{x=-1,y=0,z=0},{x=0,y=1,z=0}} },
nse = { n = {{x=1,y=0,z=0},{x=0,y=1,z=0}}, s = {{x=1,y=0,z=0},{x=0,y=-1,z=0}}, e = {{x=0,y=-1,z=0},{x=0,y=1,z=0}} },
nwe = { n = {{x=-1,y=0,z=0},{x=1,y=0,z=0}}, w = {{x=1,y=0,z=0},{x=0,y=-1,z=0}}, e = {{x=-1,y=0,z=0},{x=0,y=-1,z=0}} },
nswe = { n = {{x=-1,y=0,z=0},{x=1,y=0,z=0},{x=0,y=1,z=0}}, s = {{x=-1,y=0,z=0},{x=1,y=0,z=0},{x=0,y=-1,z=0}}, w = {{x=0,y=-1,z=0},{x=0,y=1,z=0},{x=1,y=0,z=0}}, e = {{x=0,y=-1,z=0},{x=0,y=1,z=0},{x=-1,y=0,z=0}} },
}
local function countEntries(t)
local c = 0
for _ in pairs(t) do
c = c + 1
end
return c
end
local function getTraceVectors(shape, dir)
local vectors = {}
local shapeData = TRACE_MATRIX[shape]
if shapeData and shapeData[dir] then
for _, vector in ipairs(shapeData[dir]) do
local d
if vector.x == 1 then d = "w" end
if vector.x == -1 then d = "e" end
if vector.y == 1 then d = "n" end
if vector.y == -1 then d = "s" end
if vector.z == 1 then d = "d" end
if vector.z == -1 then d = "u" end
table.insert(vectors, {x = vector.x, y = vector.y, z = vector.z, d = d})
end
end
return vectors
end
local function addDebugTile(set, x, y, z, symbol)
local id = WPUtils and WPUtils.Coords2Id and WPUtils.Coords2Id(x, y, z) or (tostring(x) .. "-" .. tostring(y) .. "-" .. tostring(z))
if not set[id] then
set[id] = {x = x, y = y, z = z, symbol = symbol}
end
end
local function tracePumpNetwork(gmd, pump)
local traced = {
pump = pump,
pipes = {},
targets = {},
closedValves = {},
}
local dirs = {
w = {x=1, y=0, z=0},
e = {x=-1, y=0, z=0},
n = {x=0, y=1, z=0},
s = {x=0, y=-1, z=0},
}
local stack = {}
for dir, vector in pairs(dirs) do
table.insert(stack, {x = pump.x + vector.x, y = pump.y + vector.y, z = pump.z + vector.z, dir = dir, depth = 0})
end
local visited = {}
local buildingBidsExpanded = {}
local safety = 0
while #stack > 0 do
local state = table.remove(stack)
safety = safety + 1
if safety > 5000 then
break
end
local stateKey = tostring(state.x) .. ":" .. tostring(state.y) .. ":" .. tostring(state.z) .. ":" .. tostring(state.dir)
if not visited[stateKey] and state.depth <= 128 then
visited[stateKey] = true
local nodeId = WPUtils.Coords2Id(state.x, state.y, state.z)
local pipe = gmd.Pipes[nodeId]
local barrel = gmd.Barrels[nodeId]
local building = gmd.Buildings[nodeId]
if pipe then
addDebugTile(traced.pipes, state.x, state.y, state.z, ".")
if gmd.Sprinklers[nodeId] then
addDebugTile(traced.targets, state.x, state.y, state.z, "S")
end
local valve = gmd.Valves[nodeId]
if valve and valve.c then
addDebugTile(traced.closedValves, state.x, state.y, state.z, "X")
else
local vectors = getTraceVectors(pipe.s, state.dir)
for _, vector in ipairs(vectors) do
table.insert(stack, {
x = state.x + vector.x,
y = state.y + vector.y,
z = state.z + vector.z,
dir = vector.d,
depth = state.depth + 1
})
end
end
elseif building then
addDebugTile(traced.targets, state.x, state.y, state.z, "B")
if building.bid and not buildingBidsExpanded[building.bid] then
buildingBidsExpanded[building.bid] = true
for _, barrelNode in pairs(gmd.Barrels) do
if barrelNode.bid == building.bid then
addDebugTile(traced.targets, barrelNode.x, barrelNode.y, barrelNode.z, "T")
end
end
end
elseif barrel then
addDebugTile(traced.targets, state.x, state.y, state.z, "R")
end
end
end
traced.pipeCount = countEntries(traced.pipes)
traced.targetCount = countEntries(traced.targets)
traced.closedValveCount = countEntries(traced.closedValves)
return traced
end
Patch.debugOverlay = Patch.debugOverlay or {
enabled = false,
recomputeEveryTicks = 30,
tick = 0,
cache = {},
unbound = {},
missingWorld = {},
}
local function isDebugModeEnabled()
if isDebugEnabled then
local ok, enabled = pcall(isDebugEnabled)
if ok and enabled then
return true
end
end
local core = getCore and getCore() or nil
if core then
if core.isDebug then
local ok, enabled = pcall(function() return core:isDebug() end)
if ok and enabled then
return true
end
end
if core.getDebug then
local ok, enabled = pcall(function() return core:getDebug() end)
if ok and enabled then
return true
end
end
end
return false
end
local function scanAndRegisterNearbyWorldBarrels()
if isServer() then
return
end
local player = getSpecificPlayer(0)
if not player then
return
end
local gmd = GetWPModData and GetWPModData() or nil
local cell = getCell and getCell() or nil
if not gmd or not cell or not WPIso or not WPIso.GetBarrel then
return
end
local px, py, pz = math.floor(player:getX()), math.floor(player:getY()), math.floor(player:getZ())
local radius = 22
local zMin = math.max(0, pz - 1)
local zMax = math.min(8, pz + 3)
local missing = {}
for z = zMin, zMax do
for y = py - radius, py + radius do
for x = px - radius, px + radius do
local sq = cell:getGridSquare(x, y, z)
if sq then
local isoBarrel = WPIso.GetBarrel(sq)
if isoBarrel then
local id = WPUtils.Coords2Id(x, y, z)
local barrelNode = gmd.Barrels and gmd.Barrels[id] or nil
if not barrelNode then
addDebugTile(missing, x, y, z, "M")
local _, wmax = WPIso.GetWaterStatus(isoBarrel)
local bid = WPIso.GetBuildingBid and WPIso.GetBuildingBid(sq) or nil
if (not bid or bid == "") then
bid = findNearbyLinkedBid(sq, 4, 2)
end
if WPVirtual and WPVirtual.BarrelAdd then
WPVirtual.BarrelAdd(x, y, z, (wmax or 40) * 100, bid)
end
end
end
end
end
end
end
Patch.debugOverlay.missingWorld = missing
end
local function relinkUnboundBarrels()
if isServer() then
return
end
local player = getSpecificPlayer(0)
if not player then
return
end
local gmd = GetWPModData and GetWPModData() or nil
if not gmd or not gmd.Barrels then
return
end
local cell = getCell and getCell() or nil
if not cell or not WPIso or not WPIso.GetBuildingBid then
return
end
for _, barrel in pairs(gmd.Barrels) do
local sq = cell:getGridSquare(barrel.x, barrel.y, barrel.z)
if sq then
local bid = WPIso.GetBuildingBid(sq)
if not bid or bid == "" then
bid = findNearbyLinkedBid(sq, 3, 2)
end
if bid and bid ~= barrel.bid and sendClientCommand then
barrel.bid = bid
sendClientCommand(player, "Commands", "BarrelMod", {
x = barrel.x,
y = barrel.y,
z = barrel.z,
bid = bid,
})
end
end
end
-- Also discover physical sinks/taps that never entered virtual data.
scanAndRegisterNearbyWorldBarrels()
end
local function recomputeDebugOverlay()
if isServer() then
return
end
local gmd = GetWPModData and GetWPModData() or nil
if not gmd or not gmd.Pumps then
Patch.debugOverlay.cache = {}
return
end
local out = {}
local unbound = {}
for _, pump in pairs(gmd.Pumps) do
table.insert(out, tracePumpNetwork(gmd, pump))
end
for _, barrel in pairs(gmd.Barrels or {}) do
if not barrel.bid or barrel.bid == "" then
addDebugTile(unbound, barrel.x, barrel.y, barrel.z, "U")
end
end
Patch.debugOverlay.cache = out
Patch.debugOverlay.unbound = unbound
end
local function drawTextSafe(x, y, text, r, g, b, a)
local tm = getTextManager and getTextManager() or nil
if not tm then
return
end
local ok = false
if UIFont and tm.DrawString then
ok = pcall(function()
tm:DrawString(UIFont.Small, x, y, text, r, g, b, a)
end)
end
if not ok and tm.DrawString then
pcall(function()
tm:DrawString(x, y, text, r, g, b, a)
end)
end
end
local function drawTileSymbol(playerNum, tile, text, r, g, b, a)
local tx = isoToScreenX(playerNum, tile.x + 0.5, tile.y + 0.5, tile.z)
local ty = isoToScreenY(playerNum, tile.x + 0.5, tile.y + 0.5, tile.z)
drawTextSafe(tx, ty, text, r, g, b, a)
end
local function renderDebugOverlay()
if isServer() then
return
end
if not Patch.debugOverlay.enabled then
return
end
if not isIngameState() then
return
end
local player = getSpecificPlayer(0)
if not player then
return
end
Patch.debugOverlay.tick = Patch.debugOverlay.tick + 1
if Patch.debugOverlay.tick % Patch.debugOverlay.recomputeEveryTicks == 0 then
recomputeDebugOverlay()
end
local playerNum = player:getPlayerNum()
local px, py, pz = player:getX(), player:getY(), player:getZ()
local range = 55
local yLine = 186
local unboundCount = countEntries(Patch.debugOverlay.unbound or {})
local missingWorldCount = countEntries(Patch.debugOverlay.missingWorld or {})
drawTextSafe(20, 150, "[WP DEBUG] Pump grid overlay ON (P pump, . pipe, B building node, T tap, R barrel, S sprinkler, X closed valve)", 0.8, 0.95, 1.0, 0.95)
drawTextSafe(20, 166, string.format("[WP DEBUG] Unbound taps (U): %d (auto relink every 1 in-game minute)", unboundCount), 1.0, 0.45, 0.45, 0.95)
drawTextSafe(20, 182, string.format("[WP DEBUG] Missing virtual taps (M): %d (physical object found, auto-registering)", missingWorldCount), 1.0, 0.65, 0.2, 0.95)
for _, traced in ipairs(Patch.debugOverlay.cache) do
local pump = traced.pump
local pActive = tostring(pump.active == true)
local pSource = pump.source and tostring(pump.source) or "none"
local summary = string.format("Pump %d,%d,%d active=%s source=%s pipes=%d targets=%d closedValves=%d",
pump.x, pump.y, pump.z, pActive, pSource, traced.pipeCount or 0, traced.targetCount or 0, traced.closedValveCount or 0)
drawTextSafe(20, yLine, summary, 0.6, 0.9, 1.0, 0.95)
yLine = yLine + 16
if math.abs(pump.x - px) <= range and math.abs(pump.y - py) <= range and math.abs(pump.z - pz) <= 4 then
drawTileSymbol(playerNum, {x = pump.x, y = pump.y, z = pump.z}, "P", 0.25, 0.65, 1.0, 1.0)
end
for _, tile in pairs(traced.pipes) do
if math.abs(tile.x - px) <= range and math.abs(tile.y - py) <= range and math.abs(tile.z - pz) <= 4 then
drawTileSymbol(playerNum, tile, ".", 0.35, 0.95, 1.0, 0.9)
end
end
for _, tile in pairs(traced.targets) do
if math.abs(tile.x - px) <= range and math.abs(tile.y - py) <= range and math.abs(tile.z - pz) <= 4 then
local symbol = tile.symbol or "T"
if symbol == "B" then
drawTileSymbol(playerNum, tile, symbol, 1.0, 0.9, 0.2, 1.0)
elseif symbol == "S" then
drawTileSymbol(playerNum, tile, symbol, 0.8, 0.9, 1.0, 1.0)
elseif symbol == "R" then
drawTileSymbol(playerNum, tile, symbol, 0.95, 0.65, 1.0, 1.0)
else
drawTileSymbol(playerNum, tile, symbol, 0.35, 1.0, 0.4, 1.0)
end
end
end
for _, tile in pairs(traced.closedValves) do
if math.abs(tile.x - px) <= range and math.abs(tile.y - py) <= range and math.abs(tile.z - pz) <= 4 then
drawTileSymbol(playerNum, tile, "X", 1.0, 0.25, 0.25, 1.0)
end
end
end
for _, tile in pairs(Patch.debugOverlay.unbound or {}) do
if math.abs(tile.x - px) <= range and math.abs(tile.y - py) <= range and math.abs(tile.z - pz) <= 4 then
drawTileSymbol(playerNum, tile, "U", 1.0, 0.2, 0.2, 1.0)
end
end
for _, tile in pairs(Patch.debugOverlay.missingWorld or {}) do
if math.abs(tile.x - px) <= range and math.abs(tile.y - py) <= range and math.abs(tile.z - pz) <= 4 then
drawTileSymbol(playerNum, tile, "M", 1.0, 0.7, 0.1, 1.0)
end
end
end
local function onPumpDebugToggle(_player, _context, _worldobjects, _test)
if isServer() then
return
end
if not isDebugModeEnabled() then
return
end
local fetch = ISWorldObjectContextMenu and ISWorldObjectContextMenu.fetchVars or nil
local square = fetch and fetch.clickedSquare or nil
if not square or not WPIso or not WPIso.GetPump then
return
end
local isoPump = WPIso.GetPump(square)
if not isoPump then
return
end
local context = _context
if not context then
return
end
local label
if Patch.debugOverlay.enabled then
label = "[WP DEBUG] Hide Pump Overlay"
else
label = "[WP DEBUG] Show Pump Overlay"
end
context:addOption(label, nil, function()
Patch.debugOverlay.enabled = not Patch.debugOverlay.enabled
if Patch.debugOverlay.enabled then
scanAndRegisterNearbyWorldBarrels()
recomputeDebugOverlay()
end
end)
end
if Events and Events.OnGameBoot then
Events.OnGameBoot.Add(tryApplyPatch)
end
if Events and Events.OnGameStart then
Events.OnGameStart.Add(tryApplyPatch)
end
if Events and Events.OnInitGlobalModData then
Events.OnInitGlobalModData.Add(tryApplyPatch)
end
if Events and Events.OnPreUIDraw then
Events.OnPreUIDraw.Add(renderDebugOverlay)
end
if Events and Events.OnPreFillWorldObjectContextMenu then
Events.OnPreFillWorldObjectContextMenu.Add(onPumpDebugToggle)
end
if Events and Events.EveryOneMinute then
Events.EveryOneMinute.Add(relinkUnboundBarrels)
end
tryApplyPatch()