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

173
api.lua
View File

@ -216,92 +216,142 @@ 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
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(neighbourPositions[key]).name]
local def=minetest.registered_nodes[minetest.get_node(endpoint.position).name]
if def then
local updateFormspec=def._industrialtest_updateFormspec
if updateFormspec then
updateFormspec(neighbourPositions[key])
updateFormspec(endpoint.position)
end
local onPowerFlow=def._industrialtest_onPowerFlow
if onPowerFlow and transferred then
onPowerFlow(neighbourPositions[key],industrialtest.api.getOppositeSide(key))
if onPowerFlow and transferredToEndpoint then
onPowerFlow(endpoint.position,industrialtest.api.getOppositeSide(1))
end
end
minetest.get_node_timer(neighbourPositions[key]):start(industrialtest.updateDelay)
if not industrialtest.api.isFullyCharged(value) then
minetest.get_node_timer(endpoint.position):start(industrialtest.updateDelay)
if not industrialtest.api.isFullyCharged(endpointMeta) then
roomAvailable=true
end
end
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
if not foundNewNode then
table.remove(workers,i)
break
end
end
end
end
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
for _,value in ipairs(industrialtest.api.getConnections(pos)) do
minetest.get_node_timer(value):start(industrialtest.updateDelay)
end
end
end
-- \brief Returns opposite side of provided one
-- \param side Side number. See industrialtest.api.addPowerStorage for order
-- \returns Opposite side
@ -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 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)
if industrialtest.api.hasPowerStorage(meta) then
result[index]=key
index=index+1
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

View File

@ -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)