Created
September 26, 2021 21:08
-
-
Save Panakotta00/1a90fe5b64cd9647bfb2884938573ebc to your computer and use it in GitHub Desktop.
Crappy Conveyor-Crawler and Item-Router
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---@class Node | |
---@field connected Node[] | |
local Node = {} | |
---@class SplitterNode : Node | |
---@field private outputs table<Node, number> | |
local SplitterNode = {} | |
function SplitterNode:findOutput(node) | |
return self.outputs[node] | |
end | |
local Graph = {} | |
function Graph.new() | |
local graph = { | |
nodes = {}, | |
edges = {}, | |
nodeAlias = {}, | |
} | |
setmetatable(graph, Graph) | |
Graph.__index = Graph | |
return graph | |
end | |
function Graph:newEndNode(endObj) | |
local endNode = self.nodeAlias[endObj.hash] | |
if endNode then | |
return endNode | |
end | |
endNode = { | |
connected = {}, | |
obj = endObj, | |
name = "end" | |
} | |
self.nodeAlias[endObj.hash] = endNode | |
table.insert(self.nodes, endNode) | |
setmetatable(endNode, Node) | |
Node.__index = Node | |
return endNode | |
end | |
---@param connector FactoryConnection | |
function Graph:nextNode(connector) | |
while connector.isConnected do | |
connector = connector:getConnected() | |
local owner = connector.owner | |
if owner:getType():isChildOf(findClass("FGBuildableConveyorBase")) then | |
connector = owner:getFactoryConnectors()[2] | |
elseif owner:getType():isChildOf(findClass("FGBuildableAttachmentMerger")) then | |
connector = owner:getFactoryConnectors()[3] | |
else | |
break | |
end | |
end | |
if not connector.isConnected then | |
return self:newEndNode(connector) | |
end | |
local owner = connector.owner | |
if owner:getType():isChildOf(findClass("CodeableSplitter")) then | |
return self:newSplitterNode(owner) | |
end | |
target = self:newEndNode(owner) | |
return target | |
end | |
---@param splitter CodeableSplitter | |
function Graph:newSplitterNode(splitter) | |
local splitterNode = self.nodeAlias[splitter.hash] | |
if splitterNode then | |
return splitterNode | |
end | |
splitterNode = { | |
splitter = splitter, | |
outputs = {}, | |
connected = {}, | |
name = "splitter " .. splitter.id | |
} | |
self.nodeAlias[splitter.hash] = splitterNode | |
table.insert(self.nodes, splitterNode) | |
for _, v in pairs(splitter:getFactoryConnectors()) do | |
if v.direction == 1 then | |
local node = self:nextNode(v) | |
splitterNode.outputs[node] = #splitterNode.connected | |
table.insert(splitterNode.connected, node) | |
end | |
end | |
setmetatable(splitterNode, SplitterNode) | |
SplitterNode.__index = SplitterNode | |
return splitterNode | |
end | |
---@param merger CodeableMerger | |
function Graph:newMergerStartNode(merger, input) | |
local id = tostring(merger.hash) .. input | |
local mergerNode = self.nodeAlias[id] | |
if mergerNode then | |
return mergerNode | |
end | |
mergerNode = { | |
merger = merger, | |
input = input, | |
connected = {} | |
} | |
self.nodeAlias[id] = mergerNode | |
mergerNode.connected[1] = self:nextNode(merger:getFactoryConnectors()[1]) | |
return mergerNode | |
end | |
function Graph:findNode(alias) | |
return self.nodeAlias[alias.hash] | |
end | |
---@param start Node | |
---@param destination Node | |
function Graph:findPath(start, destination) | |
local prevNode = {} | |
local distance = {} | |
local locked = {} | |
local current = start | |
while current do | |
locked[current] = true | |
local currentDistance = distance[current] or 0 | |
for _, connected in pairs(current.connected) do | |
local length = 1 | |
if distance[connected] == nil or currentDistance + length < distance[connected] then | |
prevNode[connected] = current | |
distance[connected] = currentDistance + length | |
end | |
end | |
currentDistance = nil | |
for connected in pairs(distance) do | |
if not locked[connected] and (currentDistance == nil or distance[connected] < currentDistance) then | |
current = connected | |
currentDistance = distance[connected] | |
end | |
end | |
if not currentDistance then | |
break | |
end | |
end | |
local path = {destination} | |
current = destination | |
while current ~= start do | |
current = prevNode[current] | |
table.insert(path, 1, current) | |
end | |
return path | |
end | |
return Graph, Node, SplitterNode |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
_libCache = {} | |
function require(libName) | |
local lib = _libCache[libName] | |
if lib then | |
return table.unpack(lib) | |
end | |
local libPath = "/" .. libName | |
if not filesystem.isFile(libPath) then | |
libPath = libPath .. ".lua" | |
if not filesystem.isFile(libPath) then | |
return nil | |
end | |
end | |
print("Lib: load Lib '" .. libPath .. "'") | |
local libFunc = filesystem.loadFile(libPath) | |
if type(libFunc) ~= "function" then | |
print("Lib: failed to load Lib '" .. libPath .. "'!") | |
else | |
lib = {libFunc()} | |
_libCache[libName] = lib | |
return table.unpack(lib) | |
end | |
end | |
--local json = require("json") | |
local Splitter = require("splitter") | |
local ConveyorGraph, Node, SplitterNode = require("conveyorGraph") | |
local splitters = {} | |
---@param splitter CodeableSplitter | |
function getRouter(splitter) | |
local router = splitters[splitter.hash] or Splitter.new(splitter) | |
splitters[splitter.hash] = router | |
event.listen(splitter) | |
return router | |
end | |
local plate = findItem("Coal") | |
local graph = ConveyorGraph.new() | |
local input = component.proxy(startComp) | |
local container = component.proxy(destinationComp) | |
local start = graph:newMergerStartNode(input, startNum) | |
local dest = graph:findNode(container) | |
local path = graph:findPath(start, dest) | |
local convertOutputSplitter = { | |
1, | |
0, | |
2 | |
} | |
for i, node in pairs(path) do | |
if getmetatable(node) == SplitterNode then | |
---@type SplitterNode | |
node = node | |
local router = getRouter(node.splitter) | |
local next = path[i+1] | |
local output = node:findOutput(next) | |
router:pushItem(plate, convertOutputSplitter[output+1]) | |
end | |
end | |
input:transferItem(startNum) | |
while true do | |
local e, s, d1, d2 = event.pull(1) | |
if e == "ItemRequest" then | |
local splitter = splitters[s.hash] | |
if splitter then | |
splitter:handleItem(d1.type) | |
end | |
else | |
for _, splitter in pairs(splitters) do | |
splitter:handleItem() | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---@class Splitter | |
---@field public component CodeableSplitter | |
---@field private itemQueues table<string, number[]> | |
---@field public defaultOutput number | |
local Splitter = {} | |
---@return Splitter | |
function Splitter.new(component, defaultOutput) | |
local splitter = { | |
component = component, | |
itemQueues = {}, | |
defaultOutput = defaultOutput or 0, | |
} | |
setmetatable(splitter, Splitter) | |
Splitter.__index = Splitter | |
return splitter | |
end | |
function Splitter:pushItem(item, output) | |
local queue = self.itemQueues[item.name] or {} | |
self.itemQueues[item.name] = queue | |
table.insert(queue, output) | |
end | |
function Splitter:popItem(item) | |
local queue = self.itemQueues[item.name] | |
if queue then | |
local output = queue[1] | |
table.remove(queue, 1) | |
if #queue < 1 then | |
self.itemQueues[item.name] = nil | |
end | |
return output | |
end | |
return self.defaultOutput | |
end | |
function Splitter:peakItem(item) | |
local queue = self.itemQueues[item.name] | |
if queue then | |
return queue[1] | |
end | |
return self.defaultOutput | |
end | |
function Splitter:handleItem(item) | |
item = item or self.component:getInput().type | |
if item then | |
print("item!", item) | |
local output = self:peakItem(item) | |
print(output) | |
if self.component:transferItem(output) then | |
self:popItem(item) | |
end | |
end | |
end | |
return Splitter |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment