Merge branch 'experimental' of github.com:mamoniot/project-cybersyn into experimental

This commit is contained in:
mamoniot
2023-03-13 17:37:49 -04:00
23 changed files with 784 additions and 212 deletions

2
.gitignore vendored
View File

@@ -1 +1,3 @@
*.zip *.zip
.vscode/launch.json
.vscode/settings.json

View File

@@ -85,14 +85,14 @@ constants.gui_content_frame_height = 744
constants.gui_inventory_table_height = 40 * 18 constants.gui_inventory_table_height = 40 * 18
constants.gui_translations = { constants.gui_translations = {
delivering_to = { "gui.ltnm-delivering-to" }, delivering_to = { "cybersyn-gui.delivering-to" },
fetching_from = { "gui.ltnm-fetching-from" }, fetching_from = { "cybersyn-gui.fetching-from" },
loading_at = { "gui.ltnm-loading-at" }, loading_at = { "cybersyn-gui.loading-at" },
not_available = { "gui.ltnm-not-available" }, not_available = { "cybersyn-gui.not-available" },
parked_at_depot_with_residue = { "gui.ltnm-parked-at-depot-with-residue" }, parked_at_depot_with_residue = { "cybersyn-gui.parked-at-depot-with-residue" },
parked_at_depot = { "gui.ltnm-parked-at-depot" }, parked_at_depot = { "cybersyn-gui.parked-at-depot" },
returning_to_depot = { "gui.ltnm-returning-to-depot" }, returning_to_depot = { "cybersyn-gui.returning-to-depot" },
unloading_at = { "gui.ltnm-unloading-at" }, unloading_at = { "cybersyn-gui.unloading-at" },
} }
constants.input_sanitizers = { constants.input_sanitizers = {
@@ -144,8 +144,8 @@ constants.ltn_event_names = {
if script then if script then
constants.open_station_gui_tooltip = { constants.open_station_gui_tooltip = {
"", "",
{ "gui.ltnm-open-station-gui" }, { "cybersyn-gui.open-station-gui" },
remote.interfaces["ltn-combinator"] and { "", "\n", { "gui.ltnm-open-ltn-combinator-gui" } } or nil, remote.interfaces["ltn-combinator"] and { "", "\n", { "cybersyn-gui.open-ltn-combinator-gui" } } or nil,
} }
end end

View File

@@ -26,14 +26,14 @@ data:extend({
--{ --{
-- type = "shortcut", -- type = "shortcut",
-- name = "ltnm-toggle-gui", -- name = "cybersyn-toggle-gui",
-- icon = data_util.build_sprite(nil, { 0, 0 }, util.paths.shortcut_icons, 32, 2), -- icon = data_util.build_sprite(nil, { 0, 0 }, util.paths.shortcut_icons, 32, 2),
-- disabled_icon = data_util.build_sprite(nil, { 48, 0 }, util.paths.shortcut_icons, 32, 2), -- disabled_icon = data_util.build_sprite(nil, { 48, 0 }, util.paths.shortcut_icons, 32, 2),
-- small_icon = data_util.build_sprite(nil, { 0, 32 }, util.paths.shortcut_icons, 24, 2), -- small_icon = data_util.build_sprite(nil, { 0, 32 }, util.paths.shortcut_icons, 24, 2),
-- disabled_small_icon = data_util.build_sprite(nil, { 36, 32 }, util.paths.shortcut_icons, 24, 2), -- disabled_small_icon = data_util.build_sprite(nil, { 36, 32 }, util.paths.shortcut_icons, 24, 2),
-- toggleable = true, -- toggleable = true,
-- action = "lua", -- action = "lua",
-- associated_control_input = "ltnm-toggle-gui", -- associated_control_input = "cybersyn-toggle-gui",
-- technology_to_unlock = "logistic-train-network", -- technology_to_unlock = "logistic-train-network",
--}, --},
}) })

View File

@@ -11,6 +11,7 @@
"? space-exploration >= 0.6.94", "? space-exploration >= 0.6.94",
"? miniloader", "? miniloader",
"? nullius", "? nullius",
"? pypostprocessing" "? pypostprocessing",
"! LtnManager"
] ]
} }

View File

@@ -12,6 +12,9 @@ cybersyn-warmup-time=Station warmup time (sec)
cybersyn-stuck-train-time=Stuck train timeout (sec) cybersyn-stuck-train-time=Stuck train timeout (sec)
cybersyn-allow-cargo-in-depot=Allow cargo in depots cybersyn-allow-cargo-in-depot=Allow cargo in depots
cybersyn-invert-sign=Invert combinator output (deprecated) cybersyn-invert-sign=Invert combinator output (deprecated)
cybersyn-manager-enabled=Enable the Cybersyn GUI.
cybersyn-manager-update-rate=Manager refresh tick interval
cybersyn-manager-result-limit=Max entities displayed on GUI pages.
[mod-setting-description] [mod-setting-description]
cybersyn-enable-planner=Enable or disable the central planning algorithm. If disabled no new trains will be dispatched. cybersyn-enable-planner=Enable or disable the central planning algorithm. If disabled no new trains will be dispatched.
@@ -27,6 +30,7 @@ cybersyn-warmup-time=How many seconds a cybernetic combinator will wait before c
cybersyn-stuck-train-time=After this many seconds from a train's dispatch, an alert will be sent to let you know a train is probably stuck and has not completed its delivery. The player will likely have to debug their network to get the train unstuck. cybersyn-stuck-train-time=After this many seconds from a train's dispatch, an alert will be sent to let you know a train is probably stuck and has not completed its delivery. The player will likely have to debug their network to get the train unstuck.
cybersyn-allow-cargo-in-depot=If checked, trains will be allowed to have cargo in depots; no alerts will be generated and the train will not be held. In addition, trains with orders to visit requester stations with "Inactivity condition" checked will wait for inactivity instead of waiting for empty cargo. Useful for creating train systems where depots handle excess cargo. For advanced users only. cybersyn-allow-cargo-in-depot=If checked, trains will be allowed to have cargo in depots; no alerts will be generated and the train will not be held. In addition, trains with orders to visit requester stations with "Inactivity condition" checked will wait for inactivity instead of waiting for empty cargo. Useful for creating train systems where depots handle excess cargo. For advanced users only.
cybersyn-invert-sign=Flip the sign of the output of cybernetic combinators to be the same as it is in LTN or in earlier versions of Project Cybersyn. cybersyn-invert-sign=Flip the sign of the output of cybernetic combinators to be the same as it is in LTN or in earlier versions of Project Cybersyn.
cybersyn-manager-result-limit=Caps the number of matching enitities (e.g. stations, trains) to limit the amount of update time consumed when the list is refreshed.\n-1 means return all results.
[item-name] [item-name]
cybersyn-combinator=Cybernetic combinator cybersyn-combinator=Cybernetic combinator

View File

@@ -1,5 +1,8 @@
[mod-name]
cybersyn=Project Cybersyn
[controls] [controls]
cybersyn-toggle-gui=Toggle LTN Manager cybersyn-toggle-gui=Toggle Cybersyn Manager
[cybersyn-gui] [cybersyn-gui]
alert-delivery-failed=Delivery failed alert-delivery-failed=Delivery failed
@@ -33,6 +36,7 @@ inventory=Inventory
keep-open=Keep open keep-open=Keep open
loading-at=Loading at loading-at=Loading at
name=Name name=Name
network-name-label=Network Filter:
network-id-label=Network ID: network-id-label=Network ID:
network-id=Network ID network-id=Network ID
no-alerts=[img=warning-white] No alerts no-alerts=[img=warning-white] No alerts
@@ -41,8 +45,7 @@ no-history=[img=warning-white] No history
no-stations=[img=warning-white] No stations no-stations=[img=warning-white] No stations
not-available=Not available not-available=Not available
no-trains=[img=warning-white] No trains no-trains=[img=warning-white] No trains
open-ltn-combinator-gui=[font=default-semibold][color=128,206,240]Control:[/color][/font] Open LTN Combinator GUI open-station-gui=Open station GUI\n[font=default-semibold][color=128,206,240]Shift:[/color][/font] Open station on map\n[font=default-semibold][color=128,206,240]Control:[/color][/font] Open Station Cybernetic Combinator\n[font=default-semibold][color=128,206,240]Alt:[/color][/font] Open Station Control Cybernetic Combinator
open-station-gui=Open station GUI\n[font=default-semibold][color=128,206,240]Shift:[/color][/font] Open station on map
open-train-gui=Open train GUI open-train-gui=Open train GUI
parked-at-depot=Parked at depot parked-at-depot=Parked at depot
parked-at-depot-with-residue=Parked at depot with residue parked-at-depot-with-residue=Parked at depot with residue
@@ -54,13 +57,14 @@ requested=Requested
returning-to-depot=Returning to depot returning-to-depot=Returning to depot
route=Route route=Route
runtime=Runtime runtime=Runtime
search-label=Search: search-label=Station Name:
search-item-label=Item Filter:
shipments-description=Green = Inbound\nBlue = Outbound shipments-description=Green = Inbound\nBlue = Outbound
shipment=Shipment shipment=Shipment
shipments=Shipments shipments=Shipments
stations=Stations stations=Stations
status-description=[img=flib_indicator_green]1 = normal status\n[img=flib_indicator_blue]n = LTN Controlled Train parked at stop, n = number of trains\n[img=flib_indicator_yellow]n = Stop is part of a scheduled delivery, n = number of trains\n[img=flib_indicator_white]1 = Error - not initialized\n[img=flib_indicator_red]1 = Error - short circuit\n[img=flib_indicator_red]2 = Error - deactivated stop status-description=[img=flib_indicator_green]1 = normal status\n[img=flib_indicator_blue]n = LTN Controlled Train parked at stop, n = number of trains\n[img=flib_indicator_yellow]n = Stop is part of a scheduled delivery, n = number of trains\n[img=flib_indicator_white]1 = Error - not initialized\n[img=flib_indicator_red]1 = Error - short circuit\n[img=flib_indicator_red]2 = Error - deactivated stop
status=Status status=Network Signal
surface-label=Surface: surface-label=Surface:
time=Time time=Time
train-id=Train ID train-id=Train ID
@@ -69,9 +73,11 @@ type=Type
unloading-at=Unloading at unloading-at=Unloading at
[cybersyn-message] [cybersyn-message]
error-ltn-combinator-not-found=Could not find an LTN Combinator for this station. error-cybernetic-combinator-not-found=Could not find a cybernetic combinator for this station.
error-station-control-combinator-not-found=Could not find a station control cybernetic combinator for this station.
error-station-is-invalid=Station is invalid, please refresh the GUI. error-station-is-invalid=Station is invalid, please refresh the GUI.
error-train-is-invalid=Train is invalid, please refresh the GUI. error-train-is-invalid=Train is invalid, please refresh the GUI.
error-cross-surface-camera-invalid=Cannot move the camera to an entity on a different surface!
[cybersyn-mod-setting-description] [cybersyn-mod-setting-description]
iterations-per-tick=Decrease this number if you're having performance issues. iterations-per-tick=Decrease this number if you're having performance issues.
@@ -81,4 +87,4 @@ history-length=History length
iterations-per-tick=Iterations per tick [img=info] iterations-per-tick=Iterations per tick [img=info]
[shortcut-name] [shortcut-name]
cybersyn-toggle-gui=Toggle LTN Manager cybersyn-toggle-gui=Toggle Cybersyn Manager

View File

@@ -364,7 +364,7 @@ data:extend({
-- custom inputs -- custom inputs
--{ --{
-- type = "custom-input", -- type = "custom-input",
-- name = "ltnm-toggle-gui", -- name = "cybersyn-toggle-gui",
-- key_sequence = "CONTROL + T", -- key_sequence = "CONTROL + T",
--}, --},
--{ --{
@@ -376,14 +376,14 @@ data:extend({
-- shortcuts -- shortcuts
{ {
type = "shortcut", type = "shortcut",
name = "ltnm-toggle-gui", name = "cybersyn-toggle-gui",
icon = data_util.build_sprite(nil, { 0, 0 }, util.paths.shortcut_icons, 32, 2), icon = data_util.build_sprite(nil, { 0, 0 }, util.paths.shortcut_icons, 32, 2),
disabled_icon = data_util.build_sprite(nil, { 48, 0 }, util.paths.shortcut_icons, 32, 2), disabled_icon = data_util.build_sprite(nil, { 48, 0 }, util.paths.shortcut_icons, 32, 2),
small_icon = data_util.build_sprite(nil, { 0, 32 }, util.paths.shortcut_icons, 24, 2), small_icon = data_util.build_sprite(nil, { 0, 32 }, util.paths.shortcut_icons, 24, 2),
disabled_small_icon = data_util.build_sprite(nil, { 36, 32 }, util.paths.shortcut_icons, 24, 2), disabled_small_icon = data_util.build_sprite(nil, { 36, 32 }, util.paths.shortcut_icons, 24, 2),
toggleable = true, toggleable = true,
action = "lua", action = "lua",
--associated_control_input = "ltnm-toggle-gui", --associated_control_input = "cybersyn-toggle-gui",
technology_to_unlock = "cybersyn-train-network", technology_to_unlock = "cybersyn-train-network",
}, },
}) })

View File

@@ -30,6 +30,8 @@ SETTING_DISABLE_DEPOT_BYPASS = 6
SETTING_ENABLE_SLOT_BARRING = 7 SETTING_ENABLE_SLOT_BARRING = 7
NETWORK_SIGNAL_DEFAULT = {name="signal-A", type="virtual"} NETWORK_SIGNAL_DEFAULT = {name="signal-A", type="virtual"}
NETWORK_SIGNAL_GUI_DEFAULT = {name="signal-each", type="virtual"}
NETWORK_ANYTHING = "signal-anything"
NETWORK_EACH = "signal-each" NETWORK_EACH = "signal-each"
INACTIVITY_TIME = 100 INACTIVITY_TIME = 100
LOCK_TRAIN_TIME = 60*60*60*24*7 LOCK_TRAIN_TIME = 60*60*60*24*7

View File

@@ -124,6 +124,8 @@
---@field public stuck_train_alert_enabled boolean --interface setting ---@field public stuck_train_alert_enabled boolean --interface setting
---@field public react_to_train_at_incorrect_station boolean --interface setting ---@field public react_to_train_at_incorrect_station boolean --interface setting
---@field public react_to_train_early_to_depot boolean --interface setting ---@field public react_to_train_early_to_depot boolean --interface setting
---@field public enable_manager boolean
---@field public manager_update_rate int
--if this is uncommented it means there are migrations to write --if this is uncommented it means there are migrations to write

View File

@@ -12,7 +12,7 @@ function alerts_tab.build(widths)
return { return {
tab = { tab = {
type = "tab", type = "tab",
caption = { "gui.ltnm-alerts" }, caption = { "cybersyn-gui.alerts" },
ref = { "alerts", "tab" }, ref = { "alerts", "tab" },
actions = { actions = {
on_click = { gui = "main", action = "change_tab", tab = "alerts" }, on_click = { gui = "main", action = "change_tab", tab = "alerts" },
@@ -36,7 +36,7 @@ function alerts_tab.build(widths)
type = "sprite-button", type = "sprite-button",
style = "tool_button_red", style = "tool_button_red",
sprite = "utility/trash", sprite = "utility/trash",
tooltip = { "gui.ltnm-delete-all-alerts" }, tooltip = { "cybersyn-gui.delete-all-alerts" },
ref = { "alerts", "delete_all_button" }, ref = { "alerts", "delete_all_button" },
actions = { actions = {
on_click = { gui = "main", action = "delete_all_alerts" }, on_click = { gui = "main", action = "delete_all_alerts" },
@@ -52,7 +52,7 @@ function alerts_tab.build(widths)
{ {
type = "label", type = "label",
style = "ltnm_semibold_label", style = "ltnm_semibold_label",
caption = { "gui.ltnm-no-alerts" }, caption = { "cybersyn-gui.no-alerts" },
ref = { "alerts", "warning_label" }, ref = { "alerts", "warning_label" },
}, },
}, },
@@ -121,7 +121,7 @@ function alerts_tab.update(self)
type = "label", type = "label",
style = "ltnm_clickable_semibold_label", style = "ltnm_clickable_semibold_label",
style_mods = { width = widths.alerts.train_id, horizontal_align = "center" }, style_mods = { width = widths.alerts.train_id, horizontal_align = "center" },
tooltip = { "gui.ltnm-open-train-gui" }, tooltip = { "cybersyn-gui.open-train-gui" },
}, },
{ {
type = "flow", type = "flow",
@@ -153,7 +153,7 @@ function alerts_tab.update(self)
type = "sprite-button", type = "sprite-button",
style = "tool_button_red", style = "tool_button_red",
sprite = "utility/trash", sprite = "utility/trash",
tooltip = { "gui.ltnm-delete-alert" }, tooltip = { "cybersyn-gui.delete-alert" },
}, },
}) })
end end
@@ -185,8 +185,8 @@ function alerts_tab.update(self)
{ elem_mods = { caption = util.signed_int32(alerts_entry.train.network_id) } }, { elem_mods = { caption = util.signed_int32(alerts_entry.train.network_id) } },
{ {
elem_mods = { elem_mods = {
caption = { "gui.ltnm-alert-" .. string.gsub(alerts_entry.type, "_", "-") }, caption = { "cybersyn-gui.alert-" .. string.gsub(alerts_entry.type, "_", "-") },
tooltip = { "gui.ltnm-alert-" .. string.gsub(alerts_entry.type, "_", "-") .. "-description" }, tooltip = { "cybersyn-gui.alert-" .. string.gsub(alerts_entry.type, "_", "-") .. "-description" },
}, },
}, },
{}, {},

View File

@@ -85,14 +85,14 @@ constants.gui_content_frame_height = 744
constants.gui_inventory_table_height = 40 * 18 constants.gui_inventory_table_height = 40 * 18
constants.gui_translations = { constants.gui_translations = {
delivering_to = { "gui.ltnm-delivering-to" }, delivering_to = { "cybersyn-gui.delivering-to" },
fetching_from = { "gui.ltnm-fetching-from" }, fetching_from = { "cybersyn-gui.fetching-from" },
loading_at = { "gui.ltnm-loading-at" }, loading_at = { "cybersyn-gui.loading-at" },
not_available = { "gui.ltnm-not-available" }, not_available = { "cybersyn-gui.not-available" },
parked_at_depot_with_residue = { "gui.ltnm-parked-at-depot-with-residue" }, parked_at_depot_with_residue = { "cybersyn-gui.parked-at-depot-with-residue" },
parked_at_depot = { "gui.ltnm-parked-at-depot" }, parked_at_depot = { "cybersyn-gui.parked-at-depot" },
returning_to_depot = { "gui.ltnm-returning-to-depot" }, returning_to_depot = { "cybersyn-gui.returning-to-depot" },
unloading_at = { "gui.ltnm-unloading-at" }, unloading_at = { "cybersyn-gui.unloading-at" },
} }
constants.input_sanitizers = { constants.input_sanitizers = {
@@ -144,8 +144,7 @@ constants.ltn_event_names = {
if script then if script then
constants.open_station_gui_tooltip = { constants.open_station_gui_tooltip = {
"", "",
{ "gui.ltnm-open-station-gui" }, { "cybersyn-gui.open-station-gui" },
remote.interfaces["ltn-combinator"] and { "", "\n", { "gui.ltnm-open-ltn-combinator-gui" } } or nil,
} }
end end

View File

@@ -8,7 +8,7 @@ function depots_tab.build(widths)
return { return {
tab = { tab = {
type = "tab", type = "tab",
caption = { "gui.ltnm-depots" }, caption = { "cybersyn-gui.depots" },
ref = { "depots", "tab" }, ref = { "depots", "tab" },
actions = { actions = {
on_click = { gui = "main", action = "change_tab", tab = "depots" }, on_click = { gui = "main", action = "change_tab", tab = "depots" },
@@ -25,7 +25,7 @@ function depots_tab.build(widths)
style_mods = { right_padding = 4 }, style_mods = { right_padding = 4 },
templates.sort_checkbox(widths, "depots", "name", true, nil, true), templates.sort_checkbox(widths, "depots", "name", true, nil, true),
templates.sort_checkbox(widths, "depots", "network_id", false), templates.sort_checkbox(widths, "depots", "network_id", false),
templates.sort_checkbox(widths, "depots", "status", false, { "gui.ltnm-status-description" }), templates.sort_checkbox(widths, "depots", "status", false, { "cybersyn-gui.status-description" }),
templates.sort_checkbox(widths, "depots", "trains", false), templates.sort_checkbox(widths, "depots", "trains", false),
}, },
{ type = "scroll-pane", style = "ltnm_table_scroll_pane", ref = { "depots", "scroll_pane" } }, { type = "scroll-pane", style = "ltnm_table_scroll_pane", ref = { "depots", "scroll_pane" } },
@@ -37,7 +37,7 @@ function depots_tab.build(widths)
{ {
type = "label", type = "label",
style = "ltnm_semibold_label", style = "ltnm_semibold_label",
caption = { "gui.ltnm-no-depots" }, caption = { "cybersyn-gui.no-depots" },
ref = { "depots", "warning_label" }, ref = { "depots", "warning_label" },
}, },
}, },

View File

@@ -12,7 +12,7 @@ function history_tab.build(widths)
return { return {
tab = { tab = {
type = "tab", type = "tab",
caption = { "gui.ltnm-history" }, caption = { "cybersyn-gui.history" },
ref = { "history", "tab" }, ref = { "history", "tab" },
actions = { actions = {
on_click = { gui = "main", action = "change_tab", tab = "history" }, on_click = { gui = "main", action = "change_tab", tab = "history" },
@@ -38,7 +38,7 @@ function history_tab.build(widths)
type = "sprite-button", type = "sprite-button",
style = "tool_button_red", style = "tool_button_red",
sprite = "utility/trash", sprite = "utility/trash",
tooltip = { "gui.ltnm-clear-history" }, tooltip = { "cybersyn-gui.clear-history" },
ref = { "history", "clear_button" }, ref = { "history", "clear_button" },
actions = { actions = {
on_click = { gui = "main", action = "clear_history" }, on_click = { gui = "main", action = "clear_history" },
@@ -54,7 +54,7 @@ function history_tab.build(widths)
{ {
type = "label", type = "label",
style = "ltnm_semibold_label", style = "ltnm_semibold_label",
caption = { "gui.ltnm-no-history" }, caption = { "cybersyn-gui.no-history" },
ref = { "history", "warning_label" }, ref = { "history", "warning_label" },
}, },
}, },

View File

@@ -1,20 +1,22 @@
local misc = require("__flib__.misc") local gui = require("__flib__.gui-lite")
local templates = require("templates") local util = require("scripts.gui.util")
local templates = require("scripts.gui.templates")
local format = require("__flib__.format")
local inventory_tab = {} local inventory_tab = {}
function inventory_tab.build() function inventory_tab.create()
return { return {
tab = { tab = {
name = "manager_inventory_tab",
type = "tab", type = "tab",
caption = { "gui.ltnm-inventory" }, caption = { "cybersyn-gui.inventory" },
ref = { "inventory", "tab" }, ref = { "inventory", "tab" },
actions = { handler = inventory_tab.handle.on_inventory_tab_selected
on_click = { gui = "main", action = "change_tab", tab = "inventory" },
},
}, },
content = { content = {
name = "manager_inventory_content_frame",
type = "flow", type = "flow",
style_mods = { horizontal_spacing = 12 }, style_mods = { horizontal_spacing = 12 },
direction = "horizontal", direction = "horizontal",
@@ -26,62 +28,245 @@ function inventory_tab.build()
} }
end end
local function update_table(self, name, color) ---@param map_data MapData
local translations = self.player_table.dictionaries.materials ---@param player_data PlayerData
function inventory_tab.build(map_data, player_data)
local state = self.state local refs = player_data.refs
local refs = self.refs.inventory
local search_query = state.search_query local search_query = player_data.search_query
local search_network_id = state.network_id local search_item = player_data.search_item
local search_surface = state.surface local search_network_name = player_data.search_network_name
local search_network_mask = player_data.search_network_mask
local search_surface_idx = player_data.search_surface_idx
local inventory_provided = {}
local inventory_in_transit = {}
local inventory_requested = {}
local ltn_inventory = state.ltn_data.inventory[name][search_surface] local stations_sorted = {}
local i = 0
local table = refs[name].table for id, station in pairs(map_data.stations) do
local children = table.children local entity = station.entity_stop
if not entity.valid then
goto continue
end
for name, count_by_network_id in pairs(ltn_inventory or {}) do if search_query then
if if not string.match(entity.backer_name, search_query) then
bit32.btest(count_by_network_id.combined_id, search_network_id) goto continue
and string.find(string.lower(translations[name]), string.lower(search_query)) end
then end
local running_count = 0 -- move surface comparison up higher in query to short circuit query earlier if surface doesn't match
for network_id, count in pairs(count_by_network_id) do if search_surface_idx then
if network_id ~= "combined_id" and bit32.btest(network_id, search_network_id) then if search_surface_idx == -1 then
running_count = running_count + count goto has_match
elseif entity.surface.index ~= search_surface_idx then
goto continue
end
::has_match::
end
if search_network_name then
if search_network_name == (NETWORK_EACH or NETWORK_ANYTHING) then
goto has_match
end
if search_network_name ~= station.network_name then
goto continue
end
::has_match::
local train_flag = get_network_flag(station, station.network_name)
if not bit32.btest(search_network_mask, train_flag) then
goto continue
end
elseif search_network_mask ~= -1 then
if station.network_name == NETWORK_EACH then
local masks = station.network_flag--[[@as {}]]
for _, network_flag in pairs(masks) do
if bit32.btest(search_network_mask, network_flag) then
goto has_match
end
end
goto continue
::has_match::
elseif not bit32.btest(search_network_mask, station.network_flag) then
goto continue
end
end
if search_item then
if station.deliveries then
for item_name, _ in pairs(station.deliveries) do
if item_name == search_item then
goto has_match
end
end
end
local comb1_signals, _ = get_signals(station)
if comb1_signals then
for _, signal_ID in pairs(comb1_signals) do
local item = signal_ID.signal.name
if item then
if item == search_item then
goto has_match
end
end
end
end
goto continue
::has_match::
end
stations_sorted[#stations_sorted + 1] = id
::continue::
end
for i, station_id in pairs(stations_sorted) do
--- @class Station
local station = map_data.stations[station_id]
local comb1_signals, _ = get_signals(station)
if comb1_signals then
for _, v in pairs(comb1_signals) do
local item = v.signal
local count = v.count
if item.type ~= "virtual" then
if count > 0 then
if inventory_provided[item.name] == nil then
inventory_provided[item.name] = count
else
inventory_provided[item.name] = inventory_provided[item.name] + count
end
else
if inventory_requested[item.name] == nil then
inventory_requested[item.name] = count
else
inventory_requested[item.name] = inventory_requested[item.name] + count
end
end
end end
end end
end
if running_count > 0 then local deliveries = station.deliveries
i = i + 1 if deliveries then
local button = children[i] for item, count in pairs(deliveries) do
if not button then if count > 0 then
button = table.add({ type = "sprite-button", style = "flib_slot_button_" .. color, enabled = false }) if inventory_in_transit[item] == nil then
inventory_in_transit[item] = 0
inventory_in_transit[item] = inventory_in_transit[item] + count
else
inventory_in_transit[item] = inventory_in_transit[item] + count
end
end end
button.sprite = string.gsub(name, ",", "/")
button.number = running_count
button.tooltip = "[img="
.. string.gsub(name, ",", "/")
.. "] [font=default-semibold]"
.. translations[name]
.. "[/font]\n"
.. misc.delineate_number(running_count)
end end
end end
end end
for j = i + 1, #children do local inventory_provided_table = refs.inventory_provided_table
children[j].destroy() local provided_children = {}
local i = 0
for item, count in pairs(inventory_provided) do
i = i + 1
local sprite, img_path, item_string = util.generate_item_references(item)
if game.is_valid_sprite_path(sprite) then
provided_children[#provided_children+1] = {
type = "sprite-button",
style = "flib_slot_button_green",
enabled = false,
sprite = sprite,
number = count,
tooltip = { "",
img_path,
" [font=default-semibold]",
{ item_string },
"[/font]\n"..format.number(count),
},
}
end
end end
local inventory_requested_table = refs.inventory_requested_table
local requested_children = {}
local i = 0
for item, count in pairs(inventory_requested) do
i = i + 1
local sprite, img_path, item_string = util.generate_item_references(item)
if game.is_valid_sprite_path(sprite) then
requested_children[#requested_children+1] = {
type = "sprite-button",
style = "flib_slot_button_red",
enabled = false,
sprite = sprite,
number = count,
tooltip = { "",
img_path,
" [font=default-semibold]",
{ item_string },
"[/font]\n"..format.number(count),
},
}
end
end
local inventory_in_transit_table = refs.inventory_in_transit_table
local in_transit_children = {}
local i = 0
for item, count in pairs(inventory_in_transit) do
i = i + 1
local sprite, img_path, item_string = util.generate_item_references(item)
if game.is_valid_sprite_path(sprite) then
in_transit_children[#in_transit_children+1] = {
type = "sprite-button",
style = "flib_slot_button_blue",
enabled = false,
sprite = sprite,
number = count,
tooltip = { "",
img_path,
" [font=default-semibold]",
{ item_string },
"[/font]\n"..format.number(count),
},
}
end
end
if next(inventory_provided_table.children) ~= nil then
refs.inventory_provided_table.clear()
end
if next(inventory_requested_table.children) ~= nil then
refs.inventory_requested_table.clear()
end
if next(inventory_in_transit_table.children) ~= nil then
refs.inventory_in_transit_table.clear()
end
gui.add(refs.inventory_provided_table, provided_children)
gui.add(refs.inventory_requested_table, requested_children)
gui.add(refs.inventory_in_transit_table, in_transit_children)
end end
function inventory_tab.update(self) inventory_tab.handle = {}
update_table(self, "provided", "green")
update_table(self, "in_transit", "blue") --- @param e {player_index: uint}
update_table(self, "requested", "red") function inventory_tab.wrapper(e, handler)
local player = game.get_player(e.player_index)
if not player then return end
local player_data = global.manager.players[e.player_index]
handler(player, player_data, player_data.refs, e)
end end
---@param player LuaPlayer
---@param player_data PlayerData
function inventory_tab.handle.on_inventory_tab_selected(player, player_data)
player_data.selected_tab = "inventory_tab"
end
gui.add_handlers(inventory_tab.handle, inventory_tab.wrapper)
return inventory_tab return inventory_tab

View File

@@ -4,7 +4,7 @@ local mod_gui = require("__core__.lualib.mod-gui")
local manager = require("scripts.gui.manager") local manager = require("scripts.gui.manager")
--- @class Manager --- @class Manager
--- @field players table<int, PlayerData> --- @field players table<uint, PlayerData>
--- @field item_order table<string, int> --- @field item_order table<string, int>
--- @class PlayerData --- @class PlayerData
@@ -18,6 +18,7 @@ local manager = require("scripts.gui.manager")
--- @field trains_orderings uint[] --- @field trains_orderings uint[]
--- @field trains_orderings_invert boolean[] --- @field trains_orderings_invert boolean[]
--- @field pinning boolean --- @field pinning boolean
--- @field selected_tab string?
@@ -46,7 +47,7 @@ end
local manager_gui = {} local manager_gui = {}
function manager_gui.on_lua_shortcut(e) function manager_gui.on_lua_shortcut(e)
if e.prototype_name == "ltnm-toggle-gui" then if e.prototype_name == "cybersyn-toggle-gui" then
manager.wrapper(e, manager.handle.manager_toggle) manager.wrapper(e, manager.handle.manager_toggle)
end end
end end
@@ -65,7 +66,7 @@ function manager_gui.on_player_created(e)
} }
global.manager.players[e.player_index] = player_data global.manager.players[e.player_index] = player_data
manager.update(global, player, player_data) --manager.update(global, player, player_data)
--top_left_button_update(player, player_data) --top_left_button_update(player, player_data)
end end
@@ -91,6 +92,21 @@ function manager_gui.on_runtime_mod_setting_changed(e)
end end
end end
commands.add_command("cybersyn_rebuild_manager_windows", nil, function(command)
local manager_data = global.manager
if manager_data then
---@param v PlayerData
for i, v in pairs(manager_data.players) do
local player = game.get_player(i)
if player ~= nil then
v.refs.manager_window.destroy()
v.refs = manager.create(player)
end
end
end
end)
--- @param manager Manager --- @param manager Manager
local function init_items(manager) local function init_items(manager)
@@ -135,4 +151,17 @@ function manager_gui.on_init()
end end
--gui.handle_events() --gui.handle_events()
---@param global cybersyn.global
function manager_gui.tick(global)
local manager_data = global.manager
if manager_data then
for i, v in pairs(manager_data.players) do
if v.is_manager_open then
local query_limit = settings.get_player_settings(i)["cybersyn-manager-result-limit"].value
manager.update(global, v, query_limit)
end
end
end
end
return manager_gui return manager_gui

View File

@@ -8,9 +8,10 @@ local templates = require("scripts.gui.templates")
local stations_tab = require("scripts.gui.stations") local stations_tab = require("scripts.gui.stations")
--local trains_tab = require("scripts.gui.trains") --local trains_tab = require("scripts.gui.trains")
--local depots_tab = require("scripts.gui.depots") --local depots_tab = require("scripts.gui.depots")
--local inventory_tab = require("scripts.gui.inventory") local inventory_tab = require("scripts.gui.inventory")
--local history_tab = require("scripts.gui.history") --local history_tab = require("scripts.gui.history")
--local alerts_tab = require("scripts.gui.alerts") --local alerts_tab = require("scripts.gui.alerts")
local util = require("scripts.gui.util")
local manager = {} local manager = {}
@@ -36,19 +37,19 @@ function manager.create(player)
style = "flib_titlebar_flow", style = "flib_titlebar_flow",
handler = manager.handle.manager_titlebar_click, handler = manager.handle.manager_titlebar_click,
children = { children = {
{ type = "label", style = "frame_title", caption = { "mod-name.LtnManager" }, ignored_by_interaction = true }, { type = "label", style = "frame_title", caption = { "mod-name.cybersyn" }, ignored_by_interaction = true },
{ type = "empty-widget", style = "flib_titlebar_drag_handle", ignored_by_interaction = true }, { type = "empty-widget", style = "flib_titlebar_drag_handle", ignored_by_interaction = true },
{ {
name = "manager_dispatcher_status_label", name = "manager_dispatcher_status_label",
type = "label", type = "label",
style = "bold_label", style = "bold_label",
style_mods = { font_color = constants.colors.red.tbl, left_margin = -4, top_margin = 1 }, style_mods = { font_color = constants.colors.red.tbl, left_margin = -4, top_margin = 1 },
caption = { "gui.ltnm-dispatcher-disabled" }, caption = { "cybersyn-gui.dispatcher-disabled" },
tooltip = { "gui.ltnm-dispatcher-disabled-description" }, tooltip = { "cybersyn-gui.dispatcher-disabled-description" },
visible = not settings.global["cybersyn-enable-planner"].value, visible = not settings.global["cybersyn-enable-planner"].value,
}, },
templates.frame_action_button("manager_pin_button", "ltnm_pin", { "gui.ltnm-keep-open" }, manager.handle.manager_pin),--on_gui_clicked templates.frame_action_button("manager_pin_button", "ltnm_pin", { "cybersyn-gui.keep-open" }, manager.handle.manager_pin),--on_gui_clicked
templates.frame_action_button("manager_refresh_button", "ltnm_refresh", { "gui.ltnm-refresh-tooltip" }, manager.handle.manager_refresh_click),--on_gui_clicked templates.frame_action_button("manager_refresh_button", "ltnm_refresh", { "cybersyn-gui.refresh-tooltip" }, manager.handle.manager_refresh_click),--on_gui_clicked
templates.frame_action_button(nil, "utility/close", { "gui.close-instruction" }, manager.handle.manager_close),--on_gui_clicked templates.frame_action_button(nil, "utility/close", { "gui.close-instruction" }, manager.handle.manager_close),--on_gui_clicked
}, },
}, },
@@ -61,15 +62,20 @@ function manager.create(player)
type = "frame", type = "frame",
style = "ltnm_main_toolbar_frame", style = "ltnm_main_toolbar_frame",
children = { children = {
{ type = "label", style = "subheader_caption_label", caption = { "gui.ltnm-search-label" } }, { type = "label", style = "subheader_caption_label", caption = { "cybersyn-gui.search-label" } },
{ {
name = "manager_text_search_field", name = "manager_text_search_field",
type = "textfield", type = "textfield",
clear_and_focus_on_right_click = true, clear_and_focus_on_right_click = true,
handler = manager.handle.manager_update_text_search, --on_gui_text_changed handler = manager.handle.manager_update_text_search, --on_gui_text_changed
}, },
--item search box commented out. It *works*, but, the filtering logic only checks delivieres, so I'm not sure what Mami intended it for, so I'm leaving it off for now...
{ type = "label", style = "subheader_caption_label", caption = { "cybersyn-gui.search-item-label" } },
{ type= "choose-elem-button", name="manager_item_filter", style="slot_button_in_shallow_frame", elem_type="signal", handler=manager.handle.manager_update_item_search, },
{ type = "empty-widget", style = "flib_horizontal_pusher" }, { type = "empty-widget", style = "flib_horizontal_pusher" },
{ type = "label", style = "caption_label", caption = { "gui.ltnm-network-id-label" } }, { type = "label", style = "caption_label", caption = { "cybersyn-gui.network-name-label" } },
{ type= "choose-elem-button", name="network", style="slot_button_in_shallow_frame", elem_type="signal", tooltip={"cybersyn-gui.network-tooltip"}, handler=manager.handle.manager_update_network_name, },
{ type = "label", style = "caption_label", caption = { "cybersyn-gui.network-id-label" } },
{ {
name = "manager_network_mask_field", name = "manager_network_mask_field",
type = "textfield", type = "textfield",
@@ -80,7 +86,7 @@ function manager.create(player)
text = "-1", text = "-1",
handler = manager.handle.manager_update_network_mask, --on_gui_text_changed handler = manager.handle.manager_update_network_mask, --on_gui_text_changed
}, },
{ type = "label", style = "caption_label", caption = { "gui.ltnm-surface-label" } }, { type = "label", style = "caption_label", caption = { "cybersyn-gui.surface-label" } },
{ {
name = "manager_surface_dropdown", name = "manager_surface_dropdown",
type = "drop-down", type = "drop-down",
@@ -92,10 +98,9 @@ function manager.create(player)
name = "manager_tabbed_pane", name = "manager_tabbed_pane",
type = "tabbed-pane", type = "tabbed-pane",
style = "ltnm_tabbed_pane", style = "ltnm_tabbed_pane",
stations_tab.create(widths),
inventory_tab.create(),
selected_tab_index = 1, selected_tab_index = 1,
tabs = {
stations_tab.create(widths)
}
}, },
}, },
}, },
@@ -111,12 +116,53 @@ function manager.create(player)
return refs return refs
end end
function manager.build(player_data)
local refs = player_data.refs
-- Surface dropdown
--- @type LuaGuiElement
local surface_dropdown = refs.manager_surface_dropdown
local surfaces = game.surfaces
local selected_surface_id = player_data.search_surface_idx
local currently_selected_index = surface_dropdown.selected_index
local currently_selected_surface = nil
if currently_selected_index ~= (nil or 0) then
currently_selected_surface = surface_dropdown.get_item(currently_selected_index)
end
surface_dropdown.clear_items()
surface_dropdown.add_item("all", 1)
i = 1
for name, _ in pairs(surfaces) do
i = i + 1
surface_dropdown.add_item(name, i)
--reselect same surface
if name == currently_selected_surface then
refs.manager_surface_dropdown.selected_index = i
end
end
-- Validate that the selected index still exist
if selected_surface_id then
local selected_surface = game.get_surface(selected_surface_id)
-- If the surface was invalidated since last update, reset to all
if not selected_surface then
player_data.search_surface_idx = -1
end
else
player_data.search_surface_idx = -1
end
end
--- @param map_data MapData --- @param map_data MapData
--- @param player LuaPlayer
--- @param player_data PlayerData --- @param player_data PlayerData
function manager.update(map_data, player, player_data) function manager.update(map_data, player_data, query_limit)
--local tab = trains_tab.build(map_data, player_data) if player_data.selected_tab ~= nil then
--gui.add(_, tab, player_data.refs) manager.build(player_data)
end
if player_data.selected_tab == "stations_tab" then
stations_tab.build(map_data, player_data, query_limit)
elseif player_data.selected_tab == "inventory_tab" then
inventory_tab.build(map_data, player_data)
end
end end
@@ -157,7 +203,7 @@ function manager.handle.manager_open(player, player_data, refs)
end end
player_data.is_manager_open = true player_data.is_manager_open = true
player.set_shortcut_toggled("ltnm-toggle-gui", true) player.set_shortcut_toggled("cybersyn-toggle-gui", true)
end end
@@ -165,23 +211,7 @@ end
--- @param player_data PlayerData --- @param player_data PlayerData
--- @param refs table<string, LuaGuiElement> --- @param refs table<string, LuaGuiElement>
function manager.handle.manager_close(player, player_data, refs) function manager.handle.manager_close(player, player_data, refs)
if player_data.pinning then util.close_manager_window(player, player_data, refs)
return
end
refs.manager_window.visible = false
player_data.visible = false
if player.opened == refs.manager_window then
player.opened = nil
end
player_data.is_manager_open = false
player.set_shortcut_toggled("ltnm-toggle-gui", false)
player_data.refs.manager_window.destroy()
player_data.refs = manager.create(player)
end end
--- @param player LuaPlayer --- @param player LuaPlayer
@@ -233,12 +263,27 @@ function manager.handle.manager_update_text_search(player, player_data, refs, e)
player_data.search_query = query player_data.search_query = query
end end
--- @param player LuaPlayer
--- @param player_data PlayerData
--- @param refs table<string, LuaGuiElement>
--- @param e GuiEventData
function manager.handle.manager_update_item_search(player, player_data, refs, e)
local element = e.element
local signal = element.elem_value
if signal then
player_data.search_item = signal.name
else
player_data.search_item = nil
end
end
--- @param player LuaPlayer --- @param player LuaPlayer
--- @param player_data PlayerData --- @param player_data PlayerData
--- @param refs table<string, LuaGuiElement> --- @param refs table<string, LuaGuiElement>
function manager.handle.manager_update_network_name(player, player_data, refs) function manager.handle.manager_update_network_name(player, player_data, refs, e)
local signal = refs.manager_network_name.elem_value local element = e.element
local signal = element.elem_value
if signal then if signal then
player_data.search_network_name = signal.name player_data.search_network_name = signal.name
else else
@@ -248,18 +293,30 @@ end
--- @param player LuaPlayer --- @param player LuaPlayer
--- @param player_data PlayerData --- @param player_data PlayerData
--- @param refs table<string, LuaGuiElement> --- @param refs table<string, LuaGuiElement>
function manager.handle.manager_update_network_mask(player, player_data, refs) function manager.handle.manager_update_network_mask(player, player_data, refs, e)
player_data.search_network_mask = tonumber(refs.manager_network_mask_field.text) or -1 player_data.search_network_mask = tonumber(e.text) or -1
end end
--- @param player LuaPlayer --- @param player LuaPlayer
--- @param player_data PlayerData --- @param player_data PlayerData
--- @param refs table<string, LuaGuiElement> --- @param refs table<string, LuaGuiElement>
function manager.handle.manager_update_surface(player, player_data, refs) function manager.handle.manager_update_surface(player, player_data, refs, e)
local i = refs.manager_surface_dropdown.selected_index --- @type LuaGuiElement
player_data.search_surface_idx = i--TODO: fix this local element = e.element
local i = element.selected_index
local refs = player_data.refs
local surface_id = -1
--all surfaces should always be the first entry with an index of 1
if i > 1 then
local surface_name = refs.manager_surface_dropdown.get_item(i)
local surface = game.get_surface(surface_name)
surface_id = surface.index
end
player_data.search_surface_idx = surface_id
end end
gui.add_handlers(manager.handle, manager.wrapper) gui.add_handlers(manager.handle, manager.wrapper)
return manager return manager

View File

@@ -9,14 +9,14 @@ local stations_tab = {}
function stations_tab.create(widths) function stations_tab.create(widths)
return { return {
tab = { tab = {
name = "manager_stations_tab",
type = "tab", type = "tab",
caption = { "gui.ltnm-stations" }, caption = { "cybersyn-gui.stations" },
ref = { "stations", "tab" }, ref = { "stations", "tab" },
actions = { handler = stations_tab.handle.on_stations_tab_selected
on_click = { gui = "main", action = "change_tab", tab = "stations" },
},
}, },
content = { content = {
name = "manager_stations_content_frame",
type = "frame", type = "frame",
style = "ltnm_main_content_frame", style = "ltnm_main_content_frame",
direction = "vertical", direction = "vertical",
@@ -25,19 +25,19 @@ function stations_tab.create(widths)
type = "frame", type = "frame",
style = "ltnm_table_toolbar_frame", style = "ltnm_table_toolbar_frame",
templates.sort_checkbox(widths, "stations", "name", true), templates.sort_checkbox(widths, "stations", "name", true),
templates.sort_checkbox(widths, "stations", "status", false, { "gui.ltnm-status-description" }), templates.sort_checkbox(widths, "stations", "status", false), --repurposed status column, description no longer necessary
templates.sort_checkbox(widths, "stations", "network_id", false), templates.sort_checkbox(widths, "stations", "network_id", false),
templates.sort_checkbox( templates.sort_checkbox(
widths, widths,
"stations", "stations",
"provided_requested", "provided_requested",
false, false,
{ "gui.ltnm-provided-requested-description" } { "cybersyn-gui-provided-requested-description" }
), ),
templates.sort_checkbox(widths, "stations", "shipments", false, { "gui.ltnm-shipments-description" }), templates.sort_checkbox(widths, "stations", "shipments", false, { "cybersyn-gui-shipments-description" }),
templates.sort_checkbox(widths, "stations", "control_signals", false), templates.sort_checkbox(widths, "stations", "control_signals", false),
}, },
{ type = "scroll-pane", style = "ltnm_table_scroll_pane", ref = { "stations", "scroll_pane" } }, { name = "manager_stations_tab_scroll_pane", type = "scroll-pane", style = "ltnm_table_scroll_pane", ref = { "stations", "scroll_pane" } },
{ {
type = "flow", type = "flow",
style = "ltnm_warning_flow", style = "ltnm_warning_flow",
@@ -46,7 +46,7 @@ function stations_tab.create(widths)
{ {
type = "label", type = "label",
style = "ltnm_semibold_label", style = "ltnm_semibold_label",
caption = { "gui.ltnm-no-stations" }, caption = { "cybersyn-gui-no-stations" },
ref = { "stations", "warning_label" }, ref = { "stations", "warning_label" },
}, },
}, },
@@ -57,29 +57,52 @@ end
--- @param map_data MapData --- @param map_data MapData
--- @param player_data PlayerData --- @param player_data PlayerData
--- @return GuiElemDef --- @return GuiElemDef
function stations_tab.build(map_data, player_data) function stations_tab.build(map_data, player_data, query_limit)
local widths = constants.gui["en"] local widths = constants.gui["en"]
local refs = player_data.refs
local search_query = player_data.search_query
local search_item = player_data.search_item local search_item = player_data.search_item
local search_network_name = player_data.search_network_name local search_network_name = player_data.search_network_name
local search_network_mask = player_data.search_network_mask local search_network_mask = player_data.search_network_mask
local search_surface_idx = player_data.search_surface_idx local search_surface_idx = player_data.search_surface_idx
local stations = map_data.stations
local stations_sorted = {} local stations_sorted = {}
local to_sorted_manifest = {} local to_sorted_manifest = {}
for id, station in pairs(map_data.stations) do
local i = 0
for id, station in pairs(stations) do
local entity = station.entity_stop local entity = station.entity_stop
if not entity.valid then if not entity.valid then
goto continue goto continue
end end
if search_query then
if not string.match(entity.backer_name, search_query) then
goto continue
end
end
-- move surface comparison up higher in query to short circuit query earlier if surface doesn't match; this can exclude hundreds of stations instantly in SE
if search_surface_idx then
if search_surface_idx == -1 then
goto has_match
elseif entity.surface.index ~= search_surface_idx then
goto continue
end
::has_match::
end
if search_network_name then if search_network_name then
if search_network_name ~= station.network_name then if search_network_name ~= station.network_name then
goto continue goto continue
end end
local train_flag = get_network_flag(station, search_network_name) local train_flag = get_network_flag(station, station.network_name)
if not bit32.btest(search_network_mask, train_flag) then if not bit32.btest(search_network_mask, train_flag) then
goto continue goto continue
end end
@@ -98,19 +121,24 @@ function stations_tab.build(map_data, player_data)
end end
end end
if search_surface_idx then
if entity.surface.index ~= search_surface_idx then
goto continue
end
end
if search_item then if search_item then
if not station.deliveries then if station.deliveries then
goto continue for item_name, _ in pairs(station.deliveries) do
if item_name == search_item then
goto has_match
end
end
end end
for item_name, _ in pairs(station.deliveries) do local comb1_signals, _ = get_signals(station)
if item_name == search_item then if comb1_signals then
goto has_match for _, signal_ID in pairs(comb1_signals) do
local item = signal_ID.signal.name
if item then
if item == search_item then
goto has_match
end
end
end end
end end
goto continue goto continue
@@ -118,6 +146,10 @@ function stations_tab.build(map_data, player_data)
end end
stations_sorted[#stations_sorted + 1] = id stations_sorted[#stations_sorted + 1] = id
i = i + 1
if query_limit ~= -1 and i >= query_limit then
break
end
::continue:: ::continue::
end end
@@ -182,72 +214,127 @@ function stations_tab.build(map_data, player_data)
return (not player_data.trains_orderings_invert[#player_data.trains_orderings_invert]) == (a < b) return (not player_data.trains_orderings_invert[#player_data.trains_orderings_invert]) == (a < b)
end) end)
local scroll_pane = refs.scroll_pane local scroll_pane = refs.manager_stations_tab_scroll_pane
if next(scroll_pane.children) ~= nil then
refs.manager_stations_tab_scroll_pane.clear()
end
for i, station_id in pairs(stations_sorted) do for i, station_id in pairs(stations_sorted) do
local station = map_data.stations[station_id] --- @type Station
local station = stations[station_id]
local network_sprite = "utility/close_black"
local network_name = station.network_name
local network_flag = get_network_flag(station, network_name)
if network_name ~= nil then
network_sprite, _, _ = util.generate_item_references(network_name)
end
local color = i % 2 == 0 and "dark" or "light" local color = i % 2 == 0 and "dark" or "light"
local row = gui.add(scroll_pane, { gui.add(scroll_pane, {
type = "frame", type = "frame",
style = "ltnm_table_row_frame_" .. color,
{ {
type = "label", type = "label",
style = "ltnm_clickable_semibold_label", style = "ltnm_clickable_semibold_label",
style_mods = { width = widths.name }, style_mods = { width = widths.stations.name },
tooltip = constants.open_station_gui_tooltip, tooltip = constants.open_station_gui_tooltip,
caption = station.entity_stop.backer_name,
handler = stations_tab.handle.open_station_gui,
tags = { station_id = station_id }
}, },
templates.status_indicator(widths.status, true), --templates.status_indicator(widths.stations.status, true), --repurposing status column for network name
{ type = "label", style_mods = { width = widths.network_id, horizontal_align = "center" } }, { type = "sprite-button", style = "ltnm_small_slot_button_default", enabled = false, sprite = network_sprite, },
templates.small_slot_table(widths, color, "provided_requested"), { type = "label", style_mods = { width = widths.stations.network_id, horizontal_align = "center" }, caption = network_flag },
templates.small_slot_table(widths, color, "shipments"), templates.small_slot_table(widths.stations, color, "provided_requested"),
templates.small_slot_table(widths, color, "control_signals"), templates.small_slot_table(widths.stations, color, "shipments"),
}) templates.small_slot_table(widths.stations, color, "control_signals"),
}, refs)
gui.add(row, { gui.add(refs.provided_requested_table, util.slot_table_build_from_station(station))
{ gui.add(refs.shipments_table, util.slot_table_build_from_deliveries(station))
elem_mods = { caption = station.entity_stop.name }, gui.add(refs.control_signals_table, util.slot_table_build_from_control_signals(station))
handler = stations_tab.hande.open_station_gui,
tags = station_id,
},
{ elem_mods = { caption = station.network_name } },
{ elem_mods = { caption = station.network_flag } },
})
util.slot_table_update(row.provided_requested_frame.provided_requested_table, {
{ color = "green", entries = station.provided, translations = dictionaries.materials },
{ color = "red", entries = station.requested, translations = dictionaries.materials },
})
util.slot_table_update(row.shipments_frame.shipments_table, {
{ color = "green", entries = station.inbound, translations = dictionaries.materials },
{ color = "blue", entries = station.outbound, translations = dictionaries.materials },
})
util.slot_table_update(row.control_signals_frame.control_signals_table, {
{
color = "default",
entries = station.control_signals,
translations = dictionaries.virtual_signals,
type = "virtual-signal",
},
})
end end
if #stations_sorted == 0 then if #stations_sorted == 0 then
refs.warning_flow.visible = true --refs.warning_flow.visible = true
scroll_pane.visible = false scroll_pane.visible = false
refs.content_frame.style = "ltnm_main_warning_frame" --refs.content_frame.style = "ltnm_main_warning_frame"
else else
refs.warning_flow.visible = false --refs.warning_flow.visible = false
scroll_pane.visible = true scroll_pane.visible = true
refs.content_frame.style = "ltnm_main_content_frame" --refs.content_frame.style = "ltnm_main_content_frame"
end end
end end
stations_tab.hande = {} stations_tab.handle = {}
function stations_tab.hande.open_station_gui() --- @param e {player_index: uint}
function stations_tab.wrapper(e, handler)
local player = game.get_player(e.player_index)
if not player then return end
local player_data = global.manager.players[e.player_index]
handler(player, player_data, player_data.refs, e)
end end
--- @param e GuiEventData
--- @param player LuaPlayer
--- @param player_data PlayerData
function stations_tab.handle.open_station_gui(player, player_data, refs, e)
local station_id = e.element.tags.station_id
--- @type Station
local station = global.stations[station_id]
local station_entity = station.entity_stop
local station_comb1 = station.entity_comb1
local station_comb2 = station.entity_comb2
if not station_entity or not station_entity.valid then
util.error_flying_text(player, { "message.ltnm-error-station-is-invalid" })
return
end
if e.shift then
if station_entity.surface ~= player.surface then
util.error_flying_text(player, { "cybersyn-message.error-cross-surface-camera-invalid" })
else
player.zoom_to_world(station_entity.position, 1, station_entity)
rendering.draw_circle({
color = constants.colors.red.tbl,
target = station_entity.position,
surface = station_entity.surface,
radius = 0.5,
filled = false,
width = 5,
time_to_live = 60 * 3,
players = { player },
})
if not player_data.pinning then util.close_manager_window(player, player_data, refs) end
end
elseif e.control then
if station_comb1 ~= nil and station_comb1.valid then
player.opened = station_comb1
else
util.error_flying_text(player, { "cybersyn-message.error-cybernetic-combinator-not-found" })
end
elseif e.alt then
if station_comb2 ~= nil and station_comb2.valid then
player.opened = station_comb2
else
util.error_flying_text(player, { "cybersyn-message.error-station-control-combinator-not-found" })
end
else
player.opened = station_entity
end
end
---@param player LuaPlayer
---@param player_data PlayerData
function stations_tab.handle.on_stations_tab_selected(player, player_data)
player_data.selected_tab = "stations_tab"
end
gui.add_handlers(stations_tab.handle, stations_tab.wrapper)
return stations_tab return stations_tab

View File

@@ -30,7 +30,7 @@ function templates.inventory_slot_table(name, columns)
return { return {
type = "flow", type = "flow",
direction = "vertical", direction = "vertical",
{ type = "label", style = "bold_label", caption = { "gui.ltnm-" .. string.gsub(name, "_", "-") } }, { type = "label", style = "bold_label", caption = { "cybersyn-gui." .. string.gsub(name, "_", "-") } },
{ {
type = "frame", type = "frame",
style = "deep_frame_in_shallow_frame", style = "deep_frame_in_shallow_frame",
@@ -43,7 +43,7 @@ function templates.inventory_slot_table(name, columns)
vertical_scroll_policy = "auto-and-reserve-space", vertical_scroll_policy = "auto-and-reserve-space",
-- vertical_scroll_policy = "always", -- vertical_scroll_policy = "always",
ref = { "inventory", name, "scroll_pane" }, ref = { "inventory", name, "scroll_pane" },
{ type = "table", style = "slot_table", column_count = columns, ref = { "inventory", name, "table" } }, { type = "table", name = "inventory_" .. name .. "_table", style = "slot_table", column_count = columns, ref = { "inventory", name, "table" } },
}, },
}, },
} }
@@ -77,7 +77,7 @@ function templates.sort_checkbox(widths, tab, column, selected, tooltip, state)
type = "checkbox", type = "checkbox",
style = selected and "ltnm_selected_sort_checkbox" or "ltnm_sort_checkbox", style = selected and "ltnm_selected_sort_checkbox" or "ltnm_sort_checkbox",
style_mods = { width = widths and widths[tab][column] or nil, horizontally_stretchable = not widths }, style_mods = { width = widths and widths[tab][column] or nil, horizontally_stretchable = not widths },
caption = { "gui.ltnm-" .. string.gsub(column, "_", "-") }, caption = { "cybersyn-gui." .. string.gsub(column, "_", "-") },
tooltip = tooltip, tooltip = tooltip,
state = state, state = state,
ref = { tab, "toolbar", column .. "_checkbox" }, ref = { tab, "toolbar", column .. "_checkbox" },

View File

@@ -12,7 +12,7 @@ local trains_tab = {}
--- @param map_data MapData --- @param map_data MapData
--- @param player_data PlayerData --- @param player_data PlayerData
--- @return GuiElemDef --- @return GuiElemDef
function trains_tab.build(map_data, player_data) function trains_tab.build(map_data, player_data, query_limit)
local widths = constants.gui["en"] local widths = constants.gui["en"]
local search_item = player_data.search_item local search_item = player_data.search_item
@@ -22,6 +22,8 @@ function trains_tab.build(map_data, player_data)
local trains_sorted = {} local trains_sorted = {}
local i = 0
for id, train in pairs(map_data.trains) do for id, train in pairs(map_data.trains) do
if search_network_name then if search_network_name then
if search_network_name ~= train.network_name then if search_network_name ~= train.network_name then
@@ -70,6 +72,10 @@ function trains_tab.build(map_data, player_data)
end end
trains_sorted[#trains_sorted + 1] = id trains_sorted[#trains_sorted + 1] = id
i = i + 1
if query_limit ~= -1 and i >= query_limit then
break
end
::continue:: ::continue::
end end
@@ -133,7 +139,7 @@ function trains_tab.build(map_data, player_data)
train_list[1] = { train_list[1] = {
type = "label", type = "label",
style = "ltnm_semibold_label", style = "ltnm_semibold_label",
caption = { "gui.ltnm-no-trains" }, caption = { "cybersyn-gui.no-trains" },
} }
else else
for idx, train_id in ipairs(trains_sorted) do for idx, train_id in ipairs(trains_sorted) do
@@ -156,7 +162,7 @@ function trains_tab.build(map_data, player_data)
{ {
type = "button", type = "button",
style = "ltnm_train_minimap_button", style = "ltnm_train_minimap_button",
tooltip = { "gui.ltnm-open-train-gui" }, tooltip = { "cybersyn-gui.open-train-gui" },
elem_mods = { entity = get_any_train_entity(train.entity) }, elem_mods = { entity = get_any_train_entity(train.entity) },
handler = trains_tab.handle.open_train_gui, --on_click handler = trains_tab.handle.open_train_gui, --on_click
tags = { train_id = train_id }, tags = { train_id = train_id },
@@ -197,7 +203,7 @@ function trains_tab.build(map_data, player_data)
tab = { tab = {
name = "trains_tab", name = "trains_tab",
type = "tab", type = "tab",
caption = #trains_sorted == 0 and { "gui.ltnm-trains" } or { "gui.ltnm-trains", #train_list }, caption = #trains_sorted == 0 and { "cybersyn-gui.trains" } or { "cybersyn-gui.trains", #train_list },
--badge_text = format.number(#ltn_data.sorted_trains.composition), --badge_text = format.number(#ltn_data.sorted_trains.composition),
handler = trains_tab.handle.change_tab, --on_click handler = trains_tab.handle.change_tab, --on_click
tags = { tab = "trains_tab" }, tags = { tab = "trains_tab" },
@@ -212,7 +218,7 @@ function trains_tab.build(map_data, player_data)
type = "frame", type = "frame",
style = "ltnm_table_toolbar_frame", style = "ltnm_table_toolbar_frame",
templates.sort_checkbox(widths, "trains", "status", false), templates.sort_checkbox(widths, "trains", "status", false),
templates.sort_checkbox(widths, "trains", "layout", false, { "gui.ltnm-composition-description" }), templates.sort_checkbox(widths, "trains", "layout", false, { "cybersyn-gui.composition-description" }),
templates.sort_checkbox(widths, "trains", "depot", false), templates.sort_checkbox(widths, "trains", "depot", false),
templates.sort_checkbox(widths, "trains", "shipment", false), templates.sort_checkbox(widths, "trains", "shipment", false),
}, },

View File

@@ -33,11 +33,35 @@ function util.gui_list(parent, iterator, test, build, update, ...)
end end
end end
--- Builds a valid sprite path or returns nil
--- @param item string
--- @return string, string, string
function util.generate_item_references(item)
local sprite = nil
local image_path = ""
local item_name = ""
if game.is_valid_sprite_path("item/" .. item) then
sprite = "item/" .. item
image_path = "[img=item." .. item .. "]"
item_name = "item-name." .. item
elseif game.is_valid_sprite_path("fluid/" .. item) then
sprite = "fluid/" .. item
image_path = "[img=fluid." .. item .. "]"
item_name = "fluid-name." .. item
elseif game.is_valid_sprite_path("virtual-signal/" .. item) then
sprite = "virtual-signal/" .. item
image_path = "[img=virtual-signal." .. item .. "]"
item_name = "virtual-signal." .. item
end
return sprite, image_path, item_name
end
--- Updates a slot table based on the passed criteria. --- Updates a slot table based on the passed criteria.
--- @param manifest Manifest --- @param manifest Manifest
--- @param color string --- @param color string
--- @return GuiElemDef[] --- @return GuiElemDef[]
function util.slot_table_build(manifest, color) function util.slot_table_build_from_manifest(manifest, color)
---@type GuiElemDef[] ---@type GuiElemDef[]
local children = {} local children = {}
for _, item in pairs(manifest) do for _, item in pairs(manifest) do
@@ -66,6 +90,125 @@ function util.slot_table_build(manifest, color)
return children return children
end end
--- @param station Station
--- @param color string
--- @return GuiElemDef[]
function util.slot_table_build_from_station(station)
---@type GuiElemDef[]
local children = {}
local comb1_signals, comb2_signals = get_signals(station)
if comb1_signals then
for _, v in pairs(comb1_signals) do
local item = v.signal
if item.type == "virtual" then
goto continue
end
local count = v.count
local name = item.name
local sprite, img_path, item_string = util.generate_item_references(name)
if sprite ~= nil then
local color
if count > 0 then
color = "green"
else
color = "red"
end
if game.is_valid_sprite_path(sprite) then
children[#children + 1] = {
type = "sprite-button",
enabled = false,
style = "ltnm_small_slot_button_" .. color,
sprite = sprite,
tooltip = {
"",
img_path,
{ item_string },
"\n"..format.number(count),
},
number = count
}
end
end
::continue::
end
end
return children
end
function util.slot_table_build_from_deliveries(station)
---@type GuiElemDef[]
local children = {}
local deliveries = station.deliveries
for item, count in pairs(deliveries) do
local sprite, img_path, item_string = util.generate_item_references(item)
if sprite ~= nil then
local color
if count > 0 then
color = "green"
else
color = "blue"
end
if game.is_valid_sprite_path(sprite) then
children[#children + 1] = {
type = "sprite-button",
enabled = false,
style = "ltnm_small_slot_button_" .. color,
sprite = sprite,
tooltip = {
"",
img_path,
{ item_string },
"\n"..format.number(count),
},
number = count
}
end
end
end
return children
end
--- @param station Station
--- @return GuiElemDef[]
function util.slot_table_build_from_control_signals(station)
---@type GuiElemDef[]
local children = {}
local comb1_signals, comb2_signals = get_signals(station)
if comb1_signals then
for _, v in pairs(comb1_signals) do
local item = v.signal
local count = v.count
local name = item.name
local sprite = ""
local color = "default"
if item.type ~= "virtual" then
goto continue
else
sprite = "virtual-signal" .. "/" .. name
end
if game.is_valid_sprite_path(sprite) then
children[#children + 1] = {
type = "sprite-button",
enabled = false,
style = "ltnm_small_slot_button_" .. color,
sprite = sprite,
tooltip = {
"",
"[img=virtual-signal." .. name .. "]",
{ "virtual-signal-name." .. name },
"\n"..format.number(count),
},
number = count
}
end
::continue::
end
end
return children
end
function util.sorted_iterator(arr, src_tbl, sort_state) function util.sorted_iterator(arr, src_tbl, sort_state)
local step = sort_state and 1 or -1 local step = sort_state and 1 or -1
local i = sort_state and 1 or #arr local i = sort_state and 1 or #arr
@@ -86,4 +229,21 @@ function util.signed_int32(val)
return (val >= MAX_INT and val - (2 * MAX_INT)) or val return (val >= MAX_INT and val - (2 * MAX_INT)) or val
end end
function util.close_manager_window(player, player_data, refs)
if player_data.pinning then
return
end
refs.manager_window.visible = false
player_data.visible = false
if player.opened == refs.manager_window then
player.opened = nil
end
player_data.is_manager_open = false
player.set_shortcut_toggled("cybersyn-toggle-gui", false)
end
return util return util

View File

@@ -835,6 +835,8 @@ local function grab_all_settings()
mod_settings.stuck_train_time = settings.global["cybersyn-stuck-train-time"].value--[[@as double]] mod_settings.stuck_train_time = settings.global["cybersyn-stuck-train-time"].value--[[@as double]]
mod_settings.allow_cargo_in_depot = settings.global["cybersyn-allow-cargo-in-depot"].value--[[@as boolean]] mod_settings.allow_cargo_in_depot = settings.global["cybersyn-allow-cargo-in-depot"].value--[[@as boolean]]
mod_settings.invert_sign = settings.global["cybersyn-invert-sign"].value--[[@as boolean]] mod_settings.invert_sign = settings.global["cybersyn-invert-sign"].value--[[@as boolean]]
mod_settings.manager_enabled = settings.startup["cybersyn-manager-enabled"].value--[[@as boolean]]
mod_settings.manager_update_rate = settings.startup["cybersyn-manager-update-rate"].value--[[@as int]]
end end
local function on_settings_changed(event) local function on_settings_changed(event)
grab_all_settings() grab_all_settings()
@@ -913,7 +915,7 @@ local function main()
end end
local MANAGER_ENABLED = true local MANAGER_ENABLED = mod_settings.manager_enabled
script.on_init(function() script.on_init(function()
local setting = settings.global["cybersyn-invert-sign"] local setting = settings.global["cybersyn-invert-sign"]
@@ -943,6 +945,10 @@ local function main()
script.on_event(defines.events.on_player_removed, manager.on_player_removed) script.on_event(defines.events.on_player_removed, manager.on_player_removed)
script.on_event(defines.events.on_player_created, manager.on_player_created) script.on_event(defines.events.on_player_created, manager.on_player_created)
script.on_event(defines.events.on_lua_shortcut, manager.on_lua_shortcut) script.on_event(defines.events.on_lua_shortcut, manager.on_lua_shortcut)
-- TODO: rework this to work as a per-player runtime setting
script.on_nth_tick(mod_settings.manager_update_rate, function()
manager.tick(global)
end)
end end
end end

View File

@@ -243,6 +243,7 @@ function interface.update_stop_from_rail(rail, forbidden_entity, force_update)
update_stop_from_rail(global, rail, forbidden_entity, force_update) update_stop_from_rail(global, rail, forbidden_entity, force_update)
end end
------------------------------------------------------------------ ------------------------------------------------------------------
--[[unsafe API]] --[[unsafe API]]
------------------------------------------------------------------ ------------------------------------------------------------------

View File

@@ -102,6 +102,31 @@ data:extend({
setting_type = "runtime-global", setting_type = "runtime-global",
default_value = false, default_value = false,
}, },
{
type = "int-setting",
name = "cybersyn-manager-update-rate",
order = "ad",
setting_type = "startup",
default_value = 60,
minimum_value = 1,
maximum_value = 2147483647,
},
{
type = "bool-setting",
name = "cybersyn-manager-enabled",
order = "aa",
setting_type = "startup",
default_value = true,
},
{
type = "int-setting",
name = "cybersyn-manager-result-limit",
order = "aa",
setting_type = "runtime-per-user",
default_value = -1,
minimum_value = -1,
maximum_value = 2147483647,
}
--{ --{
-- type = "bool-setting", -- type = "bool-setting",
-- name = "cybersyn-disable-top-left-button", -- name = "cybersyn-disable-top-left-button",