-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbm_alchemist.lua
225 lines (199 loc) · 7.45 KB
/
bm_alchemist.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
local event = require "event"
local config = require "bm_alchemist_config"
local utils = require "utils"
local HELLO_MSG = [[
Assumes no items are split across different stacks so make sure to enable Blocking Mode on the ME interface.
Restart this program if patterns has changed. Press Ctrl-C to stop.
]]
local ME_INTERFACE = config.meInterface
local TRANSPOSER = config.transposer
local TRANSPOSER_SIDE_CHEMSET = config.transposerSideChemset
local TRANSPOSER_SIDE_INPUT = config.transposerSideInput
local function isPatternsInfoValid(patterns)
local result = true
for output, entry in pairs(patterns) do
local countInputs = 0
for _, count in pairs(entry.inputs) do
countInputs = countInputs + count
end
if countInputs ~= 5 then
print(string.format(
"Pattern for %s is invalid since it does not have exactly 5 ingredients",
output
))
result = false
end
end
return result
end
--[[
Scans input box, and returns the name of output and a table of input items information
e.g. It returns "Potentia",
{
labels = {"Energium Dust", "Vibrant Alloy Dust", "Strengthened Catalyst"},
slots = {1, 2, 3},
sizes = {2, 2, 1},
}
Returns nil, nil if no matched patterns were found.
Assumes that no items are spilt across different stacks to make implementation simpler
]]
---@param transposerInput any
---@param sideInput integer
---@param patternsInfo table<string, PatternInfo>
---@param outputLookup table<string, string[]>
---@return string?
---@return {labels: string[], slots: integer[], sizes: integer[]}?
local function scanInputBox(transposerInput, sideInput, patternsInfo, outputLookup)
local stacksInfo = utils.collectStacksInfo(transposerInput, sideInput)
local possibleRecipes = {}
local allInputsInfo = {}
for input, entry in pairs(stacksInfo) do
local inputSlot = entry.slots[1]
local inputAmount = entry.sizes[1]
local matchedOutputs = outputLookup[input]
if matchedOutputs == nil then
print("Skipped unknown item " .. input)
goto continue
end
-- One input may be needed in multiple recipes
for _, output in ipairs(matchedOutputs) do
local patternInputsCounts = possibleRecipes[output] or utils.shallowCopy(patternsInfo[output].inputs)
local requiredAmount = patternInputsCounts[input]
possibleRecipes[output] = patternInputsCounts
if inputAmount >= requiredAmount then
patternInputsCounts[input] = nil
local inputsInfo = allInputsInfo[output] or {
labels = {},
slots = {},
sizes = {}
}
allInputsInfo[output] = inputsInfo
inputsInfo.labels[#inputsInfo.labels + 1] = input
inputsInfo.slots[#inputsInfo.slots + 1] = inputSlot
inputsInfo.sizes[#inputsInfo.sizes + 1] = inputAmount
if next(patternInputsCounts) == nil then
print("Found items to make " .. output)
return output, inputsInfo
end
end
end
::continue::
end
return nil, nil
end
--[[
Tests if chem set is empty (except for checking the orb slot)
]]
local function isChemsetEmpty(transposerInput, sideChemset)
local stackIter = transposerInput.getAllStacks(sideChemset)
local curStack = stackIter() -- Skips the first slot (orb slot)
for _ = 1, 6 do
curStack = stackIter()
if next(curStack) ~= nil then
return false
end
end
return true
end
--[[
Tests if chem set has an orb in it
]]
local function hasOrb(transposerInput, sideChemset)
return transposerInput.getStackInSlot(sideChemset, 1) ~= nil
end
--[[
Moves ingredients from the input chest to the chem set
Assumes chem set is empty, and the number of ingredients in inputs_info is correct
]]
---@param transposerInput any
---@param sideInput integer
---@param sideChemset integer
---@param inputsInfo {labels: string[], slots: integer[], sizes: integer[]}
local function getInput(transposerInput, sideInput, sideChemset, inputsInfo)
local chemSlot = 2
local iInput = 1
while chemSlot <= 6 do
local inputSlot = inputsInfo.slots[iInput]
local inputAmount = inputsInfo.sizes[iInput]
for _ = 1, inputAmount do
transposerInput.transferItem(sideInput, sideChemset, 1, inputSlot, chemSlot)
chemSlot = chemSlot + 1
end
iInput = iInput + 1
end
end
---@param args string[]
local function main(args)
print(HELLO_MSG)
local patterns, outputLookup = utils.getPatternsInfo(ME_INTERFACE)
if not isPatternsInfoValid(patterns) then
return
end
print(string.format("Found %d patterns", utils.sizeOfTable(patterns)))
local outputName
local inputsInfo
local STATE = { IDLE = 0, WAIT_ORB = 1, INPUT = 2, WAIT_OUTPUT = 3 }
local state = STATE.IDLE
while true do
if state == STATE.IDLE then
outputName, inputsInfo = scanInputBox(TRANSPOSER, TRANSPOSER_SIDE_INPUT, patterns, outputLookup)
if outputName and isChemsetEmpty(TRANSPOSER, TRANSPOSER_SIDE_CHEMSET) then
if hasOrb(TRANSPOSER, TRANSPOSER_SIDE_CHEMSET) then
state = STATE.INPUT
else
print("No orb in the chem set. Waiting...")
state = STATE.WAIT_ORB
end
end
elseif state == STATE.INPUT then
getInput(TRANSPOSER, TRANSPOSER_SIDE_INPUT, TRANSPOSER_SIDE_CHEMSET, inputsInfo)
print("Waiting for output")
state = STATE.WAIT_OUTPUT
elseif state == STATE.WAIT_ORB then
if hasOrb(TRANSPOSER, TRANSPOSER_SIDE_CHEMSET) then
state = STATE.INPUT
end
elseif state == STATE.WAIT_OUTPUT then
if isChemsetEmpty(TRANSPOSER, TRANSPOSER_SIDE_CHEMSET) then
print(outputName .. " done")
state = STATE.IDLE
end
end
local id = event.pull(0.5, "interrupted")
if id ~= nil then
break
end
end
end
local function testGetPatterns()
local patterns, _ = utils.getPatternsInfo(ME_INTERFACE)
print(utils.tableToString(patterns))
end
local function testValidatePatterns()
local patterns, _ = utils.getPatternsInfo(ME_INTERFACE)
print(isPatternsInfoValid(patterns))
end
local function testGetOutputLookup()
local _, outputLookup = utils.getPatternsInfo(ME_INTERFACE)
print(utils.tableToString(outputLookup))
end
local function testScanInputBox()
local patterns, outputLookup = utils.getPatternsInfo(ME_INTERFACE)
local output, inputInfo = scanInputBox(TRANSPOSER, TRANSPOSER_SIDE_INPUT, patterns, outputLookup)
print(output)
print(utils.tableToString(inputInfo))
end
local function testIsChemSetEmpty()
print(isChemsetEmpty(TRANSPOSER, TRANSPOSER_SIDE_CHEMSET))
end
local function testHasOrb()
print(hasOrb(TRANSPOSER, TRANSPOSER_SIDE_CHEMSET))
end
local function testGetInput()
local patterns, outputLookup = utils.getPatternsInfo(ME_INTERFACE)
local _, inputInfo = scanInputBox(TRANSPOSER, TRANSPOSER_SIDE_INPUT, patterns, outputLookup)
if inputInfo then
getInput(TRANSPOSER, TRANSPOSER_SIDE_INPUT, TRANSPOSER_SIDE_CHEMSET, inputInfo)
end
end
main({ ... })