From 322655f48337c447501b8847e7b9b63ebbfbeb6d Mon Sep 17 00:00:00 2001 From: mrkubax10 Date: Mon, 12 May 2025 21:44:33 +0200 Subject: [PATCH] Implement cable melting --- api/network.lua | 129 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 2 deletions(-) diff --git a/api/network.lua b/api/network.lua index c5df7ff..584779a 100644 --- a/api/network.lua +++ b/api/network.lua @@ -41,6 +41,102 @@ local function clampFlow(pos,flow) return math.min(flow,newFlow) end +-- \brief Finds path from pos to dest in network. Function finished if either dest is found or every node was visited +-- \param pos Vector +-- \param dest Vector +-- \returns table or nil +function industrialtest.api.findPathInNetwork(pos,dest) + local connections=industrialtest.api.getConnections(pos,"i") + if #connections==0 then + return nil + end + + local workers={} + local serializedSourcePos=pos.x..","..pos.y..","..pos.z + local visitedNodes={[serializedSourcePos]=true} + for _,conn in ipairs(connections) do + local sideVector=vector.subtract(conn,pos) + table.insert(workers,{ + position=conn, + direction=sideVector, + path={[1]=conn} + }) + end + + while #workers>0 do + for i=1,#workers do + local worker=workers[i] + local serializedPos=worker.position.x..","..worker.position.y..","..worker.position.z + if visitedNodes[serializedPos] then + table.remove(workers,i) + break + end + visitedNodes[serializedPos]=true + + if worker.position.x==dest.x and worker.position.y==dest.y and worker.position.z==dest.z then + return worker.path + end + + local def=minetest.registered_nodes[minetest.get_node(worker.position).name] + if def and def.groups and def.groups._industrialtest_cable then + connections=industrialtest.api.getConnections(worker.position,"i") + for j=1,#connections do + local direction=vector.subtract(connections[j],worker.position) + local oppositeDirection=vector.multiply(worker.direction,vector.new(-1,-1,-1)) + if direction.x~=oppositeDirection.x or direction.y~=oppositeDirection.y or direction.z~=oppositeDirection.z then + if worker.direction.x~=direction.x or worker.direction.y~=direction.y or worker.direction.z~=direction.z then + table.insert(worker.path,worker.position) + end + for c=1,#connections do + local nextDirection=vector.subtract(connections[c],worker.position) + if c~=j and (nextDirection.x~=oppositeDirection.x or nextDirection.y~=oppositeDirection.y or nextDirection.z~=oppositeDirection.z) then + local newWorker={ + position=connections[c], + direction=nextDirection, + path=table.copy(worker.path) + } + table.insert(newWorker.path,worker.position) + table.insert(workers,newWorker) + end + end + worker.direction=direction + worker.position=connections[j] + break + end + end + + if #connections>2 then + break + end + else + table.remove(workers,i) + break + end + end + end + + return nil +end + +-- \brief Goes through path vertices specified by path running callback on each node. +-- Function finishes if either callback returns false or entire path is went over. +-- \param path table +-- \param callback function +-- \returns nil +function industrialtest.api.walkPath(path,callback) + local pos=path[1] + for i=2,#path do + local pathNode=path[i] + local direction=vector.normalize(vector.subtract(pathNode,pos)) + while pos.x~=pathNode.x or pos.y~=pathNode.y or pos.z~=pathNode.z do + if not callback(pos) then + return + end + pos=vector.add(pos,direction) + end + end +end + -- \brief Transfers power from source node to it's network, if sides is set then power will be only transfered to network connected to that sides -- \param pos Vector with position of source node -- \param (optional) sides table with Vectors @@ -100,8 +196,36 @@ function industrialtest.api.powerFlow(pos,sides,flowOverride) roomAvailable=true end else - minetest.remove_node(endpoint.position) - industrialtest.internal.explode(endpoint.position,2) + local path=industrialtest.api.findPathInNetwork(pos,endpoint.position) + if path and #path>0 then + table.insert(path,endpoint.position) + local removed=false + industrialtest.api.walkPath(path,function(pathPos) + local def=minetest.registered_nodes[minetest.get_node(pathPos).name] + if not def or not def.groups or not def.groups._industrialtest_cable then + return false + end + if powerDistribution>def._industrialtest_cableFlow then + removed=true + minetest.swap_node(pathPos,{ + name="air" + }) + minetest.remove_node(pathPos) + minetest.check_for_falling(pathPos) + minetest.sound_play("default_cool_lava",{ + pos=pathPos, + max_hear_distance=5, + gain=0.7 + }) + end + return true + end) + if not removed and powerDistribution>endpoint.originalFlow then + minetest.remove_node(endpoint.position) + industrialtest.internal.explode(endpoint.position,2) + end + industrialtest.api.createNetworkMapForNode(pos) + end end end end @@ -199,6 +323,7 @@ function industrialtest.api.createNetworkMap(pos,addCables,omit) position=worker.position, distance=worker.distance, flow=math.min(worker.flow,flow), + originalFlow=flow, side=connectionSide, sourceSide=worker.sourceSide })