From 7a6dacb614b4f49493e5c86283d25cc8004be74b Mon Sep 17 00:00:00 2001 From: mrkubax10 Date: Sun, 12 Nov 2023 14:59:18 +0100 Subject: [PATCH] Implement industrialtest.api.createNetworkMap --- api.lua | 191 ++++++++++++++++++++++++++++++++++------------------- cables.lua | 1 + 2 files changed, 124 insertions(+), 68 deletions(-) diff --git a/api.lua b/api.lua index 84c4a96..c9f9133 100644 --- a/api.lua +++ b/api.lua @@ -216,90 +216,140 @@ industrialtest.api.transferPowerFromItem=function(srcItemstack,meta,amount) industrialtest.api.addPowerToItem(srcItemstack,-actualFlow) return actualFlow end + -- \brief Transfers power from source node to all neighbouring nodes -- \param pos Vector with position of source node -- \returns two values: true if any neighbouring node has room for more power, false otherwise -- true if any power was transferred, false otherwise industrialtest.api.powerFlow=function(pos) local meta=minetest.get_meta(pos) - if not industrialtest.api.hasPowerStorage(meta) then - return false + -- if machine doesn't have network map then it's not capable of transferring power + if not meta:contains("industrialtest.network") then + return false,false end - local neighbourPositions={ - vector.offset(pos,-1,0,0), - vector.offset(pos,1,0,0), - vector.offset(pos,0,-1,0), - vector.offset(pos,0,1,0), - vector.offset(pos,0,0,-1), - vector.offset(pos,0,0,1) - } - local neighbours={} - for key,value in ipairs(neighbourPositions) do - neighbours[key]=minetest.get_meta(value) - end - local neighboursContainingPower=0 - for key,value in ipairs(neighbours) do - local side=industrialtest.api.getOppositeSide(key) - if industrialtest.api.hasPowerStorage(value) and industrialtest.api.isPowerInput(value,side) and not industrialtest.api.isFullyCharged(value) then - neighboursContainingPower=neighboursContainingPower+1 - else - neighbourPositions[key]=0 - neighbours[key]=0 - end - end - if neighboursContainingPower==0 then - return false + local network=minetest.deserialize(meta:get_string("industrialtest.network")) + if #network==0 then + return false,false end local powerFlow=meta:get_int("industrialtest.powerFlow") - local powerDistribution=math.floor(powerFlow/neighboursContainingPower) - -- TODO: if supplying machine power flow is too large for receiving machine to handle then that machine should explode - local roomAvailable=false + local powerDistribution=math.floor(powerFlow/#network) local transferred=false - for key,value in ipairs(neighbours) do - if value~=0 then - local normalizedKey=industrialtest.api.normalizeSide(pos,key) - if industrialtest.api.isPowerOutput(meta,normalizedKey) then - if industrialtest.api.transferPower(meta,value,powerDistribution)>0 then - transferred=true - end - local def=minetest.registered_nodes[minetest.get_node(neighbourPositions[key]).name] - if def then - local updateFormspec=def._industrialtest_updateFormspec - if updateFormspec then - updateFormspec(neighbourPositions[key]) - end - local onPowerFlow=def._industrialtest_onPowerFlow - if onPowerFlow and transferred then - onPowerFlow(neighbourPositions[key],industrialtest.api.getOppositeSide(key)) + local roomAvailable=false + for _,endpoint in ipairs(network) do + local endpointMeta=minetest.get_meta(endpoint.position) + -- TODO: if supplying machine power flow is too large for receiving machine to handle then that machine should explode + local transferredToEndpoint=false + if industrialtest.api.transferPower(meta,endpointMeta,powerDistribution)>0 then + transferred=true + transferredToEndpoint=true + end + local def=minetest.registered_nodes[minetest.get_node(endpoint.position).name] + if def then + local updateFormspec=def._industrialtest_updateFormspec + if updateFormspec then + updateFormspec(endpoint.position) + end + local onPowerFlow=def._industrialtest_onPowerFlow + if onPowerFlow and transferredToEndpoint then + onPowerFlow(endpoint.position,industrialtest.api.getOppositeSide(1)) + end + end + minetest.get_node_timer(endpoint.position):start(industrialtest.updateDelay) + if not industrialtest.api.isFullyCharged(endpointMeta) then + roomAvailable=true + end + end + return roomAvailable,transferred +end + +local function addNodeToNetwork(pos,networkMasterPos) + local meta=minetest.get_meta(pos) + local networks={} + if meta:contains("industrialtest.networks") then + networks=minetest.deserialize(meta:get_string("industrialtest.networks")) + end + for _,network in ipairs(networks) do + if network==networkMasterPos then + return + end + end + table.insert(networks,networkMasterPos) + meta:set_string("industrialtest.networks",minetest.serialize(networks)) +end + +-- \brief Creates network map starting from node at pos +-- \param pos vector +-- \returns table with network map +industrialtest.api.createNetworkMap=function(pos) + local workers={} + local map={} + local connections=industrialtest.api.getConnections(pos) + if #connections==0 then + return map + end + local serializedSourcePos=pos.x..","..pos.y..","..pos.z + local visitedNodes={[serializedSourcePos]=true} + for _,value in ipairs(connections) do + visitedNodes[value.x..","..value.y..","..value.z]=true + table.insert(workers,{ + position=value, + distance=1, + }) + end + while #workers>0 do + for _,worker in ipairs(workers) do + local connections=industrialtest.api.getConnections(worker.position) + if #connections==0 then + table.remove(workers,i) + break + else + local directionAssigned=false + local foundNewNode=false + for _,conn in ipairs(connections) do + local serializedPos=conn.x..","..conn.y..","..conn.z + if not visitedNodes[serializedPos] then + local def=minetest.registered_nodes[minetest.get_node(conn).name] + visitedNodes[serializedPos]=true + foundNewNode=true + addNodeToNetwork(conn,serializedSourcePos) + if def.groups._industrialtest_cable then + if directionAssigned then + table.insert(workers,{ + position=conn, + distance=worker.distance+1 + }) + else + worker.position=conn + worker.distance=worker.distance+1 + directionAssigned=true + end + else + table.insert(map,{ + position=conn, + distance=worker.distance + }) + if #connections==1 then + table.remove(workers,i) + break + end + end end end - minetest.get_node_timer(neighbourPositions[key]):start(industrialtest.updateDelay) - if not industrialtest.api.isFullyCharged(value) then - roomAvailable=true + if not foundNewNode then + table.remove(workers,i) + break end end end end - return roomAvailable,transferred + return map end -- \brief Starts node timer of neighbouring nodes with center node -- \param pos Vector with position of center node -- \returns nil industrialtest.api.triggerNeighbours=function(pos) - local neighbourPositions={ - vector.offset(pos,-1,0,0), - vector.offset(pos,1,0,0), - vector.offset(pos,0,-1,0), - vector.offset(pos,0,1,0), - vector.offset(pos,0,0,-1), - vector.offset(pos,0,0,1) - } - for key,value in ipairs(neighbourPositions) do - local meta=minetest.get_meta(value) - local side=industrialtest.api.getOppositeSide(key) - if industrialtest.api.hasPowerStorage(meta) and industrialtest.api.isPowerOutput(meta,side) then - minetest.get_node_timer(value):start(industrialtest.updateDelay) - end + for _,value in ipairs(industrialtest.api.getConnections(pos)) do + minetest.get_node_timer(value):start(industrialtest.updateDelay) end end -- \brief Returns opposite side of provided one @@ -321,12 +371,17 @@ industrialtest.api.getConnections=function(pos) vector.offset(pos,0,0,-1), vector.offset(pos,0,0,1) } - local index=1 + local sourceMeta=minetest.get_meta(pos) for key,value in ipairs(neighbourPositions) do - local meta=minetest.get_meta(value) - if industrialtest.api.hasPowerStorage(meta) then - result[index]=key - index=index+1 + local def=minetest.registered_nodes[minetest.get_node(value).name] + if def.groups._industrialtest_cable then + table.insert(result,value) + else + local meta=minetest.get_meta(value) + local side=industrialtest.api.getOppositeSide(key) + if def.groups._industrialtest_hasPowerInput and industrialtest.api.isPowerOutput(sourceMeta,key) and industrialtest.api.isPowerInput(meta,side) then + table.insert(result,value) + end end end return result diff --git a/cables.lua b/cables.lua index feb349a..93078b4 100644 --- a/cables.lua +++ b/cables.lua @@ -142,6 +142,7 @@ local function registerCable(name,displayName,size,flow,registerInsulated) definition.sound=mcl_sounds.node_sound_metal_defaults() end definition.groups._industrialtest_hasPowerInput=1 + definition.groups._industrialtest_cable=1 minetest.register_node("industrialtest:"..name.."_cable",definition) if registerInsulated then definition=table.copy(definition)