Implement industrialtest.api.createNetworkMap

This commit is contained in:
mrkubax10 2023-11-12 14:59:18 +01:00
parent 71480f6a62
commit 7a6dacb614
2 changed files with 124 additions and 68 deletions

191
api.lua
View File

@ -216,90 +216,140 @@ industrialtest.api.transferPowerFromItem=function(srcItemstack,meta,amount)
industrialtest.api.addPowerToItem(srcItemstack,-actualFlow) industrialtest.api.addPowerToItem(srcItemstack,-actualFlow)
return actualFlow return actualFlow
end end
-- \brief Transfers power from source node to all neighbouring nodes -- \brief Transfers power from source node to all neighbouring nodes
-- \param pos Vector with position of source node -- \param pos Vector with position of source node
-- \returns two values: true if any neighbouring node has room for more power, false otherwise -- \returns two values: true if any neighbouring node has room for more power, false otherwise
-- true if any power was transferred, false otherwise -- true if any power was transferred, false otherwise
industrialtest.api.powerFlow=function(pos) industrialtest.api.powerFlow=function(pos)
local meta=minetest.get_meta(pos) local meta=minetest.get_meta(pos)
if not industrialtest.api.hasPowerStorage(meta) then -- if machine doesn't have network map then it's not capable of transferring power
return false if not meta:contains("industrialtest.network") then
return false,false
end end
local neighbourPositions={ local network=minetest.deserialize(meta:get_string("industrialtest.network"))
vector.offset(pos,-1,0,0), if #network==0 then
vector.offset(pos,1,0,0), return false,false
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
end end
local powerFlow=meta:get_int("industrialtest.powerFlow") local powerFlow=meta:get_int("industrialtest.powerFlow")
local powerDistribution=math.floor(powerFlow/neighboursContainingPower) local powerDistribution=math.floor(powerFlow/#network)
-- TODO: if supplying machine power flow is too large for receiving machine to handle then that machine should explode
local roomAvailable=false
local transferred=false local transferred=false
for key,value in ipairs(neighbours) do local roomAvailable=false
if value~=0 then for _,endpoint in ipairs(network) do
local normalizedKey=industrialtest.api.normalizeSide(pos,key) local endpointMeta=minetest.get_meta(endpoint.position)
if industrialtest.api.isPowerOutput(meta,normalizedKey) then -- TODO: if supplying machine power flow is too large for receiving machine to handle then that machine should explode
if industrialtest.api.transferPower(meta,value,powerDistribution)>0 then local transferredToEndpoint=false
transferred=true if industrialtest.api.transferPower(meta,endpointMeta,powerDistribution)>0 then
end transferred=true
local def=minetest.registered_nodes[minetest.get_node(neighbourPositions[key]).name] transferredToEndpoint=true
if def then end
local updateFormspec=def._industrialtest_updateFormspec local def=minetest.registered_nodes[minetest.get_node(endpoint.position).name]
if updateFormspec then if def then
updateFormspec(neighbourPositions[key]) local updateFormspec=def._industrialtest_updateFormspec
end if updateFormspec then
local onPowerFlow=def._industrialtest_onPowerFlow updateFormspec(endpoint.position)
if onPowerFlow and transferred then end
onPowerFlow(neighbourPositions[key],industrialtest.api.getOppositeSide(key)) 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
end end
minetest.get_node_timer(neighbourPositions[key]):start(industrialtest.updateDelay) if not foundNewNode then
if not industrialtest.api.isFullyCharged(value) then table.remove(workers,i)
roomAvailable=true break
end end
end end
end end
end end
return roomAvailable,transferred return map
end end
-- \brief Starts node timer of neighbouring nodes with center node -- \brief Starts node timer of neighbouring nodes with center node
-- \param pos Vector with position of center node -- \param pos Vector with position of center node
-- \returns nil -- \returns nil
industrialtest.api.triggerNeighbours=function(pos) industrialtest.api.triggerNeighbours=function(pos)
local neighbourPositions={ for _,value in ipairs(industrialtest.api.getConnections(pos)) do
vector.offset(pos,-1,0,0), minetest.get_node_timer(value):start(industrialtest.updateDelay)
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
end end
end end
-- \brief Returns opposite side of provided one -- \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),
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 for key,value in ipairs(neighbourPositions) do
local meta=minetest.get_meta(value) local def=minetest.registered_nodes[minetest.get_node(value).name]
if industrialtest.api.hasPowerStorage(meta) then if def.groups._industrialtest_cable then
result[index]=key table.insert(result,value)
index=index+1 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
end end
return result return result

View File

@ -142,6 +142,7 @@ local function registerCable(name,displayName,size,flow,registerInsulated)
definition.sound=mcl_sounds.node_sound_metal_defaults() definition.sound=mcl_sounds.node_sound_metal_defaults()
end end
definition.groups._industrialtest_hasPowerInput=1 definition.groups._industrialtest_hasPowerInput=1
definition.groups._industrialtest_cable=1
minetest.register_node("industrialtest:"..name.."_cable",definition) minetest.register_node("industrialtest:"..name.."_cable",definition)
if registerInsulated then if registerInsulated then
definition=table.copy(definition) definition=table.copy(definition)