-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathinfinity-loader.lua
320 lines (298 loc) · 9.3 KB
/
infinity-loader.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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
local flib_direction = require("__flib__.direction")
local flib_migration = require("__flib__.migration")
local position = require("__flib__.position")
local transport_belt_connectables = {
"transport-belt",
"underground-belt",
"splitter",
"loader",
"loader-1x1",
"linked-belt",
"lane-splitter",
}
--- @param entity LuaEntity
local function snap(entity)
local offset_direction = entity.direction
if entity.loader_type == "input" then
offset_direction = flib_direction.opposite(offset_direction)
end
local belt_position = position.add(entity.position, flib_direction.to_vector(offset_direction))
local belt =
entity.surface.find_entities_filtered({ position = belt_position, type = transport_belt_connectables })[1]
if not belt then
belt =
entity.surface.find_entities_filtered({ position = belt_position, ghost_type = transport_belt_connectables })[1]
end
if not belt then
return
end
if belt.direction == flib_direction.opposite(entity.direction) then
entity.loader_type = entity.loader_type == "output" and "input" or "output"
end
end
--- @param entity LuaEntity
--- @param chest LuaEntity?
local function sync_chest_filter(entity, chest)
if not chest then
chest = entity.surface.find_entity("ee-infinity-loader-chest", entity.position)
end
if not chest then
entity.destroy()
return
end
for i = 1, 2 do
local filter = entity.get_filter(i)
if filter then
chest.set_infinity_container_filter(i, {
index = i,
name = filter.name --[[@as string]],
quality = filter.quality,
count = prototypes.item[filter.name].stack_size * 5,
mode = "exactly",
})
else
chest.set_infinity_container_filter(i, nil)
end
end
end
--- @param loader LuaEntity
--- @param combinator LuaEntity
local function copy_from_loader_to_combinator(loader, combinator)
local cb = combinator.get_or_create_control_behavior() --[[@as LuaConstantCombinatorControlBehavior]]
--- @type LuaLogisticSection?
local section
for _, sec in pairs(cb.sections) do
if sec.group == "" then
section = sec
break
end
end
if not section then
section = cb.add_section()
end
if not section then
return -- When will this ever happen?
end
--- @type ItemFilter?
local first_filter
for i = 1, 2 do
local filter = loader.get_filter(i)
if not filter then
goto continue
end
if i == 1 then
first_filter = filter
elseif first_filter and filter.name == first_filter.name and filter.quality == first_filter.quality then
return
end
section.set_slot(i, {
value = {
type = "item",
name = filter.name --[[@as string]],
quality = filter.quality,
},
min = 1,
})
::continue::
end
end
--- @param combinator LuaEntity
--- @param loader LuaEntity
local function copy_from_combinator_to_loader(combinator, loader)
local cb = combinator.get_control_behavior() --[[@as LuaConstantCombinatorControlBehavior?]]
if not cb then
return
end
local section = cb.get_section(1)
if not section then
return
end
for i = 1, 2 do
local filter = section.filters[i]
if filter then
local value = filter.value
if value and prototypes[value.type or "item"][value.name] then
loader.set_filter(i, { name = value.name, quality = value.quality })
else
loader.set_filter(i, nil)
end
end
end
sync_chest_filter(loader)
end
--- @param e BuiltEvent
local function on_entity_built(e)
local entity = e.entity or e.destination
if not entity.valid then
return
end
if entity.name ~= "ee-infinity-loader" then
return
end
-- Create chest
local chest = entity.surface.create_entity({
name = "ee-infinity-loader-chest",
position = entity.position,
force = entity.force,
create_build_effect_smoke = false,
raise_built = true,
})
if not chest then
entity.destroy()
return
end
chest.remove_unfiltered_items = true
sync_chest_filter(entity, chest)
snap(entity)
end
--- @param e DestroyedEvent
local function on_entity_destroyed(e)
local entity = e.entity
if not entity.valid or entity.name ~= "ee-infinity-loader" then
return
end
local chest = entity.surface.find_entity("ee-infinity-loader-chest", entity.position)
if chest then
chest.destroy({ raise_destroy = true })
end
end
--- @param e EventData.on_player_rotated_entity
local function on_entity_rotated(e)
local entity = e.entity
if not entity.valid or entity.name ~= "ee-infinity-loader" then
return
end
sync_chest_filter(entity)
end
--- @param e EventData.on_entity_settings_pasted
local function on_entity_settings_pasted(e)
local source, destination = e.source, e.destination
if not source.valid or not destination.valid then
return
end
local source_is_loader, destination_is_loader =
source.name == "ee-infinity-loader", destination.name == "ee-infinity-loader"
if source_is_loader and destination.name == "constant-combinator" then
copy_from_loader_to_combinator(source, destination)
elseif source.name == "constant-combinator" and destination_is_loader then
copy_from_combinator_to_loader(source, destination)
elseif destination_is_loader then
sync_chest_filter(destination)
end
end
--- @param e EventData.on_gui_opened
local function on_gui_opened(e)
if e.gui_type ~= defines.gui_type.entity then
return
end
local entity = e.entity
if not entity or not entity.valid then
return
end
if entity.name == "ee-infinity-loader" then
storage.infinity_loader_open[e.player_index] = entity
end
end
--- @param e EventData.on_gui_closed
local function on_gui_closed(e)
if e.gui_type ~= defines.gui_type.entity then
return
end
local loader = storage.infinity_loader_open[e.player_index]
if loader and loader.valid then
sync_chest_filter(loader)
storage.infinity_loader_open[e.player_index] = nil
end
end
local infinity_loader = {}
function infinity_loader.on_init()
--- @type table<uint, LuaEntity>
storage.infinity_loader_open = {}
end
--- @param e ConfigurationChangedData
function infinity_loader.on_configuration_changed(e)
flib_migration.on_config_changed(
e,
infinity_loader.migrations,
script.mod_name,
e.mod_changes.EditorExtensions and e.mod_changes.EditorExtensions.old_version
)
end
infinity_loader.migrations = {
["2.0.0"] = function()
for _, surface in pairs(game.surfaces) do
for _, combinator in pairs(surface.find_entities_filtered({ name = "ee-infinity-loader-dummy-combinator" })) do
local cb = combinator.get_control_behavior() --[[@as LuaConstantCombinatorControlBehavior?]]
if not cb then
goto continue
end
local section = cb.get_section(1)
if not section then
goto continue
end
local filter_1, filter_2 = section.filters[1], section.filters[2]
local loader = combinator.surface.create_entity({
name = "ee-infinity-loader",
direction = combinator.direction,
position = combinator.position,
force = combinator.force,
last_user = combinator.last_user,
fast_replace = true,
create_build_effect_smoke = false,
})
if not loader then
error("Failed to create infinity loader replacement.")
end
if filter_1 and filter_1.value then
loader.set_filter(1, { name = filter_1.value.name, quality = filter_1.value.quality, amount = filter_1.min })
end
if filter_2 and filter_2.value then
loader.set_filter(2, { name = filter_2.value.name, quality = filter_2.value.quality, amount = filter_2.min })
end
snap(loader)
combinator.destroy()
::continue::
end
end
end,
--- @param old_version string
["2.4.0"] = function(old_version)
if not flib_migration.is_newer_version("2.0.0", old_version) then
return
end
for _, surface in pairs(game.surfaces) do
for _, loader in pairs(surface.find_entities_filtered({ name = "ee-infinity-loader" })) do
loader.set_filter(2, loader.get_filter(1))
end
end
end,
}
infinity_loader.events = {
[defines.events.on_built_entity] = on_entity_built,
[defines.events.on_entity_cloned] = on_entity_built,
[defines.events.on_entity_died] = on_entity_destroyed,
[defines.events.on_entity_settings_pasted] = on_entity_settings_pasted,
[defines.events.on_gui_closed] = on_gui_closed,
[defines.events.on_gui_opened] = on_gui_opened,
[defines.events.on_player_mined_entity] = on_entity_destroyed,
[defines.events.on_player_rotated_entity] = on_entity_rotated,
[defines.events.on_robot_built_entity] = on_entity_built,
[defines.events.on_robot_mined_entity] = on_entity_destroyed,
[defines.events.script_raised_built] = on_entity_built,
[defines.events.script_raised_destroy] = on_entity_destroyed,
[defines.events.script_raised_revive] = on_entity_built,
[defines.events.on_space_platform_built_entity] = on_entity_built,
[defines.events.on_space_platform_mined_entity] = on_entity_destroyed,
}
infinity_loader.on_nth_tick = {
[15] = function()
for unit_number, loader in pairs(storage.infinity_loader_open) do
if loader.valid then
sync_chest_filter(loader)
else
storage.infinity_loader_open[unit_number] = nil
end
end
end,
}
return infinity_loader