-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontrol.lua
More file actions
256 lines (220 loc) · 8.94 KB
/
control.lua
File metadata and controls
256 lines (220 loc) · 8.94 KB
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
local flib_dictionary = require "__flib__/dictionary"
local flib_gui = require "__flib__/gui"
local flib_table = require "__flib__/table"
local fs_log = require "fs_log"
local fs_util = require "fs_util"
local save = require "manage/save"
local pre_solve = require "manage/pre_solve"
local virtual = require "manage/virtual"
local common = require "ui/common"
local main_window = require "ui/main_window"
local build_assistant = require "ui/build_assistant"
-- factoriomod-debug injects __DebugAdapter as a truthy global only when the
-- VM is running under the debugger. The injection happens before any mod
-- code loads, so taking a local snapshot here is safe and keeps LuaLS from
-- flagging the global as undefined.
local __DebugAdapter = _G["__DebugAdapter"]
-- Activate the in-game smoke driver only when this Factorio instance was
-- launched with --load-scenario factory_solver/<smoke-variant>. The mod's
-- normal flow is untouched otherwise. Each variant ships its own driver under
-- manage/ with the same on_player_created / on_tick shape.
local smoke = nil
if script.level and script.level.mod_name == "factory_solver" then
if script.level.level_name == "smoke" then
smoke = require "manage/smoke"
elseif script.level.level_name == "smoke_missing_prototype" then
smoke = require "manage/smoke_missing_prototype"
end
end
script.on_init(function()
flib_dictionary.on_init()
storage.virtuals = virtual.create_virtuals()
storage.players = {}
for _, player in pairs(game.players) do
save.init_player_data(player.index)
if __DebugAdapter then
player.cheat_mode = true
end
end
storage.forces = {}
for _, force in pairs(game.forces) do
save.init_force_data(force.index)
if __DebugAdapter then
for _, quality in pairs(prototypes.quality) do
force.unlock_quality(quality)
end
end
end
if __DebugAdapter then
if remote.interfaces["freeplay"] then
remote.call("freeplay", "set_skip_intro", true)
remote.call("freeplay", "set_disable_crashsite", true)
end
end
end)
script.on_load(function()
for _, force in pairs(storage.forces) do
save.resetup_force_data_metatable(force)
end
end)
script.on_configuration_changed(function(event)
flib_dictionary.on_configuration_changed()
storage.virtuals = virtual.create_virtuals()
for _, player in pairs(game.players) do
save.reinit_player_data(player.index)
local player_data = storage.players[player.index]
local screen = player.gui.screen
for _, name in ipairs(player_data.opened_gui) do
if screen[name] then
screen[name].destroy()
end
end
player_data.opened_gui = {}
player.set_shortcut_toggled("factory-solver-toggle-main-window", false)
-- The build assistant is a docked panel in gui.left, outside the
-- opened_gui modal stack, so it is destroyed and untoggled explicitly.
if player.gui.left["factory_solver_build_assistant"] then
player.gui.left["factory_solver_build_assistant"].destroy()
end
player.set_shortcut_toggled("factory-solver-toggle-build-assistant", false)
end
for _, force in pairs(game.forces) do
save.reinit_force_data(force.index)
end
end)
script.on_event(defines.events.on_player_created, function(event)
save.init_player_data(event.player_index)
if __DebugAdapter then
game.players[event.player_index].cheat_mode = true
end
if smoke then smoke.on_player_created(event) end
end)
script.on_event(defines.events.on_player_changed_force, function(event)
save.init_force_data(event.force.index)
if __DebugAdapter then
for _, quality in pairs(prototypes.quality) do
event.force.unlock_quality(quality)
end
end
end)
script.on_event(defines.events.on_player_removed, function(event)
storage.players[event.player_index] = nil
end)
script.on_event(defines.events.on_force_created, function(event)
save.init_force_data(event.force.index)
end)
script.on_event(defines.events.on_force_reset, function(event)
save.reinit_force_data(event.force.index)
end)
script.on_event(defines.events.on_forces_merged, function(event)
local destination_force_data = storage.forces[event.destination.index]
local source_force_data = storage.forces[event.source_index]
destination_force_data.solutions = flib_table.array_merge {
destination_force_data.solutions,
source_force_data.solutions
}
storage.forces[event.source_index] = nil
end)
script.on_event(defines.events.on_research_finished, function(event)
save.reinit_force_data(event.research.force.index)
end)
script.on_event(defines.events.on_research_reversed, function(event)
save.reinit_force_data(event.research.force.index)
end)
script.on_event(defines.events.on_tick, function(event)
flib_dictionary.on_tick()
local force_data, solution = pre_solve.find_the_need_for_solve()
if force_data and solution then
pre_solve.forwerd_solve(force_data, solution)
for _, player in pairs(game.players) do
local window = player.gui.screen["factory_solver_main_window"]
if window then
fs_util.dispatch_to_subtree(window, "on_calculation_changed")
end
local build_window = player.gui.left["factory_solver_build_assistant"]
if build_window then
fs_util.dispatch_to_subtree(build_window, "on_calculation_changed")
end
end
end
if smoke then smoke.on_tick(event) end
end)
---@param player_index integer
local function toggle_main_window(player_index)
local player = game.players[player_index]
local window = player.gui.screen["factory_solver_main_window"]
if window == nil then
common.open_gui(player_index, false, main_window)
else
common.on_close_self {
element = window,
name = "on_close_toggle",
player_index = player_index,
tick = game.tick,
mod_name = window.get_mod()
}
end
end
-- The build assistant is a persistent, docked panel rather than a floating
-- window: it lives in gui.left so it sits beside the main window instead of
-- hiding behind it, and it is added/destroyed directly rather than through
-- common.open_gui (which targets gui.screen, pushes onto the opened_gui modal
-- stack, and sets player.opened — none of which fit a docked panel).
---@param player_index integer
local function toggle_build_assistant(player_index)
local player = game.players[player_index]
local window = player.gui.left["factory_solver_build_assistant"]
if window == nil then
fs_util.add_gui(player.gui.left, build_assistant)
else
fs_util.dispatch_to_subtree(window, "on_close")
window.destroy()
end
end
---@param event EventData.CustomInputEvent
script.on_event("factory-solver-toggle-main-window", function(event)
toggle_main_window(event.player_index)
end)
---@param event EventData.CustomInputEvent
script.on_event("factory-solver-toggle-build-assistant", function(event)
toggle_build_assistant(event.player_index)
end)
script.on_event(defines.events.on_lua_shortcut, function(event)
if event.prototype_name == "factory-solver-toggle-main-window" then
toggle_main_window(event.player_index)
elseif event.prototype_name == "factory-solver-toggle-build-assistant" then
toggle_build_assistant(event.player_index)
end
end)
-- Lets a player (or the server console) raise the fs_log threshold below
-- `debug` so the A-matrix dump in solver.lp's "ready" block reaches the log.
-- Intended for fixture capture: turn trace on, trigger a solve, copy the
-- emitted cost/limit/subject block into a tests/cases/*.lua entry, turn it
-- back off. Threshold lives in fs_log's module-local state (not storage), so
-- the change is per-process and does not need to survive save/load; running
-- the command on every client in MP keeps log threshold consistent across
-- clients without making it desync-relevant.
commands.add_command(
"factory-solver-log-level",
"Set the fs_log threshold (trace | debug | info | warn | error). " ..
"With no argument, prints the current level.",
function(event)
local sink = event.player_index
and game.players[event.player_index]
or game
local arg = event.parameter and event.parameter:match("^%s*(%S+)%s*$")
if not arg then
sink.print("factory_solver log level: " .. fs_log.get_level())
return
end
local ok = pcall(fs_log.set_level, arg)
if ok then
sink.print("factory_solver log level set to " .. arg)
else
sink.print("factory_solver: unknown log level '" .. arg ..
"' (expected trace | debug | info | warn | error)")
end
end
)
flib_dictionary.handle_events()
flib_gui.handle_events()