From fd772f3c551a6f896098ca3b7ac0ba132f4413f9 Mon Sep 17 00:00:00 2001 From: mrkubax10 Date: Wed, 2 Apr 2025 23:02:26 +0200 Subject: [PATCH] Rewrite `industrialtest.api.createNetworkMap` and few other network related features --- api/network.lua | 151 +++++++++++++++++++++--------------------------- api/power.lua | 67 +++++++++++++++++---- 2 files changed, 121 insertions(+), 97 deletions(-) diff --git a/api/network.lua b/api/network.lua index 7ce6d6c..f2dca76 100644 --- a/api/network.lua +++ b/api/network.lua @@ -64,11 +64,21 @@ function industrialtest.api.powerFlow(pos,sides,flowOverride) if endpointCount==0 then return false,false end - local powerDistribution=math.floor((flowOverride and flowOverride or math.min(meta:get_int("industrialtest.powerAmount"),meta:get_int("industrialtest.powerFlow")))/endpointCount) + + local ioConfig=industrialtest.api.getIoConfig(meta) local transferred=false local roomAvailable=false for _,endpoint in ipairs(network) do if not sides or sides[endpoint.sourceSide] then + local flow + if flowOverride then + flow=flowOverride + elseif type(ioConfig)=="string" then + flow=math.min(meta:get_int("industrialtest.powerAmount"),meta:get_int("industrialtest.powerFlow")) + else + flow=math.min(meta:get_int("industrialtest.powerAmount"),ioConfig[endpoint.sourceSide].flow) + end + local powerDistribution=math.floor(flow/endpointCount) local endpointMeta=minetest.get_meta(endpoint.position) if powerDistribution<=endpoint.flow then local transferredPower=industrialtest.api.transferPower(meta,endpointMeta,powerDistribution) @@ -104,12 +114,14 @@ end -- \param (optional) omit Vector -- \returns table with network map function industrialtest.api.createNetworkMap(pos,addCables,omit) - local workers={} - local map={} local connections=industrialtest.api.getConnections(pos,"i") if #connections==0 then return map end + + local sourceMeta=minetest.get_meta(pos) + local workers={} + local map={} local sides={ ["-1,0,0"]=1, ["1,0,0"]=2, @@ -122,104 +134,71 @@ function industrialtest.api.createNetworkMap(pos,addCables,omit) local visitedNodes={[serializedSourcePos]=true} for _,conn in ipairs(connections) do if not omit or conn.x~=omit.x or conn.y~=omit.y or conn.z~=omit.z then - visitedNodes[conn.x..","..conn.y..","..conn.z]=true - addNodeToNetwork(conn,pos) local sideVector=vector.subtract(conn,pos) local serializedSideVector=sideVector.x..","..sideVector.y..","..sideVector.z - local def=minetest.registered_nodes[minetest.get_node(conn).name] - if def.groups._industrialtest_cable then - table.insert(workers,{ - position=conn, - targetPosition=conn, - distance=1, - flow=def._industrialtest_cableFlow, - targetFlow=0, - sourceSide=industrialtest.api.normalizeSide(pos,sides[serializedSideVector]) - }) - if addCables then - table.insert(map,{ - position=conn, - distance=0 - }) - end - else - local meta=minetest.get_meta(conn) - table.insert(map,{ - position=conn, - distance=0, - flow=meta:get_int("industrialtest.powerFlow"), - side=sides[serializedSideVector], - sourceSide=industrialtest.api.normalizeSide(pos,sides[serializedSideVector]) - }) - end + local sourceSide=industrialtest.api.normalizeSide(pos,sides[serializedSideVector]) + table.insert(workers,{ + position=conn, + direction=sideVector, + distance=1, + flow=industrialtest.api.getPowerFlowForSide(sourceMeta,sourceSide), + sourceSide=sourceSide + }) end end + while #workers>0 do for i=1,#workers do local worker=workers[i] - connections=industrialtest.api.getConnections(worker.position,"i") - if #connections==0 then + local serializedPos=worker.position.x..","..worker.position.y..","..worker.position.z + if visitedNodes[serializedPos] or (omit and omit==worker.position) then table.remove(workers,i) break - else - local directionAssigned=false - local foundNewNode=false - for _,conn in ipairs(connections) do - if not omit or conn.x~=omit.x or conn.y~=omit.y or conn.z~=omit.z then - 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,pos) - if def.groups._industrialtest_cable then - if directionAssigned then - table.insert(workers,{ - position=conn, - targetPosition=conn, - distance=worker.distance+1, - flow=clampFlow(conn,worker.flow), - targetFlow=0, - sourceSide=worker.sourceSide - }) - else - worker.targetPosition=conn - worker.distance=worker.distance+1 - worker.targetFlow=clampFlow(conn,worker.flow) - directionAssigned=true - end - if addCables then - table.insert(map,{ - position=conn, - distance=worker.distance+1, - }) - end - else - local sideVector=vector.subtract(conn,worker.position) - table.insert(map,{ - position=conn, - distance=worker.distance, - flow=clampFlow(conn,worker.flow), - side=sides[sideVector.x..","..sideVector.y..","..sideVector.z], - sourceSide=worker.sourceSide - }) - if #connections==1 then - foundNewNode=false - break - end - end - end - end - end - if not foundNewNode then + end + visitedNodes[serializedPos]=true + addNodeToNetwork(worker.position,pos) + + 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") + if #connections==0 then table.remove(workers,i) break end - worker.position=worker.targetPosition - worker.flow=worker.targetFlow + worker.flow=clampFlow(worker.position,worker.flow) + worker.distance=worker.distance+1 + for i=2,#connections do + table.insert(workers,{ + position=connections[i], + direction=vector.subtract(connections[i],worker.position), + distance=worker.distance, + flow=worker.flow, + sourceSide=worker.sourceSide + }) + end + worker.direction=vector.subtract(connections[1],worker.position) + worker.position=connections[1] + if #connections>=2 then + break + end + else + local meta=minetest.get_meta(worker.position) + local incomingSide=industrialtest.api.normalizeSide(worker.position,sides[worker.direction.x..","..worker.direction.y..","..worker.direction.z]) + local connectionSide=industrialtest.api.getOppositeSide(incomingSide) + local flow=industrialtest.api.getPowerFlowForSide(meta,connectionSide) + table.insert(map,{ + position=worker.position, + distance=worker.distance, + flow=math.min(worker.flow,flow), + side=connectionSide, + sourceSide=worker.sourceSide + }) + table.remove(workers,i) + break end end end + return map end diff --git a/api/power.lua b/api/power.lua index 49c673d..b75387d 100644 --- a/api/power.lua +++ b/api/power.lua @@ -20,13 +20,16 @@ local S=minetest.get_translator("industrialtest") -- \param capacity How much EU item/node can store -- \param flow How much EU can flow in or out item/node per industrialtest.updateDelay -- \param ioConfig Input/Output configuration in following side order: -X, +X, -Y, +Y, -Z, +Z --- a - bidirectional, i - input, o - output +-- a - bidirectional, i - input, o - output. +-- Instead of string containing IO mode for each side, ioConfig can hold a table for each side, containing +-- IO mode and flow override -- \returns nil function industrialtest.api.addPowerStorage(meta,capacity,flow,ioConfig) meta:set_int("industrialtest.powerCapacity",capacity) meta:set_int("industrialtest.powerFlow",flow) meta:set_int("industrialtest.powerAmount",0) - meta:set_string("industrialtest.ioConfig",ioConfig) + meta:set_int("industrialtest.extendedIoConfig",type(ioConfig)~="string") + meta:set_string("industrialtest.ioConfig",type(ioConfig)=="string" and ioConfig or minetest.serialize(ioConfig)) end -- \brief Checks if metadata contains power storage @@ -42,15 +45,49 @@ function industrialtest.api.hasPowerStorage(meta) return true end +-- \brief Checks if ioConfig from metadata is extended one. It exploits the fact that minetest.serialize returns Lua code +-- which returns table, hence it can check for return at the beginning of the string +-- \param meta MetaDataRef +-- \returns bool +function industrialtest.api.isExtendedIoConfig(meta) + return meta:get_int("industrialtest.extendedIoConfig")==1 +end + +-- \brief Returns ioConfig from metadata, deserializing it if it's extended one +-- \param meta MetaDataRef +-- \returns table or string +function industrialtest.api.getIoConfig(meta) + local ioConfig=meta:get_string("industrialtest.ioConfig") + return industrialtest.api.isExtendedIoConfig(meta) and minetest.deserialize(ioConfig) or ioConfig +end + -- \brief Changes node's power IO config. Function doesn't check if meta actually contains power storage. -- \param meta MetaDataRef of node which power IO config should be changed -- \param side Side number. See industrialtest.api.addPowerStorage to check order. -- \param mode Side mode. See industrialtest.api.addPowerStorage for possible values. -- \returns nil function industrialtest.api.changeIoConfig(meta,side,mode) - local ioConfig=meta:get_string("industrialtest.ioConfig") - ioConfig=string.sub(ioConfig,1,side-1)..mode..string.sub(ioConfig,side+1) - meta:set_string("industrialtest.ioConfig",ioConfig) + local ioConfig=industrialtest.api.getIoConfig(meta) + if type(ioConfig)=="string" then + ioConfig=string.sub(ioConfig,1,side-1)..mode..string.sub(ioConfig,side+1) + meta:set_string("industrialtest.ioConfig",ioConfig) + else + ioConfig[side]=mode + meta:set_string("industrialtest.ioConfig",minetest.serialize(ioConfig)) + end +end + +-- \brief Returns power flow for side +-- \param meta MetaDataRef +-- \param side number Side number +-- \returns number +function industrialtest.api.getPowerFlowForSide(meta,side) + local ioConfig=industrialtest.api.getIoConfig(meta) + if type(ioConfig)=="string" then + return meta:get_int("industrialtest.powerFlow") + else + return ioConfig[side].flow + end end -- \brief Checks if provided side is power input @@ -58,9 +95,13 @@ end -- \param side Side number. See industrialtest.api.addPowerStorage to check order. -- \returns true if provided side is power input, false otherwise function industrialtest.api.isPowerInput(meta,side) - local ioConfig=meta:get_string("industrialtest.ioConfig") - local mode=string.sub(ioConfig,side,side) - return (mode=="i" or mode=="a") + local ioConfig=industrialtest.api.getIoConfig(meta) + if type(ioConfig)=="string" then + local mode=string.sub(ioConfig,side,side) + return (mode=="i" or mode=="a") + else + return (ioConfig[side].direction=="i" or ioConfig[side].direction=="a") + end end -- \brief Checks if provided side is power output @@ -68,9 +109,13 @@ end -- \param side Side number. See industrialtest.api.addPowerStorage to check order. -- \returns true if provided side is power output, false otherwise function industrialtest.api.isPowerOutput(meta,side) - local ioConfig=meta:get_string("industrialtest.ioConfig") - local mode=string.sub(ioConfig,side,side) - return (mode=="o" or mode=="a") + local ioConfig=industrialtest.api.getIoConfig(meta) + if type(ioConfig)=="string" then + local mode=string.sub(ioConfig,side,side) + return (mode=="o" or mode=="a") + else + return (ioConfig[side].direction=="o" or ioConfig[side].direction=="a") + end end -- \brief Checks if power storage is fully charged