From 48b7f6171cbb0fdfff21d5b1605e391894c4c831 Mon Sep 17 00:00:00 2001 From: luaotix <94216417+luaotix@users.noreply.github.com> Date: Mon, 5 Jun 2023 13:58:46 +0800 Subject: [PATCH 01/29] Update base.cfg --- cybersyn/locale/zh-CN/base.cfg | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cybersyn/locale/zh-CN/base.cfg b/cybersyn/locale/zh-CN/base.cfg index c64ecc7..9d4a533 100644 --- a/cybersyn/locale/zh-CN/base.cfg +++ b/cybersyn/locale/zh-CN/base.cfg @@ -14,7 +14,7 @@ cybersyn-locked-slots=默认每车厢锁定格数 cybersyn-network-flag=默认网络掩码 cybersyn-fuel-threshold=燃料阈值 cybersyn-depot-bypass-enabled=启用车库绕行 -cybersyn-warmup-time=车站预热时间(秒) +cybersyn-warmup-time=车站预备时间(秒) cybersyn-stuck-train-time=列车卡住超时(秒) cybersyn-allow-cargo-in-depot=允许车库中存放货物 cybersyn-invert-sign=反转运算器输出(已弃用) @@ -34,7 +34,7 @@ cybersyn-fuel-threshold=列车的燃料库存必须达到多少百分比才能 cybersyn-depot-bypass-enabled=若选中,则当列车完成交付和加油后,可以在返回其车库之前从网络中接受新订单。 cybersyn-warmup-time=协同控制运算器在连接到Cybersyn网络之前要等待多少秒。这是一个宽限期,便于在列车开始调度到一个新站台前,修改或纠正信号网络。 cybersyn-stuck-train-time=在列车派遣后的这么多秒后,将发送警报,以让您知道列车可能卡住了,并且无完成交付。玩家可能需要调试其网络以使列车脱困。 -cybersyn-allow-cargo-in-depot=若选中,则允许列车在车库中装载货物。不会生成任何警报,列车也不会被拦住。此外,具有访问请求站点并勾选了“非活动状态”的订单的列车将等待非活动状态,而不是等待空货物。对于创建由车库处理多余货物的列车系统非常有用。仅适用于高水准玩家。 +cybersyn-allow-cargo-in-depot=若选中,则允许列车在车库中装载货物。不会生成任何警报,列车也不会被拦住。此外,具有访问请求站点并勾选了“静止状态”的订单的列车将等待静止状态,而非等待清空货物。这对于创建由车库处理多余货物的列车系统非常有用。仅适用于高水准玩家。 cybersyn-invert-sign=翻转协同控制运算器输出的信号,使其与LTN或Project Cybersyn早期版本中的信号相同。 cybersyn-manager-enabled=允许查看连接到Cybersyn的所有列车和车站。此管理器界面目前正处于开发中,可能会导致多次崩溃。 cybersyn-manager-updates-per-second=控制Cybersyn管理器界面刷新的频率。必须将Cybersyn管理器设置为启用才能生效。 @@ -57,7 +57,7 @@ cybersyn-combinator=有5种不同的模式。但您仅需站台和车库模式 cybersyn-train-network=Cybersyn 列车协同控制网络 [technology-description] -cybersyn-train-network=站台控制器能够协调整体的输入和输出。 +cybersyn-train-network=一款列车站台控制器,能够统筹全局运输的物流调度。 [virtual-signal-name] cybersyn-priority=站台优先级 @@ -148,9 +148,9 @@ cybersyn-toggle-gui=切换Cybersyn管理器 [cybersyn-message] error-cybernetic-combinator-not-found=找不到该车站的协同控制运算器。 error-station-control-combinator-not-found=找不到该车站的协同控制运算器。 -error-station-is-invalid=车站无效,请刷新管理器界面。 -error-train-is-invalid=列车无效,请刷新管理器界面。 -error-cross-surface-camera-invalid=无法将相机移动到不同表面上的实体上! +error-station-is-invalid=车站无效,请刷新管理器。 +error-train-is-invalid=列车无效,请刷新管理器。 +error-cross-surface-camera-invalid=无法将视角移动至不同表面上的实体上! [cybersyn-mod-setting-description] iterations-per-tick=若您遇到性能问题,降低本数值。 @@ -160,4 +160,4 @@ history-length=历史记录长度 iterations-per-tick=每tick的迭代次数[img=info] [shortcut-name] -cybersyn-toggle-gui=切换Cybersyn管理器 +cybersyn-toggle-gui=Cybersyn管理器 From 756d2036744da4c0867fcfd13419afb1c2505460 Mon Sep 17 00:00:00 2001 From: Mjonir Date: Tue, 6 Jun 2023 15:56:20 +0200 Subject: [PATCH 02/29] Add files via upload --- cybersyn/scripts/gui/main.lua | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/cybersyn/scripts/gui/main.lua b/cybersyn/scripts/gui/main.lua index 7628c42..f7de53c 100644 --- a/cybersyn/scripts/gui/main.lua +++ b/cybersyn/scripts/gui/main.lua @@ -60,9 +60,10 @@ end -function manager_gui.on_player_created(e) - local player = game.get_player(e.player_index) +local function create_player(player_index) + local player = game.get_player(player_index) if not player then return end + local player_data = { search_network_mask = -1, trains_orderings = {}, @@ -71,12 +72,16 @@ function manager_gui.on_player_created(e) refs = manager.create(player), selected_tab = "stations_tab", } - global.manager.players[e.player_index] = player_data + global.manager.players[player_index] = player_data --manager.update(global, player, player_data) --top_left_button_update(player, player_data) end +function manager_gui.on_player_created(e) + create_player(player_index) +end + function manager_gui.on_player_removed(e) global.manager.players[e.player_index] = nil end @@ -147,9 +152,16 @@ end function manager_gui.on_migration() + for i, p in pairs(game.players) do + if global.manager.players[player_index] == nil then + create_player(i) + end + end + for i, v in pairs(global.manager.players) do manager_gui.reset_player(i, v) end + init_items(global.manager) end From b7bdc86527f1e51edc71b3e01e3286a0f9aa607c Mon Sep 17 00:00:00 2001 From: Mjonir Date: Tue, 6 Jun 2023 17:53:40 +0200 Subject: [PATCH 03/29] Fix: getting player_index from the proper places --- cybersyn/scripts/gui/main.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cybersyn/scripts/gui/main.lua b/cybersyn/scripts/gui/main.lua index f7de53c..d6bae48 100644 --- a/cybersyn/scripts/gui/main.lua +++ b/cybersyn/scripts/gui/main.lua @@ -79,7 +79,7 @@ local function create_player(player_index) end function manager_gui.on_player_created(e) - create_player(player_index) + create_player(e.player_index) end function manager_gui.on_player_removed(e) @@ -153,7 +153,7 @@ end function manager_gui.on_migration() for i, p in pairs(game.players) do - if global.manager.players[player_index] == nil then + if global.manager.players[i] == nil then create_player(i) end end From 10c152fe05f23b529d8b01002d53397bbd89f0cc Mon Sep 17 00:00:00 2001 From: svr8450 <108701516+svr8450@users.noreply.github.com> Date: Sun, 11 Jun 2023 17:52:13 -0400 Subject: [PATCH 04/29] fix empty manifest by using lesser threshold --- cybersyn/scripts/central-planning.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cybersyn/scripts/central-planning.lua b/cybersyn/scripts/central-planning.lua index 9428d4d..55fee92 100644 --- a/cybersyn/scripts/central-planning.lua +++ b/cybersyn/scripts/central-planning.lua @@ -157,11 +157,17 @@ function create_manifest(map_data, r_station_id, p_station_id, train_id, primary end local p_effective_item_count = p_station.item_p_counts[item_name] --could be an item that is not present at the station + local effective_threshold local override_threshold = p_station.item_thresholds and p_station.item_thresholds[item_name] if override_threshold and p_station.is_stack and item_type == "item" then override_threshold = override_threshold*get_stack_size(map_data, item_name) end - if p_effective_item_count and p_effective_item_count >= (override_threshold or r_threshold) then + if override_threshold and override_threshold <= r_threshold then + effective_threshold = override_threshold + else + effective_threshold = r_threshold + end + if p_effective_item_count and p_effective_item_count >= effective_threshold then local item = {name = item_name, type = item_type, count = min(-r_effective_item_count, p_effective_item_count)} if item_name == primary_item_name then manifest[#manifest + 1] = manifest[1] From 7e5504d680c5da254163d0df7dfe6e4d8e719949 Mon Sep 17 00:00:00 2001 From: Erin Dachtler Date: Thu, 22 Jun 2023 03:32:31 -0700 Subject: [PATCH 05/29] fix for #98 --- cybersyn/scripts/gui.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cybersyn/scripts/gui.lua b/cybersyn/scripts/gui.lua index 6265a07..c70896a 100644 --- a/cybersyn/scripts/gui.lua +++ b/cybersyn/scripts/gui.lua @@ -92,7 +92,7 @@ local function handle_drop_down(e) --prevent the use of the each signal with depots local network = element.parent.parent.bottom.network--[[@as LuaGuiElement]] local signal = network.elem_value--[[@as SignalID]] - if signal.name == NETWORK_EACH then + if signal and (signal.name == NETWORK_EACH) then network.elem_value = nil set_comb_network_name(comb, nil) end From bfb417d0f5d666fcdd72306f19c6db844f01e346 Mon Sep 17 00:00:00 2001 From: Patrick Wrobel Date: Fri, 23 Jun 2023 00:53:01 -0400 Subject: [PATCH 06/29] Issue 104: Don't crash when clicking on combinator when the GUI is open --- cybersyn/scripts/gui.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cybersyn/scripts/gui.lua b/cybersyn/scripts/gui.lua index 6265a07..1dd1528 100644 --- a/cybersyn/scripts/gui.lua +++ b/cybersyn/scripts/gui.lua @@ -201,6 +201,9 @@ function gui_opened(comb, player) combinator_update(global, comb, true) local rootgui = player.gui.screen + if rootgui[COMBINATOR_NAME] then + rootgui[COMBINATOR_NAME].destroy() + end local selected_index, signal, switch_state, bits = get_comb_gui_settings(comb) local _, main_window = flib_gui.add(rootgui, { From 204ec6391bea4182bdfa2526f01e20a82d8ee315 Mon Sep 17 00:00:00 2001 From: Patrick Wrobel Date: Fri, 23 Jun 2023 02:07:16 -0400 Subject: [PATCH 07/29] Fix escape and E not closing the combinator GUI when the manager is enabled --- cybersyn/scripts/gui.lua | 3 --- cybersyn/scripts/gui/main.lua | 9 +++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cybersyn/scripts/gui.lua b/cybersyn/scripts/gui.lua index 1dd1528..6265a07 100644 --- a/cybersyn/scripts/gui.lua +++ b/cybersyn/scripts/gui.lua @@ -201,9 +201,6 @@ function gui_opened(comb, player) combinator_update(global, comb, true) local rootgui = player.gui.screen - if rootgui[COMBINATOR_NAME] then - rootgui[COMBINATOR_NAME].destroy() - end local selected_index, signal, switch_state, bits = get_comb_gui_settings(comb) local _, main_window = flib_gui.add(rootgui, { diff --git a/cybersyn/scripts/gui/main.lua b/cybersyn/scripts/gui/main.lua index 7628c42..d5030db 100644 --- a/cybersyn/scripts/gui/main.lua +++ b/cybersyn/scripts/gui/main.lua @@ -51,6 +51,15 @@ function manager_gui.on_lua_shortcut(e) if e.element then if e.element.name == "manager_window" then manager.wrapper(e, manager.handle.manager_toggle) + elseif e.element.name == COMBINATOR_NAME and e.name == defines.events.on_gui_closed then + -- With the manager enabled, this handler overwrites the combinator's + -- on_gui_close handler. Copy the logic to close the combinator's GUI here + -- as well. + local player = game.get_player(e.player_index) + if not player then return end + if player.gui.screen[COMBINATOR_NAME] then + player.gui.screen[COMBINATOR_NAME].destroy() + end end else manager.wrapper(e, manager.handle.manager_toggle) From 3df1e76715307c6447385767ee05cbb7b5ca2319 Mon Sep 17 00:00:00 2001 From: Gillett Hernandez Date: Tue, 4 Jul 2023 17:26:29 -0700 Subject: [PATCH 08/29] fix issue 106 and bump version --- cybersyn/info.json | 2 +- cybersyn/scripts/layout.lua | 102 ++++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 40 deletions(-) diff --git a/cybersyn/info.json b/cybersyn/info.json index 739a874..7b31b65 100644 --- a/cybersyn/info.json +++ b/cybersyn/info.json @@ -1,6 +1,6 @@ { "name": "cybersyn", - "version": "1.2.16", + "version": "1.2.17", "title": "Project Cybersyn", "author": "Mami", "factorio_version": "1.1", diff --git a/cybersyn/scripts/layout.lua b/cybersyn/scripts/layout.lua index 46b82b1..0b83b70 100644 --- a/cybersyn/scripts/layout.lua +++ b/cybersyn/scripts/layout.lua @@ -9,7 +9,7 @@ local bit_extract = bit32.extract local defines_front = defines.rail_direction.front local defines_back = defines.rail_direction.back local defines_straight = defines.rail_connection_direction.straight -local search_type = {"straight-rail", "curved-rail"} +local search_type = { "straight-rail", "curved-rail" } ---@param layout_pattern (0|1|2|3)[] @@ -33,6 +33,7 @@ function is_refuel_layout_accepted(layout_pattern, layout) end return valid end + ---@param layout_pattern (0|1|2|3)[] ---@param layout (0|1|2)[] function is_layout_accepted(layout_pattern, layout) @@ -83,7 +84,6 @@ function remove_train(map_data, train_id, train) interface_raise_train_removed(train_id, train) end - ---@param map_data MapData ---@param train Train function set_train_layout(map_data, train) @@ -166,7 +166,7 @@ end function set_p_wagon_combs(map_data, station, train) if not station.wagon_combs or not next(station.wagon_combs) then return end local carriages = train.entity.carriages - local manifest = train.manifest--[[@as Manifest]] + local manifest = train.manifest --[[@as Manifest]] if not manifest[1] then return end local sign = mod_settings.invert_sign and 1 or -1 @@ -178,7 +178,7 @@ function set_p_wagon_combs(map_data, station, train) local total_item_slots if locked_slots > 0 then local total_cargo_wagons = #train.entity.cargo_wagons - total_item_slots = max(train.item_slot_capacity - total_cargo_wagons*locked_slots, 1) + total_item_slots = max(train.item_slot_capacity - total_cargo_wagons * locked_slots, 1) else total_item_slots = train.item_slot_capacity end @@ -186,10 +186,10 @@ function set_p_wagon_combs(map_data, station, train) local to_be_used_item_slots = 0 for i, item in ipairs(train.manifest) do if item.type == "item" then - to_be_used_item_slots = to_be_used_item_slots + ceil(item.count/get_stack_size(map_data, item.name)) + to_be_used_item_slots = to_be_used_item_slots + ceil(item.count / get_stack_size(map_data, item.name)) end end - percent_slots_to_use_per_wagon = min(to_be_used_item_slots/total_item_slots, 1.0) + percent_slots_to_use_per_wagon = min(to_be_used_item_slots / total_item_slots, 1.0) end local item_i = 1 @@ -219,16 +219,20 @@ function set_p_wagon_combs(map_data, station, train) local signals = {} local inv_filter_i = 1 - local item_slots_capacity = max(ceil((#inv - locked_slots)*percent_slots_to_use_per_wagon), 1) + local item_slots_capacity = max(ceil((#inv - locked_slots) * percent_slots_to_use_per_wagon), 1) while item_slots_capacity > 0 and item_i <= #manifest do local do_inc if item.type == "item" then local stack_size = get_stack_size(map_data, item.name) local i = #signals + 1 - local count_to_fill = min(item_slots_capacity*stack_size, item_count) - local slots_to_fill = ceil(count_to_fill/stack_size) + local count_to_fill = min(item_slots_capacity * stack_size, item_count) + local slots_to_fill = ceil(count_to_fill / stack_size) - signals[i] = {index = i, signal = {type = item.type, name = item.name}, count = sign*count_to_fill} + signals[i] = { + index = i, + signal = { type = item.type, name = item.name }, + count = sign * count_to_fill + } item_count = item_count - count_to_fill item_slots_capacity = item_slots_capacity - slots_to_fill if comb then @@ -255,7 +259,7 @@ function set_p_wagon_combs(map_data, station, train) if comb then if bit_extract(get_comb_params(comb).second_constant, SETTING_ENABLE_SLOT_BARRING) > 0 then - inv.set_bar(inv_filter_i--[[@as uint]]) + inv.set_bar(inv_filter_i --[[@as uint]]) train.has_filtered_wagon = true end set_combinator_output(map_data, comb, signals) @@ -270,7 +274,11 @@ function set_p_wagon_combs(map_data, station, train) if fluid.type == "fluid" then local count_to_fill = min(fluid_count, fluid_capacity) - signals[1] = {index = 1, signal = {type = fluid.type, name = fluid.name}, count = sign*count_to_fill} + signals[1] = { + index = 1, + signal = { type = fluid.type, name = fluid.name }, + count = sign * count_to_fill + } fluid_count = fluid_count - count_to_fill fluid_capacity = 0 do_inc = fluid_count == 0 @@ -323,7 +331,12 @@ function set_r_wagon_combs(map_data, station, train) local stack = inv[stack_i] if stack.valid_for_read then local i = #signals + 1 - signals[i] = {index = i, signal = {type = "item", name = stack.name}, count = sign*stack.count} + signals[i] = { + index = i, + signal = { type = "item", name = stack.name }, + count = sign * + stack.count + } end end set_combinator_output(map_data, comb, signals) @@ -334,14 +347,13 @@ function set_r_wagon_combs(map_data, station, train) local inv = carriage.get_fluid_contents() for fluid_name, count in pairs(inv) do local i = #signals + 1 - signals[i] = {index = i, signal = {type = "fluid", name = fluid_name}, count = sign*floor(count)} + signals[i] = { index = i, signal = { type = "fluid", name = fluid_name }, count = sign * floor(count) } end set_combinator_output(map_data, comb, signals) end end end - ---@param map_data MapData ---@param refueler Refueler ---@param train Train @@ -379,7 +391,7 @@ function set_refueler_combs(map_data, refueler, train) name = a.name end if game.item_prototypes[name] then - wagon_signals[1] = {index = 1, signal = {type = "item", name = a.name}, count = 1} + wagon_signals[1] = { index = 1, signal = { type = "item", name = a.name }, count = 1 } end end end @@ -388,10 +400,14 @@ function set_refueler_combs(map_data, refueler, train) if stack.valid_for_read then if comb then local i = #wagon_signals + 1 - wagon_signals[i] = {index = i, signal = {type = "item", name = stack.name}, count = stack.count} + wagon_signals[i] = { + index = i, + signal = { type = "item", name = stack.name }, + count = stack.count + } end local j = #signals + 1 - signals[j] = {index = j, signal = {type = "item", name = stack.name}, count = stack.count} + signals[j] = { index = j, signal = { type = "item", name = stack.name }, count = stack.count } end end if comb then @@ -403,7 +419,6 @@ function set_refueler_combs(map_data, refueler, train) set_combinator_output(map_data, refueler.entity_comb, signals) end - ---@param map_data MapData ---@param stop Station|Refueler function unset_wagon_combs(map_data, stop) @@ -421,7 +436,7 @@ function unset_wagon_combs(map_data, stop) end end -local type_filter = {"inserter", "pump", "arithmetic-combinator", "loader-1x1"} +local type_filter = { "inserter", "pump", "arithmetic-combinator", "loader-1x1", "loader" } ---@param map_data MapData ---@param stop Station|Refueler ---@param is_station_or_refueler boolean @@ -450,20 +465,20 @@ function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_ent local area_delta local is_ver if stop_direction == defines.direction.north then - search_area = {{middle_x - reach, middle_y}, {middle_x + reach, middle_y + 6}} - area_delta = {0, 7} + search_area = { { middle_x - reach, middle_y }, { middle_x + reach, middle_y + 6 } } + area_delta = { 0, 7 } is_ver = true elseif stop_direction == defines.direction.east then - search_area = {{middle_x - 6, middle_y - reach}, {middle_x, middle_y + reach}} - area_delta = {-7, 0} + search_area = { { middle_x - 6, middle_y - reach }, { middle_x, middle_y + reach } } + area_delta = { -7, 0 } is_ver = false elseif stop_direction == defines.direction.south then - search_area = {{middle_x - reach, middle_y - 6}, {middle_x + reach, middle_y}} - area_delta = {0, -7} + search_area = { { middle_x - reach, middle_y - 6 }, { middle_x + reach, middle_y } } + area_delta = { 0, -7 } is_ver = true elseif stop_direction == defines.direction.west then - search_area = {{middle_x, middle_y - reach}, {middle_x + 6, middle_y + reach}} - area_delta = {7, 0} + search_area = { { middle_x, middle_y - reach }, { middle_x + 6, middle_y + reach } } + area_delta = { 7, 0 } is_ver = false else assert(false, "cybersyn: invalid stop direction") @@ -471,11 +486,12 @@ function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_ent local length = 1 ---@type LuaEntity? local pre_rail = stop_rail - local layout_pattern = {0} + local layout_pattern = { 0 } local wagon_number = 0 for i = 1, 112 do if pre_rail then - local rail, rail_direction, rail_connection_direction = pre_rail.get_connected_rail({rail_direction = rail_direction_from_stop, rail_connection_direction = defines_straight}) + local rail, rail_direction, rail_connection_direction = pre_rail.get_connected_rail({ + rail_direction = rail_direction_from_stop, rail_connection_direction = defines_straight }) if not rail or rail_connection_direction ~= defines_straight then -- There is a curved rail or break in the tracks at this point -- We are assuming it's a curved rail, maybe that's a bad assumption @@ -543,7 +559,7 @@ function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_ent end end end - elseif entity.type == "loader-1x1" then + elseif entity.type == "loader-1x1" or entity.type == "loader" then if not supports_cargo then local direction = entity.direction if is_ver then @@ -627,7 +643,7 @@ end ---@param forbidden_entity LuaEntity? ---@param force boolean? local function resolve_update_stop_from_rail(map_data, entity, forbidden_entity, force) - local id = entity.unit_number--[[@as uint]] + local id = entity.unit_number --[[@as uint]] local is_station = true ---@type Station|Refueler local stop = map_data.stations[id] @@ -661,7 +677,10 @@ function update_stop_from_rail(map_data, rail, forbidden_entity, force) resolve_update_stop_from_rail(map_data, entity, forbidden_entity, force) return end - rail_back = rail_back.get_connected_rail({rail_direction = defines_back, rail_connection_direction = defines_straight}) + rail_back = rail_back.get_connected_rail({ + rail_direction = defines_back, + rail_connection_direction = defines_straight + }) end if rail_front then local entity = rail_front.get_rail_segment_entity(defines_front, false) @@ -669,7 +688,10 @@ function update_stop_from_rail(map_data, rail, forbidden_entity, force) resolve_update_stop_from_rail(map_data, entity, forbidden_entity, force) return end - rail_front = rail_front.get_connected_rail({rail_direction = defines_front, rail_connection_direction = defines_straight}) + rail_front = rail_front.get_connected_rail({ + rail_direction = defines_front, + rail_connection_direction = defines_straight + }) end end end @@ -682,6 +704,7 @@ function update_stop_from_pump(map_data, pump, forbidden_entity) update_stop_from_rail(map_data, pump.pump_rail_target, forbidden_entity) end end + ---@param map_data MapData ---@param inserter LuaEntity ---@param forbidden_entity LuaEntity? @@ -713,10 +736,10 @@ function update_stop_from_inserter(map_data, inserter, forbidden_entity) end -- We need to check secondary positions because of weird modded inserters. -- Mostly because of miniloaders not aligning with the hitbox of a rail by default. - pos1.x = pos1.x + 0.2*(pos1.x - pos0.x) - pos1.y = pos1.y + 0.2*(pos1.y - pos0.y) - pos2.x = pos2.x + 0.2*(pos2.x - pos0.x) - pos2.y = pos2.y + 0.2*(pos2.y - pos0.y) + pos1.x = pos1.x + 0.2 * (pos1.x - pos0.x) + pos1.y = pos1.y + 0.2 * (pos1.y - pos0.y) + pos2.x = pos2.x + 0.2 * (pos2.x - pos0.x) + pos2.y = pos2.y + 0.2 * (pos2.y - pos0.y) rails = surface.find_entities_filtered({ type = search_type, position = pos1, @@ -732,6 +755,7 @@ function update_stop_from_inserter(map_data, inserter, forbidden_entity) update_stop_from_rail(map_data, rails[1], forbidden_entity) end end + ---@param map_data MapData ---@param loader LuaEntity ---@param forbidden_entity LuaEntity? @@ -741,7 +765,7 @@ function update_stop_from_loader(map_data, loader, forbidden_entity) local loader_type = loader.loader_type local position = loader.position --check input/output direction and loader position, and case position and modify x or y by +/- 1 for search - if loader_type == "input" then --loading train + if loader_type == "input" then --loading train if direction == defines.direction.east then position.x = position.x + 1 -- input and facing east -> move on X axis 1 to the right elseif direction == defines.direction.south then From d5cc48736805cc3a6652f52a7f3fe8849c559735 Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Fri, 31 Mar 2023 16:52:00 +0200 Subject: [PATCH 09/29] Add Swedish translations --- cybersyn/locale/sv-SE/base.cfg | 103 ++++++++++++++++++++++++++++++ cybersyn/locale/sv-SE/manager.cfg | 57 +++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 cybersyn/locale/sv-SE/base.cfg create mode 100644 cybersyn/locale/sv-SE/manager.cfg diff --git a/cybersyn/locale/sv-SE/base.cfg b/cybersyn/locale/sv-SE/base.cfg new file mode 100644 index 0000000..9ad191e --- /dev/null +++ b/cybersyn/locale/sv-SE/base.cfg @@ -0,0 +1,103 @@ +[mod-description] +cybersyn=Använder cybernetiska kombinatorer för att skapa funktionsfyllda tågnätverk för logistik. Du kan koordinera de ekonomiska in- och utflödena för hela din megabas med bara den här modden. + +[mod-setting-name] +cybersyn-enable-planner=Aktivera centralplanering +cybersyn-ticks-per-second=Centralplaneringsuppdateringar per sekund +cybersyn-update-rate=Centralplaneringuppdateringsfrekvens +cybersyn-request-threshold=Standardbeställningströskel +cybersyn-priority=Standardprioritet +cybersyn-locked-slots=Standardvärde för låsta platser per lastvagn +cybersyn-network-flag=Standardnätverksmask +cybersyn-fuel-threshold=Bränsletröskel +cybersyn-depot-bypass-enabled=Hoppa över depåer +cybersyn-warmup-time=Stationsuppvärmningstid (sek) +cybersyn-stuck-train-time=Timeout för tåg som fastnat (sek) +cybersyn-allow-cargo-in-depot=Tillåt last i depåer +cybersyn-invert-sign=Invertera kombinatorers utsignaler (förlegad) +cybersyn-manager-enabled=Aktivera Cybersyn-GUI:t +cybersyn-manager-update-rate=Uppdateringsfrekvens för hanteraren +cybersyn-manager-result-limit=Max antal entiteter som visas på GUI-sidor. + +[mod-setting-description] +cybersyn-enable-planner=Aktivera eller avaktivera centralplaneringsalgoritmen. När den är avstängd kommer ingen nya tåg att skickas iväg. +cybersyn-ticks-per-second=Antal gånger per sekund som centralplaneraren ska uppdatera nätverksstatusen och planera leveranser. Värdet rundas upp till en divisor 60. Om satt till 0 stoppas alla avsändningar. +cybersyn-update-rate=Antal stationer per tick som uppdateras eller får leveranser planerade åt gången. Större nummer låter centralplaneraren hålla sig uppdaterade gentemot nätverkets status, men kräver mer prestanda. +cybersyn-request-threshold=Standardvärde för förfrågningströskeln när en specifik tröskelsignal inte ges till en station. När en station tar emot en negativ varusignal som är större än förfrågningströskeln, förutsatt att det finns en annan station med en positiv signal som är större än tröskeln, planeras en leverans av varan mellan de två stationerna. +cybersyn-priority=Standardvärde för prioritet när en prioritetssignal inte ges till en station, depå, eller bränslestation. Stationer med högre prioritet tar emot leveranser innan stationer med lägre prioritet. +cybersyn-locked-slots=Standardvärde för antal låsta platser per lastvagn när en signal för "låsta platser per lastvagn" inte ges till stationen. När en leverantörsstation har ett värde X för "låsta platser per lastvagn", leder det till att tåg som utför leveranser från den stationen får sin order justerad så att varje lastvagn har åtminstone X platser som lämnas tomma. Detta är nödvändigt för att möjliggöra leverantörsstationer som kan leverera fler än en typ av vara. +cybersyn-network-flag=Standardvärde för nätverksmasken (en samling subnätverk) en station konfigureras med om ingen signal för nätverksmask ges till den. Heltalet tolkas bitvis för 32 möjliga subnätverk att välja mellan. +cybersyn-fuel-threshold=Andelen av ett tågs bränsleinnehåll som måste vara fylld för att tåget ska hoppa över bränslestationer. När värdet är 1 kommer tåg alltid att besöka en bränslestation efter varje utförd leverans. +cybersyn-depot-bypass-enabled=Med den här inställningen aktiverad kan tåg, efter att de slutfört sin leverans och eventuell påfyllning av bränsle, få en ny order från nätverket utan att först återvänta till sin depå. +cybersyn-warmup-time=Antal sekunder som en Cybernetisk kombinatorer väntar innan den ansluter till Cybersyn-nätverket. Det här tillåter tid för ändringar eller korrigeringar till kretsnätverket innan tåg börjar skickas till en nyligen byggd station. +cybersyn-stuck-train-time=Antal sekunder räknat från ett tågs avsändningstid som en varning skickas för att meddela att ett tåg antagligen fastnat och inte har slutfört sin leverans. Spelaren kommer antagligen behöva felsöka sitt nätverk för att få loss tåget. +cybersyn-allow-cargo-in-depot=Tillåter att tåg anländer till en depå med last kvar i sina vagnar. Inga varningar kommer skapas och tåget hålls inte kvar i depån. Dessutom, för tåg med en order att besöka en beställarstation som har "Inaktivetetsvillkor" ikryssat, kommer de att vänta på inaktivetet istället för tom last. Användbart för att skapa tågsystem där depåer hanterar överflödig last. Endast för avancerade användare. +cybersyn-invert-sign=Invertera (ändra positivt till negativt och vice versa) utsignalen från Cybernetiska kombinatorer till att vara som de är i LTN eller tidigare versioner av Projekt Cybersyn. +cybersyn-manager-enabled=Ger en översikt över alla tåg och stationer som är anslutna till Cybersyn-nätverket. Gränssnittet är under utveckling och kan leda till många krascher. +cybersyn-manager-updates-per-second=Ställer in hur ofta gränssnittet för Cybersyn-hanteraren uppdateras. Cybersyn-hanteraren måste vara aktiverad för att den här inställningen ska ha någon effekt. +cybersyn-manager-result-limit=Sätter en gräns på antalet matchande entiteter (t.ex. stationer, tåg) för att begränsa tiden det tar att uppdatera när listan uppdateras.\nSätt till -1 för att visa allt. + +[item-name] +cybersyn-combinator=__ENTITY__cybersyn-combinator__ + +[item-description] +cybersyn-combinator=Placera vid en tågstation för att lägga till den till Cybersyn-tågnätverket. Stationen kan nu beställa eller leverera varor som skickas in till kombinatorn via signaler i kretsnätverket. + +[entity-name] +cybersyn-combinator=Cybernetisk kombinator +cybersyn-combinator-output=Cybernetisk kombinator-utsignaler + +[entity-description] +cybersyn-combinator=Har 5 olika lägen. Det behövs bara stationsläge och depåläge för att komma igång. + +[technology-name] +cybersyn-train-network=Cybersyn tågnätverk + +[technology-description] +cybersyn-train-network=Tågstationsenheter som kan koordinera in- och utflöden för en hel ekonomi. + +[virtual-signal-name] +cybersyn-priority=Stationsprioritet +cybersyn-request-threshold=Beställningströskel +cybersyn-locked-slots=Låsta platser per lastvagn + +[cybersyn-messages] +nonempty-train=Ett tåg hålls kvar i depån eftersom det fortfarande innehåller last +unexpected-train=Ett tåg har oväntat återvänt till depån utan att slutföra sin leverans +stuck-train=Ett tåg har fastnat +cannot-path-between-surfaces=Ett tåg försöker leverera mellan två olika ytor som inte är sammankopplade. Testa att använda separata nätverk för ytorna. +depot-broken=Ett tåg är vilse för att dess depå försvann +refueler-broken=Ett tåg är vilse för att dess bränslestation försvann +station-broken=Ett tåg är vilse för att en av dess leveransstationer försvann +train-at-incorrect=Ett tåg är parkerat vid en station den inte var planerad att leverera till +missing-train=Kunde inte hitta något tåg på rätt nätverk för att utföra leverans från __2__ till __1__ +no-train-has-capacity=Kunde inte hitta något tåg med tillräcklig kapacitet för att utföra leverans från __2__ till __1__ +no-train-matches-r-layout=Kunde inte hitta något tåg på listan av tillåtna tåg för __1__ för att utföra en leverans +no-train-matches-p-layout=Kunde inte hitta något tåg på listan av tillåtna tåg för __2__ för att leverera till __1__ + +[cybersyn-gui] +combinator-title=__ENTITY__cybersyn-combinator__ +operation=Läge +comb1=Station +depot=Depå +refueler=Bränslestation +comb2=Stationskontroll +wagon-manifest=Vagnkontroll +switch-provide=Leverantör +switch-request=Beställare +switch-provide-tooltip=Lås den här stationen till att endast leverera varor till nätverket. I ospecificerat läge kan den både leverera och beställa. +switch-request-tooltip=Lås den här stationen till att endast beställa varor från nätverket. I ospecificerat läge kan den både beställa och leverera. +network=Nätverk +network-tooltip=En signal som används för att identifiera vilket nätverk den här kombinatorn tillhör. Tåg skickas endast endast från depåer till leverantörer och beställare om de alla delar samma signal. +allow-list-description=Automatiskt tillåtna tåg +allow-list-tooltip=Om aktiverad kommer den här stationen automatiskt tillåta tåg att använda den om alla vagnar på tåget kan lastas på eller av vid den. Annars används ingen automatisk logik och alla tåg kan använda staionen oavsett. +is-stack-description=Stapeltrösklar +is-stack-tooltip=Alla beställningströsklar för den här stationen tolkas som ett antal staplar istället för styckantal. Trösklar för vätskor påverkas inte. +enable-inactive-description=Inaktivitetsvillkor +enable-inactive-tooltip=Om aktiverad krävs det att tåg vid en leverantör väntar på inaktivitet innan det lämnar, även om ordern redan har fyllts. Detta är främst användbart för att förhindra att lastkranar fastnar med saker i sina händer. +use-same-depot-description=Använd samma depå +use-same-depot-tooltip=Om aktiverad kommer tåg som lämnar från den här depån alltid att återvända till samma station. Annars är tåget tillåtet att återvända till en annan depåstation med samma namn som den här. +depot-bypass-description=Hoppa över depå +depot-bypass-tooltip=Tåg från den här depån kan få nya ordrar utan att först parkera vid depån, om de inte har en pågående order. De kommer fortfarande att återvända till depån om de har låg bränslenivå och det inte finns några bränslestationer tillgängliga på nätverket. +enable-slot-barring-description=Blockera ofiltrerade platser +enable-slot-barring-tooltip=Platser i intilliggande vagn som inte har filter blockeras istället så att varor inte kan lastas i dem. diff --git a/cybersyn/locale/sv-SE/manager.cfg b/cybersyn/locale/sv-SE/manager.cfg new file mode 100644 index 0000000..e711496 --- /dev/null +++ b/cybersyn/locale/sv-SE/manager.cfg @@ -0,0 +1,57 @@ +[mod-name] +cybersyn=Projekt Cybersyn + +[controls] +cybersyn-toggle-gui=Visa/dölj Cybersyn-hanteraren + +[cybersyn-gui] +alerts=Larm +all-paren=(Alla) +control-signals=Styrsignaler +;history=Historik +in-transit=Transporterar +inventory=Innehåll +layout=Tåglayout +name=Namn +network-name-label=Nätverksfilter: +network-id-label=Nätverks-ID: +network-id=Nätverks-ID +no-alerts=[img=warning-white] Inga larm +;no-history=[img=warning-white] Ingen historik +no-stations=[img=warning-white] Inga stationer +;not-available=Ej tillgänglig +no-trains=[img=warning-white] Inga tåg +open-station-gui=Öppna stations-GUI\n[font=default-semibold][color=128,206,240]Skift:[/color][/font] Öppna station på kartan\n[font=default-semibold][color=128,206,240]Kontroll:[/color][/font] Öppna stationens Cybernetiska kombinator\n[font=default-semibold][color=128,206.240]Alt:[/color][/font] Öppna stationens Cybernetiska stationskontrollkombinator +open-train-gui=Öppna tåg-GUI +provided=Levererat +;provided-requested-description=Grönt = levererat\nRött = beställt +provided-requested=Levererat / beställt +;refresh-tooltip=Uppdatera\n[font=default-semibold][color=128,206,240]Skift:[/color][/font] Slå på/av autouppdatering +requested=Beställt +search-label=Stationsnamn: +search-item-label=Varufilter: +shipment=Leverans +shipments=Leveranser +stations=Stationer +status=Nätverkssignal +surface-label=Yta: +time=Tid +train-id=Tåg-ID +trains=Tåg + +[cybersyn-message] +error-cybernetic-combinator-not-found=Kunde inte hitta en Cybernetisk kombinator för stationen. +error-station-control-combinator-not-found=Kunde inte hitta en Cybernetisk stationskontrollkombinator för stationen. +error-station-is-invalid=Stationen är felaktig, var god uppdatera GUI:t. +error-train-is-invalid=Tåget är felaktigt, var god uppdatera GUI:t. +error-cross-surface-camera-invalid=Kan inte flytta kameran till en entitet på en annan yta! + +[cybersyn-mod-setting-description] +iterations-per-tick=Minska numret om du har prestandaproblem. + +[cybersyn-mod-setting-name] +history-length=Historiklängd +iterations-per-tick=Iterationer per tick [img=info] + +[shortcut-name] +cybersyn-toggle-gui=Visa/dölj Cybersyn-hanteraren From e2aaa2612ba1381292c3e7f0478d3f1b0ecac531 Mon Sep 17 00:00:00 2001 From: Eldrinn-Elantey <46845681+Eldrinn-Elantey@users.noreply.github.com> Date: Sat, 5 Aug 2023 15:52:41 +0400 Subject: [PATCH 10/29] Minor --- cybersyn/locale/ru/manager.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cybersyn/locale/ru/manager.cfg b/cybersyn/locale/ru/manager.cfg index 1b73542..95b5f56 100644 --- a/cybersyn/locale/ru/manager.cfg +++ b/cybersyn/locale/ru/manager.cfg @@ -21,7 +21,7 @@ no-alerts=[img=warning-white] Тревог нет no-stations=[img=warning-white] Станций нет ;not-available=Not available no-trains=[img=warning-white] Поездов нет -open-station-gui=Открыть интерфейс станции\n[font=default-semibold][color=128,206,240]Shift:[/color][/font] Открыть станцию на карте\n[font=default-semibold][color=128,206,240]Control:[/color][/font] Открыть интерфейс кибернетического комбинатора станции\n[font=default-semibold][color=128,206,240]Alt:[/color][/font] Открыть интерфейс кибернетического комбинатора контроля станции +open-station-gui=Открыть интерфейс станции\n[font=default-semibold][color=128,206,240]Shift:[/color][/font] Открыть станцию на карте\n[font=default-semibold][color=128,206,240]Control:[/color][/font] Открыть интерфейс кибернетического комбинатора станции\n[font=default-semibold][color=128,206,240]Alt:[/color][/font] Открыть интерфейс кибернетического комбинатора управления станции open-train-gui=Открыть интерфейс поезда provided=Снабжение ;provided-requested-description=Green = provided\nRed = requested From 38782c4bcb3407073d63f5058ac63301071011cd Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Sat, 5 Aug 2023 18:06:38 +0200 Subject: [PATCH 11/29] Fix typos and improve wording in sv-SE locale --- cybersyn/locale/sv-SE/base.cfg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cybersyn/locale/sv-SE/base.cfg b/cybersyn/locale/sv-SE/base.cfg index 9ad191e..c4843fd 100644 --- a/cybersyn/locale/sv-SE/base.cfg +++ b/cybersyn/locale/sv-SE/base.cfg @@ -20,7 +20,7 @@ cybersyn-manager-update-rate=Uppdateringsfrekvens för hanteraren cybersyn-manager-result-limit=Max antal entiteter som visas på GUI-sidor. [mod-setting-description] -cybersyn-enable-planner=Aktivera eller avaktivera centralplaneringsalgoritmen. När den är avstängd kommer ingen nya tåg att skickas iväg. +cybersyn-enable-planner=Aktivera eller avaktivera centralplaneringsalgoritmen. När den är avstängd kommer inga nya tåg att skickas iväg. cybersyn-ticks-per-second=Antal gånger per sekund som centralplaneraren ska uppdatera nätverksstatusen och planera leveranser. Värdet rundas upp till en divisor 60. Om satt till 0 stoppas alla avsändningar. cybersyn-update-rate=Antal stationer per tick som uppdateras eller får leveranser planerade åt gången. Större nummer låter centralplaneraren hålla sig uppdaterade gentemot nätverkets status, men kräver mer prestanda. cybersyn-request-threshold=Standardvärde för förfrågningströskeln när en specifik tröskelsignal inte ges till en station. När en station tar emot en negativ varusignal som är större än förfrågningströskeln, förutsatt att det finns en annan station med en positiv signal som är större än tröskeln, planeras en leverans av varan mellan de två stationerna. @@ -28,9 +28,9 @@ cybersyn-priority=Standardvärde för prioritet när en prioritetssignal inte ge cybersyn-locked-slots=Standardvärde för antal låsta platser per lastvagn när en signal för "låsta platser per lastvagn" inte ges till stationen. När en leverantörsstation har ett värde X för "låsta platser per lastvagn", leder det till att tåg som utför leveranser från den stationen får sin order justerad så att varje lastvagn har åtminstone X platser som lämnas tomma. Detta är nödvändigt för att möjliggöra leverantörsstationer som kan leverera fler än en typ av vara. cybersyn-network-flag=Standardvärde för nätverksmasken (en samling subnätverk) en station konfigureras med om ingen signal för nätverksmask ges till den. Heltalet tolkas bitvis för 32 möjliga subnätverk att välja mellan. cybersyn-fuel-threshold=Andelen av ett tågs bränsleinnehåll som måste vara fylld för att tåget ska hoppa över bränslestationer. När värdet är 1 kommer tåg alltid att besöka en bränslestation efter varje utförd leverans. -cybersyn-depot-bypass-enabled=Med den här inställningen aktiverad kan tåg, efter att de slutfört sin leverans och eventuell påfyllning av bränsle, få en ny order från nätverket utan att först återvänta till sin depå. -cybersyn-warmup-time=Antal sekunder som en Cybernetisk kombinatorer väntar innan den ansluter till Cybersyn-nätverket. Det här tillåter tid för ändringar eller korrigeringar till kretsnätverket innan tåg börjar skickas till en nyligen byggd station. -cybersyn-stuck-train-time=Antal sekunder räknat från ett tågs avsändningstid som en varning skickas för att meddela att ett tåg antagligen fastnat och inte har slutfört sin leverans. Spelaren kommer antagligen behöva felsöka sitt nätverk för att få loss tåget. +cybersyn-depot-bypass-enabled=Med den här inställningen aktiverad kan tåg, efter att de slutfört sin leverans och eventuell påfyllning av bränsle, få en ny order från nätverket utan att först återvända till sin depå. +cybersyn-warmup-time=Antal sekunder som en Cybernetisk kombinator väntar innan den ansluter till Cybersyn-nätverket. Det här tillåter tid för ändringar eller korrigeringar till kretsnätverket innan tåg börjar skickas till en nyligen byggd station. +cybersyn-stuck-train-time=Antal sekunder räknat från ett tågs avgångstid som en varning skickas för att meddela att ett tåg antagligen fastnat och inte har slutfört sin leverans. Spelaren kommer antagligen behöva felsöka sitt nätverk för att få loss tåget. cybersyn-allow-cargo-in-depot=Tillåter att tåg anländer till en depå med last kvar i sina vagnar. Inga varningar kommer skapas och tåget hålls inte kvar i depån. Dessutom, för tåg med en order att besöka en beställarstation som har "Inaktivetetsvillkor" ikryssat, kommer de att vänta på inaktivetet istället för tom last. Användbart för att skapa tågsystem där depåer hanterar överflödig last. Endast för avancerade användare. cybersyn-invert-sign=Invertera (ändra positivt till negativt och vice versa) utsignalen från Cybernetiska kombinatorer till att vara som de är i LTN eller tidigare versioner av Projekt Cybersyn. cybersyn-manager-enabled=Ger en översikt över alla tåg och stationer som är anslutna till Cybersyn-nätverket. Gränssnittet är under utveckling och kan leda till många krascher. From 2f09febbe6874e7c285c21bf52d83990f275b0ee Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Sat, 5 Aug 2023 18:13:12 +0200 Subject: [PATCH 12/29] =?UTF-8?q?Use=20"last/f=C3=B6rem=C3=A5l"=20instead?= =?UTF-8?q?=20of=20"vara"=20in=20sv-SE=20locale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cybersyn/locale/sv-SE/base.cfg | 12 ++++++------ cybersyn/locale/sv-SE/manager.cfg | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cybersyn/locale/sv-SE/base.cfg b/cybersyn/locale/sv-SE/base.cfg index c4843fd..1849c1a 100644 --- a/cybersyn/locale/sv-SE/base.cfg +++ b/cybersyn/locale/sv-SE/base.cfg @@ -23,9 +23,9 @@ cybersyn-manager-result-limit=Max antal entiteter som visas på GUI-sidor. cybersyn-enable-planner=Aktivera eller avaktivera centralplaneringsalgoritmen. När den är avstängd kommer inga nya tåg att skickas iväg. cybersyn-ticks-per-second=Antal gånger per sekund som centralplaneraren ska uppdatera nätverksstatusen och planera leveranser. Värdet rundas upp till en divisor 60. Om satt till 0 stoppas alla avsändningar. cybersyn-update-rate=Antal stationer per tick som uppdateras eller får leveranser planerade åt gången. Större nummer låter centralplaneraren hålla sig uppdaterade gentemot nätverkets status, men kräver mer prestanda. -cybersyn-request-threshold=Standardvärde för förfrågningströskeln när en specifik tröskelsignal inte ges till en station. När en station tar emot en negativ varusignal som är större än förfrågningströskeln, förutsatt att det finns en annan station med en positiv signal som är större än tröskeln, planeras en leverans av varan mellan de två stationerna. +cybersyn-request-threshold=Standardvärde för förfrågningströskeln när en specifik tröskelsignal inte ges till en station. När en station tar emot en negativ lastsignal som är större än förfrågningströskeln, förutsatt att det finns en annan station med en positiv signal som är större än tröskeln, planeras en leverans av lasten mellan de två stationerna. cybersyn-priority=Standardvärde för prioritet när en prioritetssignal inte ges till en station, depå, eller bränslestation. Stationer med högre prioritet tar emot leveranser innan stationer med lägre prioritet. -cybersyn-locked-slots=Standardvärde för antal låsta platser per lastvagn när en signal för "låsta platser per lastvagn" inte ges till stationen. När en leverantörsstation har ett värde X för "låsta platser per lastvagn", leder det till att tåg som utför leveranser från den stationen får sin order justerad så att varje lastvagn har åtminstone X platser som lämnas tomma. Detta är nödvändigt för att möjliggöra leverantörsstationer som kan leverera fler än en typ av vara. +cybersyn-locked-slots=Standardvärde för antal låsta platser per lastvagn när en signal för "låsta platser per lastvagn" inte ges till stationen. När en leverantörsstation har ett värde X för "låsta platser per lastvagn", leder det till att tåg som utför leveranser från den stationen får sin order justerad så att varje lastvagn har åtminstone X platser som lämnas tomma. Detta är nödvändigt för att möjliggöra leverantörsstationer som kan leverera fler än en typ av last. cybersyn-network-flag=Standardvärde för nätverksmasken (en samling subnätverk) en station konfigureras med om ingen signal för nätverksmask ges till den. Heltalet tolkas bitvis för 32 möjliga subnätverk att välja mellan. cybersyn-fuel-threshold=Andelen av ett tågs bränsleinnehåll som måste vara fylld för att tåget ska hoppa över bränslestationer. När värdet är 1 kommer tåg alltid att besöka en bränslestation efter varje utförd leverans. cybersyn-depot-bypass-enabled=Med den här inställningen aktiverad kan tåg, efter att de slutfört sin leverans och eventuell påfyllning av bränsle, få en ny order från nätverket utan att först återvända till sin depå. @@ -41,7 +41,7 @@ cybersyn-manager-result-limit=Sätter en gräns på antalet matchande entiteter cybersyn-combinator=__ENTITY__cybersyn-combinator__ [item-description] -cybersyn-combinator=Placera vid en tågstation för att lägga till den till Cybersyn-tågnätverket. Stationen kan nu beställa eller leverera varor som skickas in till kombinatorn via signaler i kretsnätverket. +cybersyn-combinator=Placera vid en tågstation för att lägga till den till Cybersyn-tågnätverket. Stationen kan nu beställa eller leverera last som skickas in till kombinatorn via signaler i kretsnätverket. [entity-name] cybersyn-combinator=Cybernetisk kombinator @@ -85,8 +85,8 @@ comb2=Stationskontroll wagon-manifest=Vagnkontroll switch-provide=Leverantör switch-request=Beställare -switch-provide-tooltip=Lås den här stationen till att endast leverera varor till nätverket. I ospecificerat läge kan den både leverera och beställa. -switch-request-tooltip=Lås den här stationen till att endast beställa varor från nätverket. I ospecificerat läge kan den både beställa och leverera. +switch-provide-tooltip=Lås den här stationen till att endast leverera föremål till nätverket. I ospecificerat läge kan den både leverera och beställa. +switch-request-tooltip=Lås den här stationen till att endast beställa föremål från nätverket. I ospecificerat läge kan den både beställa och leverera. network=Nätverk network-tooltip=En signal som används för att identifiera vilket nätverk den här kombinatorn tillhör. Tåg skickas endast endast från depåer till leverantörer och beställare om de alla delar samma signal. allow-list-description=Automatiskt tillåtna tåg @@ -100,4 +100,4 @@ use-same-depot-tooltip=Om aktiverad kommer tåg som lämnar från den här depå depot-bypass-description=Hoppa över depå depot-bypass-tooltip=Tåg från den här depån kan få nya ordrar utan att först parkera vid depån, om de inte har en pågående order. De kommer fortfarande att återvända till depån om de har låg bränslenivå och det inte finns några bränslestationer tillgängliga på nätverket. enable-slot-barring-description=Blockera ofiltrerade platser -enable-slot-barring-tooltip=Platser i intilliggande vagn som inte har filter blockeras istället så att varor inte kan lastas i dem. +enable-slot-barring-tooltip=Platser i intilliggande vagn som inte har filter blockeras istället så att föremål inte kan lastas i dem. diff --git a/cybersyn/locale/sv-SE/manager.cfg b/cybersyn/locale/sv-SE/manager.cfg index e711496..1613787 100644 --- a/cybersyn/locale/sv-SE/manager.cfg +++ b/cybersyn/locale/sv-SE/manager.cfg @@ -29,7 +29,7 @@ provided-requested=Levererat / beställt ;refresh-tooltip=Uppdatera\n[font=default-semibold][color=128,206,240]Skift:[/color][/font] Slå på/av autouppdatering requested=Beställt search-label=Stationsnamn: -search-item-label=Varufilter: +search-item-label=Lastfilter: shipment=Leverans shipments=Leveranser stations=Stationer From ab673dca0c311238ae171785622b8bdaab2d4b0e Mon Sep 17 00:00:00 2001 From: FinalFrag Date: Thu, 10 Aug 2023 00:57:31 +0200 Subject: [PATCH 13/29] Added missing provider message --- cybersyn/locale/en/base.cfg | 1 + cybersyn/scripts/central-planning.lua | 4 +++- cybersyn/scripts/factorio-api.lua | 11 +++++++++++ cybersyn/scripts/remote-interface.lua | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cybersyn/locale/en/base.cfg b/cybersyn/locale/en/base.cfg index dbba4ea..41dac51 100644 --- a/cybersyn/locale/en/base.cfg +++ b/cybersyn/locale/en/base.cfg @@ -67,6 +67,7 @@ depot-broken=A train is lost because its depot was broken refueler-broken=A train is lost because its refueler was broken station-broken=A train is lost because one of its delivery stations was broken train-at-incorrect=A train parked at a station it was not scheduled to delivered to +missing-provider=Could not find a station providing __1__ to make a delivery to __2__ missing-train=Could not find any train on the correct network to make a delivery from __2__ to __1__ no-train-has-capacity=Could not find a train with enough cargo capacity to make a delivery from __2__ to __1__ no-train-matches-r-layout=Could not find a train on the allow-list of __1__ to make a delivery diff --git a/cybersyn/scripts/central-planning.lua b/cybersyn/scripts/central-planning.lua index 9428d4d..9ab50bc 100644 --- a/cybersyn/scripts/central-planning.lua +++ b/cybersyn/scripts/central-planning.lua @@ -492,7 +492,9 @@ local function tick_dispatch(map_data, mod_settings) create_delivery(map_data, r_station_id, p_station_id, best_train_id, manifest) return false else - if correctness == 1 then + if correctness == 0 then + send_alert_missing_provider(item_name, r_station.entity_stop) + elseif correctness == 1 then send_alert_missing_train(r_station.entity_stop, closest_to_correct_p_station.entity_stop) elseif correctness == 2 then send_alert_no_train_has_capacity(r_station.entity_stop, closest_to_correct_p_station.entity_stop) diff --git a/cybersyn/scripts/factorio-api.lua b/cybersyn/scripts/factorio-api.lua index cf78fc0..f2b18ac 100644 --- a/cybersyn/scripts/factorio-api.lua +++ b/cybersyn/scripts/factorio-api.lua @@ -776,6 +776,17 @@ function send_alert_sounds(train) end +---@param r_stop LuaEntity +---@param item_name string +function send_alert_missing_provider(item_name, r_stop) + for _, player in pairs(r_stop.force.players) do + player.add_custom_alert( + r_stop, + send_alert_about_missing_train_icon, + {"cybersyn-messages.missing-provider", item_name, r_stop.backer_name}, + true) + end +end ---@param r_stop LuaEntity ---@param p_stop LuaEntity function send_alert_missing_train(r_stop, p_stop) diff --git a/cybersyn/scripts/remote-interface.lua b/cybersyn/scripts/remote-interface.lua index efaa420..9985750 100644 --- a/cybersyn/scripts/remote-interface.lua +++ b/cybersyn/scripts/remote-interface.lua @@ -353,6 +353,7 @@ interface.add_refueler_schedule = add_refueler_schedule --[[alerts]] ------------------------------------------------------------------ +interface.send_alert_missing_provider = send_alert_missing_provider interface.send_alert_missing_train = send_alert_missing_train interface.send_alert_unexpected_train = send_alert_unexpected_train interface.send_alert_nonempty_train_in_depot = send_alert_nonempty_train_in_depot From d24a4ed32ec64f2a7256f81c4a7d7a23c28f38db Mon Sep 17 00:00:00 2001 From: FinalFrag Date: Thu, 10 Aug 2023 02:08:03 +0200 Subject: [PATCH 14/29] Added missing provider message --- cybersyn/scripts/factorio-api.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cybersyn/scripts/factorio-api.lua b/cybersyn/scripts/factorio-api.lua index f2b18ac..44b2f18 100644 --- a/cybersyn/scripts/factorio-api.lua +++ b/cybersyn/scripts/factorio-api.lua @@ -776,8 +776,8 @@ function send_alert_sounds(train) end ----@param r_stop LuaEntity ---@param item_name string +---@param r_stop LuaEntity function send_alert_missing_provider(item_name, r_stop) for _, player in pairs(r_stop.force.players) do player.add_custom_alert( From bd28d8a3fcd7ac80bbfd1c149b2068d332232a1a Mon Sep 17 00:00:00 2001 From: Shadowsvoices Date: Sun, 10 Sep 2023 23:49:42 +0200 Subject: [PATCH 15/29] manager gui stations: include station control signals in control signal column --- cybersyn/scripts/gui/stations.lua | 2 +- cybersyn/scripts/gui/util.lua | 65 ++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/cybersyn/scripts/gui/stations.lua b/cybersyn/scripts/gui/stations.lua index 6f1b4c1..4948a55 100644 --- a/cybersyn/scripts/gui/stations.lua +++ b/cybersyn/scripts/gui/stations.lua @@ -250,7 +250,7 @@ function stations_tab.build(map_data, player_data, query_limit) 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)) - gui.add(refs.control_signals_table, util.slot_table_build_from_control_signals(station)) + gui.add(refs.control_signals_table, util.slot_table_build_from_control_signals(station, map_data)) end diff --git a/cybersyn/scripts/gui/util.lua b/cybersyn/scripts/gui/util.lua index dd7c7f6..e06debe 100644 --- a/cybersyn/scripts/gui/util.lua +++ b/cybersyn/scripts/gui/util.lua @@ -171,10 +171,11 @@ end --- @param station Station --- @return GuiElemDef[] -function util.slot_table_build_from_control_signals(station) +function util.slot_table_build_from_control_signals(station, map_data) ---@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 @@ -205,6 +206,68 @@ function util.slot_table_build_from_control_signals(station) ::continue:: end end + + if comb2_signals then + for _, v in pairs(comb2_signals) do + local item = v.signal + local count = v.count + local name = item.name + local sprite = "" + local color = "default" + + if item.type == "item" or item.type == "fluid" then + 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 = "blue" + end + end + + if station.is_stack and item.type == "item" then + count = count * get_stack_size(map_data, 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_path, + item_string, + "\n"..format.number(count), + }, + number = count + } + end + + elseif item.type == "virtual" then + sprite = "virtual-signal" .. "/" .. name + 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 + end + ::continue:: + end + end + return children end From 82fd7fcac00e2af72a87a77adf57616a822503ad Mon Sep 17 00:00:00 2001 From: Shadowsvoices Date: Sun, 10 Sep 2023 23:52:24 +0200 Subject: [PATCH 16/29] manager gui inventory: only include requests GTEQ threshold --- cybersyn/scripts/gui/inventory.lua | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/cybersyn/scripts/gui/inventory.lua b/cybersyn/scripts/gui/inventory.lua index 20405d9..7034d27 100644 --- a/cybersyn/scripts/gui/inventory.lua +++ b/cybersyn/scripts/gui/inventory.lua @@ -132,10 +132,17 @@ function inventory_tab.build(map_data, player_data) 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 + local r_threshold = station.item_thresholds and station.item_thresholds[item.name] or station.r_threshold + if station.is_stack and item_type == "item" then + r_threshold = r_threshold*get_stack_size(map_data, item.name) + end + + if -count >= r_threshold then + 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 From 9516a1356605f0e0a5b5c1d7c539bcdd933505cd Mon Sep 17 00:00:00 2001 From: Monica Moniot Date: Sun, 24 Sep 2023 18:30:51 -0400 Subject: [PATCH 17/29] updated revision number and changelog --- cybersyn/changelog.txt | 16 ++++++++++++++++ cybersyn/info.json | 2 +- cybersyn/info.lua | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/cybersyn/changelog.txt b/cybersyn/changelog.txt index 670de34..8adddaf 100644 --- a/cybersyn/changelog.txt +++ b/cybersyn/changelog.txt @@ -1,4 +1,20 @@ --------------------------------------------------------------------------------------------------- +Version: 1.3.0 +Date: 2023-9-24 + Features: + - Added an alert when no provider is found for an item, indicating a bottleneck in your factory - contributed by FinalFrag + - The manager gui now displays control signals - contributed by Shadowvoices + - The manager gui now excludes requests that do not exceed the request threshold - contributed by Shadowvoices + Bugfixes: + - Fixed a crash when clicking on a combinator when the GUI is open - contributed by PeteyPii + - Fixed a crash when setting a combinator to depot mode without a network - contributed by download13 + - Fixed a crash when opening the manager when adding cybersyn to an existing save - contributed by Mjonir + - Stations with provider item thresholds can no longer generate empty train orders - contributed by svr8450 + Translation: + - Swedish language added - contributed by Sharparam + - Chinese language update - contributed by luaotix + - Russian language update - contributed by Eldrinn-Elantey +--------------------------------------------------------------------------------------------------- Version: 1.2.16 Date: 2023-5-14 Bugfixes: diff --git a/cybersyn/info.json b/cybersyn/info.json index 739a874..4af65bd 100644 --- a/cybersyn/info.json +++ b/cybersyn/info.json @@ -1,6 +1,6 @@ { "name": "cybersyn", - "version": "1.2.16", + "version": "1.3.0", "title": "Project Cybersyn", "author": "Mami", "factorio_version": "1.1", diff --git a/cybersyn/info.lua b/cybersyn/info.lua index 639a3a2..67b1327 100644 --- a/cybersyn/info.lua +++ b/cybersyn/info.lua @@ -3,4 +3,4 @@ --- It is used in migrations.lua to determine if any migrations need to be run for beta testers. --- It is expected these are only meaningful between releases during beta testing. --- It should be set to nil for any release version. -return nil +return 0 From 14be7dcfa0f448aaf66aa240a5632b40b0ca4e52 Mon Sep 17 00:00:00 2001 From: Freya Arbjerg Date: Tue, 26 Sep 2023 17:03:16 +0200 Subject: [PATCH 18/29] Ensure manager is initialised upon migration --- cybersyn/scripts/gui/main.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cybersyn/scripts/gui/main.lua b/cybersyn/scripts/gui/main.lua index dfbcade..52bd545 100644 --- a/cybersyn/scripts/gui/main.lua +++ b/cybersyn/scripts/gui/main.lua @@ -161,6 +161,10 @@ end function manager_gui.on_migration() + if not global.manager then + manager_gui.on_init() + end + for i, p in pairs(game.players) do if global.manager.players[i] == nil then create_player(i) From 6501193a932e7e61a5a494a5a7e4bfc0ad7ea0e1 Mon Sep 17 00:00:00 2001 From: James Gangur Date: Thu, 28 Sep 2023 22:56:26 +1000 Subject: [PATCH 19/29] fixed provide/request orders for the same item getting generated simultaneously --- cybersyn/scripts/central-planning.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cybersyn/scripts/central-planning.lua b/cybersyn/scripts/central-planning.lua index 926d0dd..1a799cc 100644 --- a/cybersyn/scripts/central-planning.lua +++ b/cybersyn/scripts/central-planning.lua @@ -304,6 +304,12 @@ local function tick_dispatch(map_data, mod_settings) goto continue end + --don't request when already providing + local item_deliveries = station.deliveries[item_name] + if item_deliveries and item_deliveries < 0 then + goto continue + end + r_station_i = i r_threshold = threshold best_r_prior = prior @@ -348,7 +354,7 @@ local function tick_dispatch(map_data, mod_settings) ---@type uint local j = 1 while j <= #p_stations do - local p_flag, r_flag, netand, best_p_train_id, best_t_prior, best_capacity, best_t_to_p_dist, effective_count, override_threshold, p_prior, best_p_to_r_dist, effective_threshold, slot_threshold + local p_flag, r_flag, netand, best_p_train_id, best_t_prior, best_capacity, best_t_to_p_dist, effective_count, override_threshold, p_prior, best_p_to_r_dist, effective_threshold, slot_threshold, item_deliveries local p_station_id = p_stations[j] local p_station = stations[p_station_id] @@ -483,6 +489,12 @@ local function tick_dispatch(map_data, mod_settings) goto p_continue end + --don't provide when already requesting + item_deliveries = p_station.deliveries[item_name] + if item_deliveries and item_deliveries > 0 then + goto p_continue + end + p_station_i = j best_train_id = best_p_train_id best_p_prior = p_prior From 07c810c04ec4b168edb53052d3678258ab6c6b3e Mon Sep 17 00:00:00 2001 From: James Gangur Date: Fri, 29 Sep 2023 23:21:25 +1000 Subject: [PATCH 20/29] remove old check for each on depots --- cybersyn/scripts/gui.lua | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cybersyn/scripts/gui.lua b/cybersyn/scripts/gui.lua index c70896a..263aa44 100644 --- a/cybersyn/scripts/gui.lua +++ b/cybersyn/scripts/gui.lua @@ -89,13 +89,6 @@ local function handle_drop_down(e) set_comb_operation(comb, MODE_PRIMARY_IO) elseif element.selected_index == 2 then set_comb_operation(comb, MODE_DEPOT) - --prevent the use of the each signal with depots - local network = element.parent.parent.bottom.network--[[@as LuaGuiElement]] - local signal = network.elem_value--[[@as SignalID]] - if signal and (signal.name == NETWORK_EACH) then - network.elem_value = nil - set_comb_network_name(comb, nil) - end elseif element.selected_index == 3 then set_comb_operation(comb, MODE_REFUELER) elseif element.selected_index == 4 then From 1cf59f9915901cabd6c9e3f64c37aaa8ebca0190 Mon Sep 17 00:00:00 2001 From: James Gangur Date: Sat, 30 Sep 2023 19:43:32 +1000 Subject: [PATCH 21/29] add custom sprites for combinator displays --- .../combinator/cybernetic-displays.png | Bin 10876 -> 1756 bytes .../combinator/hr-cybernetic-displays.png | Bin 19055 -> 4945 bytes dev/hr-cybernetic-displays.xcf | Bin 0 -> 24385 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 dev/hr-cybernetic-displays.xcf diff --git a/cybersyn/graphics/combinator/cybernetic-displays.png b/cybersyn/graphics/combinator/cybernetic-displays.png index 7d5d36a06e2be5b0b3dbe05dfc111ae24574c01f..97547c2cbacfd2cd69c4f0d978c2b2ef7e882426 100644 GIT binary patch delta 1741 zcmV;;1~U2lRNM`aBYy^?Nkl?wK>+x^!`J2-`+U zN&4;$gag}YdG#oB4}XQ`1Eb8ocaAk}tz4eDLT5)iA52Y?ZEpGZ%;gW)U%EIscA+)OMjDio=>S%BAd-HcQvHz{x2~1we2(?7-jOG?_9^$ytd;|i6UC=-N@X) zcG^GUpFVeXN$*Nn*Kr-&^HN~h=!A>u?IS(dkJHwH_odI{PtOn>+(!`j1inW$ohFfR zacn!e!1ngx5B6hC&yfE8D4rjnlq8)Fn2+X3^!DKl_J5O}o+0tCiR;;_*RpL~+rsJX z!yD`;(bj=m^IyEMw08xpZP^x5NCMwOD@CRlVnqsXd<-)*Oi~s|zdnZB`v{h0VF25< zu`J8f*mN;OM~ZYYL}^Vj;bM%zbzLx!EQVwvg;Nac*ahz+U&T81240xQ3=QM{VlNC0 zr6Fr$ zG`4MVHDACO!`0SiRI^W^s~e#txz=W6vrnn3n}1Syo>&S*EWol@U|X9pRYqw=p|=k` z*iZSP$A~I1h3brAS9d*I_2ysu18T=pgq#gJn4O5^#od}KyB@MtQAnCkDvY|ZPq z34d%0f+L5}C&p;mcpuiux5)hJ1u`%HW=U_OJ!b-+a^MjJe%+pJfJ#&$k#MhF0bwC3 zF#vL87kXY2oj!&7&m7u-F$S#-S}Ci>%3PWF^eK##$Q{ouFh)xBvwN?fv52jClXt8` z?syJ+-JQrs2hipC+7-Wnx5lbm8Bz0(?0>?ny&L`PUX0_{v9?kgsU%V=L@bF~n-R@E z(dGwHgZ)HJ?aY7gN#av)qLd`62(;EkuC~gneQRF?$hxa2;amJW45~l*F+BqX9_!{*^Utt%;@BcaP?i818V z`I}}};?3m?*tSJneI4ZNMbyD{OM0!{yLa39TyA4F6LgeHWy|wYPPsg9`M&3bxxC$! z$=bPm-toMYT`rfcR4Qo;AurwWv45`PfOWgEZa$Y=KRxyS@P!7M_CbS8Ti5-G@oM7z z-`Slzcb0&+S;4AH%UY)W)br`Q_dd$+oguhq182{j<>w93axv>Y;8S|IMD}=wx!#a9 zFSl~}?HjYVlC;19R=C_onYPIf_*731%+5kj43=l=^PA=g zW_*HoZ_M6G(z1$GmzKZvea64}ZAiEr9^KDA9dmg93mkQvWfL!W+(#YNB#SO)#NfW@ z!U#BjT%Ns^q+Qj47iU_iG{uPtY^`bk%>CFxvP&CYxrxM6p+=ros92-7YNRdE72O$$vtTFOK~gU8=C9r-v`!Ak!AJg=0n3h$7!sLTr_p3l)B$>EoNO%V88_~DOuX^Bj0 z#Ac5L1S1|9e1bPUf`R4Pwqi&+QnZYZks2DNMHc8d`4*Y2gLUlco`3M7OdC!ndH$Xa zeA0Gk-|$%~SQIBFC>fSbyyW^M@@a{^)u?%A_v#ZURa7jCG;F>fsg00000NkvXXu0mjfibI8h literal 10876 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 diff --git a/dev/hr-cybernetic-displays.xcf b/dev/hr-cybernetic-displays.xcf new file mode 100644 index 0000000000000000000000000000000000000000..72866733ef7a1305e38876141319d59d67aa04e3 GIT binary patch literal 24385 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 s?iV# Date: Sun, 1 Oct 2023 17:35:01 -0700 Subject: [PATCH 22/29] Revert "fix issue 106 and bump version" This reverts commit 3df1e76715307c6447385767ee05cbb7b5ca2319. --- cybersyn/info.json | 2 +- cybersyn/scripts/layout.lua | 102 ++++++++++++++---------------------- 2 files changed, 40 insertions(+), 64 deletions(-) diff --git a/cybersyn/info.json b/cybersyn/info.json index 7b31b65..739a874 100644 --- a/cybersyn/info.json +++ b/cybersyn/info.json @@ -1,6 +1,6 @@ { "name": "cybersyn", - "version": "1.2.17", + "version": "1.2.16", "title": "Project Cybersyn", "author": "Mami", "factorio_version": "1.1", diff --git a/cybersyn/scripts/layout.lua b/cybersyn/scripts/layout.lua index 0b83b70..46b82b1 100644 --- a/cybersyn/scripts/layout.lua +++ b/cybersyn/scripts/layout.lua @@ -9,7 +9,7 @@ local bit_extract = bit32.extract local defines_front = defines.rail_direction.front local defines_back = defines.rail_direction.back local defines_straight = defines.rail_connection_direction.straight -local search_type = { "straight-rail", "curved-rail" } +local search_type = {"straight-rail", "curved-rail"} ---@param layout_pattern (0|1|2|3)[] @@ -33,7 +33,6 @@ function is_refuel_layout_accepted(layout_pattern, layout) end return valid end - ---@param layout_pattern (0|1|2|3)[] ---@param layout (0|1|2)[] function is_layout_accepted(layout_pattern, layout) @@ -84,6 +83,7 @@ function remove_train(map_data, train_id, train) interface_raise_train_removed(train_id, train) end + ---@param map_data MapData ---@param train Train function set_train_layout(map_data, train) @@ -166,7 +166,7 @@ end function set_p_wagon_combs(map_data, station, train) if not station.wagon_combs or not next(station.wagon_combs) then return end local carriages = train.entity.carriages - local manifest = train.manifest --[[@as Manifest]] + local manifest = train.manifest--[[@as Manifest]] if not manifest[1] then return end local sign = mod_settings.invert_sign and 1 or -1 @@ -178,7 +178,7 @@ function set_p_wagon_combs(map_data, station, train) local total_item_slots if locked_slots > 0 then local total_cargo_wagons = #train.entity.cargo_wagons - total_item_slots = max(train.item_slot_capacity - total_cargo_wagons * locked_slots, 1) + total_item_slots = max(train.item_slot_capacity - total_cargo_wagons*locked_slots, 1) else total_item_slots = train.item_slot_capacity end @@ -186,10 +186,10 @@ function set_p_wagon_combs(map_data, station, train) local to_be_used_item_slots = 0 for i, item in ipairs(train.manifest) do if item.type == "item" then - to_be_used_item_slots = to_be_used_item_slots + ceil(item.count / get_stack_size(map_data, item.name)) + to_be_used_item_slots = to_be_used_item_slots + ceil(item.count/get_stack_size(map_data, item.name)) end end - percent_slots_to_use_per_wagon = min(to_be_used_item_slots / total_item_slots, 1.0) + percent_slots_to_use_per_wagon = min(to_be_used_item_slots/total_item_slots, 1.0) end local item_i = 1 @@ -219,20 +219,16 @@ function set_p_wagon_combs(map_data, station, train) local signals = {} local inv_filter_i = 1 - local item_slots_capacity = max(ceil((#inv - locked_slots) * percent_slots_to_use_per_wagon), 1) + local item_slots_capacity = max(ceil((#inv - locked_slots)*percent_slots_to_use_per_wagon), 1) while item_slots_capacity > 0 and item_i <= #manifest do local do_inc if item.type == "item" then local stack_size = get_stack_size(map_data, item.name) local i = #signals + 1 - local count_to_fill = min(item_slots_capacity * stack_size, item_count) - local slots_to_fill = ceil(count_to_fill / stack_size) + local count_to_fill = min(item_slots_capacity*stack_size, item_count) + local slots_to_fill = ceil(count_to_fill/stack_size) - signals[i] = { - index = i, - signal = { type = item.type, name = item.name }, - count = sign * count_to_fill - } + signals[i] = {index = i, signal = {type = item.type, name = item.name}, count = sign*count_to_fill} item_count = item_count - count_to_fill item_slots_capacity = item_slots_capacity - slots_to_fill if comb then @@ -259,7 +255,7 @@ function set_p_wagon_combs(map_data, station, train) if comb then if bit_extract(get_comb_params(comb).second_constant, SETTING_ENABLE_SLOT_BARRING) > 0 then - inv.set_bar(inv_filter_i --[[@as uint]]) + inv.set_bar(inv_filter_i--[[@as uint]]) train.has_filtered_wagon = true end set_combinator_output(map_data, comb, signals) @@ -274,11 +270,7 @@ function set_p_wagon_combs(map_data, station, train) if fluid.type == "fluid" then local count_to_fill = min(fluid_count, fluid_capacity) - signals[1] = { - index = 1, - signal = { type = fluid.type, name = fluid.name }, - count = sign * count_to_fill - } + signals[1] = {index = 1, signal = {type = fluid.type, name = fluid.name}, count = sign*count_to_fill} fluid_count = fluid_count - count_to_fill fluid_capacity = 0 do_inc = fluid_count == 0 @@ -331,12 +323,7 @@ function set_r_wagon_combs(map_data, station, train) local stack = inv[stack_i] if stack.valid_for_read then local i = #signals + 1 - signals[i] = { - index = i, - signal = { type = "item", name = stack.name }, - count = sign * - stack.count - } + signals[i] = {index = i, signal = {type = "item", name = stack.name}, count = sign*stack.count} end end set_combinator_output(map_data, comb, signals) @@ -347,13 +334,14 @@ function set_r_wagon_combs(map_data, station, train) local inv = carriage.get_fluid_contents() for fluid_name, count in pairs(inv) do local i = #signals + 1 - signals[i] = { index = i, signal = { type = "fluid", name = fluid_name }, count = sign * floor(count) } + signals[i] = {index = i, signal = {type = "fluid", name = fluid_name}, count = sign*floor(count)} end set_combinator_output(map_data, comb, signals) end end end + ---@param map_data MapData ---@param refueler Refueler ---@param train Train @@ -391,7 +379,7 @@ function set_refueler_combs(map_data, refueler, train) name = a.name end if game.item_prototypes[name] then - wagon_signals[1] = { index = 1, signal = { type = "item", name = a.name }, count = 1 } + wagon_signals[1] = {index = 1, signal = {type = "item", name = a.name}, count = 1} end end end @@ -400,14 +388,10 @@ function set_refueler_combs(map_data, refueler, train) if stack.valid_for_read then if comb then local i = #wagon_signals + 1 - wagon_signals[i] = { - index = i, - signal = { type = "item", name = stack.name }, - count = stack.count - } + wagon_signals[i] = {index = i, signal = {type = "item", name = stack.name}, count = stack.count} end local j = #signals + 1 - signals[j] = { index = j, signal = { type = "item", name = stack.name }, count = stack.count } + signals[j] = {index = j, signal = {type = "item", name = stack.name}, count = stack.count} end end if comb then @@ -419,6 +403,7 @@ function set_refueler_combs(map_data, refueler, train) set_combinator_output(map_data, refueler.entity_comb, signals) end + ---@param map_data MapData ---@param stop Station|Refueler function unset_wagon_combs(map_data, stop) @@ -436,7 +421,7 @@ function unset_wagon_combs(map_data, stop) end end -local type_filter = { "inserter", "pump", "arithmetic-combinator", "loader-1x1", "loader" } +local type_filter = {"inserter", "pump", "arithmetic-combinator", "loader-1x1"} ---@param map_data MapData ---@param stop Station|Refueler ---@param is_station_or_refueler boolean @@ -465,20 +450,20 @@ function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_ent local area_delta local is_ver if stop_direction == defines.direction.north then - search_area = { { middle_x - reach, middle_y }, { middle_x + reach, middle_y + 6 } } - area_delta = { 0, 7 } + search_area = {{middle_x - reach, middle_y}, {middle_x + reach, middle_y + 6}} + area_delta = {0, 7} is_ver = true elseif stop_direction == defines.direction.east then - search_area = { { middle_x - 6, middle_y - reach }, { middle_x, middle_y + reach } } - area_delta = { -7, 0 } + search_area = {{middle_x - 6, middle_y - reach}, {middle_x, middle_y + reach}} + area_delta = {-7, 0} is_ver = false elseif stop_direction == defines.direction.south then - search_area = { { middle_x - reach, middle_y - 6 }, { middle_x + reach, middle_y } } - area_delta = { 0, -7 } + search_area = {{middle_x - reach, middle_y - 6}, {middle_x + reach, middle_y}} + area_delta = {0, -7} is_ver = true elseif stop_direction == defines.direction.west then - search_area = { { middle_x, middle_y - reach }, { middle_x + 6, middle_y + reach } } - area_delta = { 7, 0 } + search_area = {{middle_x, middle_y - reach}, {middle_x + 6, middle_y + reach}} + area_delta = {7, 0} is_ver = false else assert(false, "cybersyn: invalid stop direction") @@ -486,12 +471,11 @@ function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_ent local length = 1 ---@type LuaEntity? local pre_rail = stop_rail - local layout_pattern = { 0 } + local layout_pattern = {0} local wagon_number = 0 for i = 1, 112 do if pre_rail then - local rail, rail_direction, rail_connection_direction = pre_rail.get_connected_rail({ - rail_direction = rail_direction_from_stop, rail_connection_direction = defines_straight }) + local rail, rail_direction, rail_connection_direction = pre_rail.get_connected_rail({rail_direction = rail_direction_from_stop, rail_connection_direction = defines_straight}) if not rail or rail_connection_direction ~= defines_straight then -- There is a curved rail or break in the tracks at this point -- We are assuming it's a curved rail, maybe that's a bad assumption @@ -559,7 +543,7 @@ function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_ent end end end - elseif entity.type == "loader-1x1" or entity.type == "loader" then + elseif entity.type == "loader-1x1" then if not supports_cargo then local direction = entity.direction if is_ver then @@ -643,7 +627,7 @@ end ---@param forbidden_entity LuaEntity? ---@param force boolean? local function resolve_update_stop_from_rail(map_data, entity, forbidden_entity, force) - local id = entity.unit_number --[[@as uint]] + local id = entity.unit_number--[[@as uint]] local is_station = true ---@type Station|Refueler local stop = map_data.stations[id] @@ -677,10 +661,7 @@ function update_stop_from_rail(map_data, rail, forbidden_entity, force) resolve_update_stop_from_rail(map_data, entity, forbidden_entity, force) return end - rail_back = rail_back.get_connected_rail({ - rail_direction = defines_back, - rail_connection_direction = defines_straight - }) + rail_back = rail_back.get_connected_rail({rail_direction = defines_back, rail_connection_direction = defines_straight}) end if rail_front then local entity = rail_front.get_rail_segment_entity(defines_front, false) @@ -688,10 +669,7 @@ function update_stop_from_rail(map_data, rail, forbidden_entity, force) resolve_update_stop_from_rail(map_data, entity, forbidden_entity, force) return end - rail_front = rail_front.get_connected_rail({ - rail_direction = defines_front, - rail_connection_direction = defines_straight - }) + rail_front = rail_front.get_connected_rail({rail_direction = defines_front, rail_connection_direction = defines_straight}) end end end @@ -704,7 +682,6 @@ function update_stop_from_pump(map_data, pump, forbidden_entity) update_stop_from_rail(map_data, pump.pump_rail_target, forbidden_entity) end end - ---@param map_data MapData ---@param inserter LuaEntity ---@param forbidden_entity LuaEntity? @@ -736,10 +713,10 @@ function update_stop_from_inserter(map_data, inserter, forbidden_entity) end -- We need to check secondary positions because of weird modded inserters. -- Mostly because of miniloaders not aligning with the hitbox of a rail by default. - pos1.x = pos1.x + 0.2 * (pos1.x - pos0.x) - pos1.y = pos1.y + 0.2 * (pos1.y - pos0.y) - pos2.x = pos2.x + 0.2 * (pos2.x - pos0.x) - pos2.y = pos2.y + 0.2 * (pos2.y - pos0.y) + pos1.x = pos1.x + 0.2*(pos1.x - pos0.x) + pos1.y = pos1.y + 0.2*(pos1.y - pos0.y) + pos2.x = pos2.x + 0.2*(pos2.x - pos0.x) + pos2.y = pos2.y + 0.2*(pos2.y - pos0.y) rails = surface.find_entities_filtered({ type = search_type, position = pos1, @@ -755,7 +732,6 @@ function update_stop_from_inserter(map_data, inserter, forbidden_entity) update_stop_from_rail(map_data, rails[1], forbidden_entity) end end - ---@param map_data MapData ---@param loader LuaEntity ---@param forbidden_entity LuaEntity? @@ -765,7 +741,7 @@ function update_stop_from_loader(map_data, loader, forbidden_entity) local loader_type = loader.loader_type local position = loader.position --check input/output direction and loader position, and case position and modify x or y by +/- 1 for search - if loader_type == "input" then --loading train + if loader_type == "input" then --loading train if direction == defines.direction.east then position.x = position.x + 1 -- input and facing east -> move on X axis 1 to the right elseif direction == defines.direction.south then From 197614d4e1ad77739f1c70b418b4c433a716d287 Mon Sep 17 00:00:00 2001 From: Gillett Hernandez Date: Sun, 1 Oct 2023 17:35:39 -0700 Subject: [PATCH 23/29] isolate and reapply non-whitespace change --- cybersyn/scripts/layout.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cybersyn/scripts/layout.lua b/cybersyn/scripts/layout.lua index 46b82b1..bfdea45 100644 --- a/cybersyn/scripts/layout.lua +++ b/cybersyn/scripts/layout.lua @@ -421,7 +421,7 @@ function unset_wagon_combs(map_data, stop) end end -local type_filter = {"inserter", "pump", "arithmetic-combinator", "loader-1x1"} +local type_filter = {"inserter", "pump", "arithmetic-combinator", "loader-1x1", "loader"} ---@param map_data MapData ---@param stop Station|Refueler ---@param is_station_or_refueler boolean @@ -543,7 +543,7 @@ function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_ent end end end - elseif entity.type == "loader-1x1" then + elseif entity.type == "loader-1x1" or entity.type == "loader" then if not supports_cargo then local direction = entity.direction if is_ver then From 50edbd9fb1215194eda910e381aac6199ad37e76 Mon Sep 17 00:00:00 2001 From: Monica Moniot Date: Tue, 10 Oct 2023 17:47:22 -0400 Subject: [PATCH 24/29] Revert "Added missing provider message" --- cybersyn/locale/en/base.cfg | 1 - cybersyn/scripts/central-planning.lua | 4 +--- cybersyn/scripts/factorio-api.lua | 11 ----------- cybersyn/scripts/remote-interface.lua | 1 - 4 files changed, 1 insertion(+), 16 deletions(-) diff --git a/cybersyn/locale/en/base.cfg b/cybersyn/locale/en/base.cfg index 41dac51..dbba4ea 100644 --- a/cybersyn/locale/en/base.cfg +++ b/cybersyn/locale/en/base.cfg @@ -67,7 +67,6 @@ depot-broken=A train is lost because its depot was broken refueler-broken=A train is lost because its refueler was broken station-broken=A train is lost because one of its delivery stations was broken train-at-incorrect=A train parked at a station it was not scheduled to delivered to -missing-provider=Could not find a station providing __1__ to make a delivery to __2__ missing-train=Could not find any train on the correct network to make a delivery from __2__ to __1__ no-train-has-capacity=Could not find a train with enough cargo capacity to make a delivery from __2__ to __1__ no-train-matches-r-layout=Could not find a train on the allow-list of __1__ to make a delivery diff --git a/cybersyn/scripts/central-planning.lua b/cybersyn/scripts/central-planning.lua index 926d0dd..55fee92 100644 --- a/cybersyn/scripts/central-planning.lua +++ b/cybersyn/scripts/central-planning.lua @@ -498,9 +498,7 @@ local function tick_dispatch(map_data, mod_settings) create_delivery(map_data, r_station_id, p_station_id, best_train_id, manifest) return false else - if correctness == 0 then - send_alert_missing_provider(item_name, r_station.entity_stop) - elseif correctness == 1 then + if correctness == 1 then send_alert_missing_train(r_station.entity_stop, closest_to_correct_p_station.entity_stop) elseif correctness == 2 then send_alert_no_train_has_capacity(r_station.entity_stop, closest_to_correct_p_station.entity_stop) diff --git a/cybersyn/scripts/factorio-api.lua b/cybersyn/scripts/factorio-api.lua index 44b2f18..cf78fc0 100644 --- a/cybersyn/scripts/factorio-api.lua +++ b/cybersyn/scripts/factorio-api.lua @@ -776,17 +776,6 @@ function send_alert_sounds(train) end ----@param item_name string ----@param r_stop LuaEntity -function send_alert_missing_provider(item_name, r_stop) - for _, player in pairs(r_stop.force.players) do - player.add_custom_alert( - r_stop, - send_alert_about_missing_train_icon, - {"cybersyn-messages.missing-provider", item_name, r_stop.backer_name}, - true) - end -end ---@param r_stop LuaEntity ---@param p_stop LuaEntity function send_alert_missing_train(r_stop, p_stop) diff --git a/cybersyn/scripts/remote-interface.lua b/cybersyn/scripts/remote-interface.lua index 9985750..efaa420 100644 --- a/cybersyn/scripts/remote-interface.lua +++ b/cybersyn/scripts/remote-interface.lua @@ -353,7 +353,6 @@ interface.add_refueler_schedule = add_refueler_schedule --[[alerts]] ------------------------------------------------------------------ -interface.send_alert_missing_provider = send_alert_missing_provider interface.send_alert_missing_train = send_alert_missing_train interface.send_alert_unexpected_train = send_alert_unexpected_train interface.send_alert_nonempty_train_in_depot = send_alert_nonempty_train_in_depot From 4620b6c5f744238e1b677f9d134089bd7fe74742 Mon Sep 17 00:00:00 2001 From: Monica Moniot Date: Tue, 10 Oct 2023 18:06:47 -0400 Subject: [PATCH 25/29] updated changelog --- cybersyn/changelog.txt | 10 ++++++---- cybersyn/info.lua | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cybersyn/changelog.txt b/cybersyn/changelog.txt index 8adddaf..4dba533 100644 --- a/cybersyn/changelog.txt +++ b/cybersyn/changelog.txt @@ -1,15 +1,17 @@ --------------------------------------------------------------------------------------------------- Version: 1.3.0 -Date: 2023-9-24 +Date: 2023-10-10 Features: - - Added an alert when no provider is found for an item, indicating a bottleneck in your factory - contributed by FinalFrag + - Added improved combinator display sprites - contributed by jagoly - The manager gui now displays control signals - contributed by Shadowvoices - The manager gui now excludes requests that do not exceed the request threshold - contributed by Shadowvoices Bugfixes: - Fixed a crash when clicking on a combinator when the GUI is open - contributed by PeteyPii - - Fixed a crash when setting a combinator to depot mode without a network - contributed by download13 - - Fixed a crash when opening the manager when adding cybersyn to an existing save - contributed by Mjonir + - Fixed a crash when setting a combinator to depot mode without a network - contributed by download13 and TheXIFC - Stations with provider item thresholds can no longer generate empty train orders - contributed by svr8450 + - Added missing loader entity type to the automatic allow-list - contributed by gillett-hernandez + - Fixed a crash when opening the manager when adding cybersyn to an existing save - contributed by Mjonir + - Fixed a crash when enabling the manager on an existing save - contributed by freyacodes Translation: - Swedish language added - contributed by Sharparam - Chinese language update - contributed by luaotix diff --git a/cybersyn/info.lua b/cybersyn/info.lua index 67b1327..860f838 100644 --- a/cybersyn/info.lua +++ b/cybersyn/info.lua @@ -3,4 +3,4 @@ --- It is used in migrations.lua to determine if any migrations need to be run for beta testers. --- It is expected these are only meaningful between releases during beta testing. --- It should be set to nil for any release version. -return 0 +return 1 From f0b866540319a49d7b8cd7780475e467022b4bbe Mon Sep 17 00:00:00 2001 From: Monica Moniot Date: Tue, 10 Oct 2023 19:33:33 -0400 Subject: [PATCH 26/29] created a clean fix for combinator_update --- cybersyn/changelog.txt | 1 + cybersyn/scripts/main.lua | 200 ++++++++++++++++++++++---------------- 2 files changed, 115 insertions(+), 86 deletions(-) diff --git a/cybersyn/changelog.txt b/cybersyn/changelog.txt index 4dba533..02d58ee 100644 --- a/cybersyn/changelog.txt +++ b/cybersyn/changelog.txt @@ -10,6 +10,7 @@ Date: 2023-10-10 - Fixed a crash when setting a combinator to depot mode without a network - contributed by download13 and TheXIFC - Stations with provider item thresholds can no longer generate empty train orders - contributed by svr8450 - Added missing loader entity type to the automatic allow-list - contributed by gillett-hernandez + - Fixed a case where combinator changes not being applied for depots and refuelers - contributed by jagoly - Fixed a crash when opening the manager when adding cybersyn to an existing save - contributed by Mjonir - Fixed a crash when enabling the manager on an existing save - contributed by freyacodes Translation: diff --git a/cybersyn/scripts/main.lua b/cybersyn/scripts/main.lua index 978893d..50db145 100644 --- a/cybersyn/scripts/main.lua +++ b/cybersyn/scripts/main.lua @@ -285,10 +285,11 @@ local function on_combinator_built(map_data, comb) control.parameters = params end - map_data.to_comb[comb.unit_number] = comb - map_data.to_comb_params[comb.unit_number] = params - map_data.to_output[comb.unit_number] = out - map_data.to_stop[comb.unit_number] = stop + local unit_number = comb.unit_number--[[@as uint]] + map_data.to_comb[unit_number] = comb + map_data.to_comb_params[unit_number] = params + map_data.to_output[unit_number] = out + map_data.to_stop[unit_number] = stop if op == MODE_WAGON then if rail then @@ -328,6 +329,48 @@ local function on_combinator_built(map_data, comb) end end end + +---@param map_data MapData +---@param comb LuaEntity +---@param unit_number uint +---@return uint, uint, Station|Depot|Refueler|nil, LuaEntity? +--Returns the internal entity associated with the given combinator, if one exists. +--`unit_number` must be equal to `comb.unit_number`. +--Returns 1 if `comb` is `entity_comb1` of a station. +--Returns 2 if `comb` is `entity_comb2` of a station. +--Returns 3 if `comb` defines a depot. +--Returns 4 if `comb` defines a refueler. +--Returns 0 if `comb` is not a core component of any entity. +local function comb_to_internal_entity(map_data, comb, unit_number) + local stop = map_data.to_stop[unit_number] + if stop and stop.valid then + local id = stop.unit_number--[[@as uint]] + local station = map_data.stations[id] + if station then + if station.entity_comb1 == comb then + return 1, id, station, stop + elseif station.entity_comb2 == comb then + return 2, id, station, stop + end + else + local depot = map_data.depots[id] + if depot then + if depot.entity_comb == comb then + return 3, id, depot, stop + end + else + local refueler = map_data.refuelers[id] + if refueler then + if refueler.entity_comb == comb then + return 4, id, refueler, stop + end + end + end + end + end + return 0, 0, nil, nil +end + ---@param map_data MapData ---@param comb LuaEntity function on_combinator_broken(map_data, comb) @@ -335,33 +378,20 @@ function on_combinator_broken(map_data, comb) ---@type uint local comb_id = comb.unit_number local out = map_data.to_output[comb_id] - local stop = map_data.to_stop[comb_id] - if stop and stop.valid then - local id = stop.unit_number--[[@as uint]] - local station = map_data.stations[id] - if station then - if station.entity_comb1 == comb then - on_station_broken(map_data, id, station) - on_stop_built_or_updated(map_data, stop, comb) - elseif station.entity_comb2 == comb then - station.entity_comb2 = search_for_station_combinator(map_data, stop, MODE_SECONDARY_IO, comb) - end - else - local depot = map_data.depots[id] - if depot then - if depot.entity_comb == comb then - on_depot_broken(map_data, id, depot) - on_stop_built_or_updated(map_data, stop, comb) - end - else - local refueler = map_data.refuelers[id] - if refueler and refueler.entity_comb == comb then - on_refueler_broken(map_data, id, refueler) - on_stop_built_or_updated(map_data, stop, comb) - end - end - end + local type, id, entity, stop = comb_to_internal_entity(map_data, comb, comb_id) + if type == 1 then + on_station_broken(map_data, id, entity--[[@as Station]]) + on_stop_built_or_updated(map_data, stop--[[@as LuaEntity]], comb) + elseif type == 2 then + local station = entity--[[@as Station]] + station.entity_comb2 = search_for_station_combinator(map_data, stop--[[@as LuaEntity]], MODE_SECONDARY_IO, comb) + elseif type == 3 then + on_depot_broken(map_data, id, entity--[[@as Depot]]) + on_stop_built_or_updated(map_data, stop--[[@as LuaEntity]], comb) + elseif type == 4 then + on_refueler_broken(map_data, id, entity--[[@as Refueler]]) + on_stop_built_or_updated(map_data, stop--[[@as LuaEntity]], comb) end if out and out.valid then @@ -382,22 +412,20 @@ function combinator_update(map_data, comb, reset_display) local params = control.parameters local old_params = map_data.to_comb_params[unit_number] local has_changed = false - local station = nil - local id = nil + local type, id, entity = nil, nil, nil - - if params.operation == MODE_PRIMARY_IO_ACTIVE or params.operation == MODE_PRIMARY_IO_FAILED_REQUEST or params.operation == MODE_PRIMARY_IO then + local op = params.operation + local is_mode_primary_io = op == MODE_PRIMARY_IO + --handle the combinator's display, if it is part of a station + if is_mode_primary_io or op == MODE_PRIMARY_IO_ACTIVE or op == MODE_PRIMARY_IO_FAILED_REQUEST then --the follow is only present to fix combinators that have been copy-pasted by blueprint with the wrong operation - local stop = map_data.to_stop[comb.unit_number--[[@as uint]]] - local should_reset = reset_display - if stop then - id = stop.unit_number--[[@as uint]] - station = map_data.stations[id] - if station and station.entity_comb1 ~= comb then - station = nil - end - if should_reset and station then - --make sure only MODE_PRIMARY_IO gets stored on map_data.to_comb_params + local params_op_wasnt_set = true + + if reset_display then + type, id, entity = comb_to_internal_entity(map_data, comb, unit_number) + + if type == 1 then + local station = entity--[[@as Station]] if station.display_state == 0 then params.operation = MODE_PRIMARY_IO elseif station.display_state%2 == 1 then @@ -405,16 +433,17 @@ function combinator_update(map_data, comb, reset_display) else params.operation = MODE_PRIMARY_IO_FAILED_REQUEST end + params_op_wasnt_set = false control.parameters = params - should_reset = false end end - if should_reset then + --make sure only MODE_PRIMARY_IO gets stored on map_data.to_comb_params + if params_op_wasnt_set and not is_mode_primary_io then params.operation = MODE_PRIMARY_IO control.parameters = params end - params.operation = MODE_PRIMARY_IO end + if params.operation ~= old_params.operation then --NOTE: This is rather dangerous, we may need to actually implement operation changing on_combinator_broken(map_data, comb) @@ -422,6 +451,7 @@ function combinator_update(map_data, comb, reset_display) interface_raise_combinator_changed(comb, old_params) return end + local new_signal = params.first_signal local old_signal = old_params.first_signal local new_network = new_signal and new_signal.name or nil @@ -429,54 +459,52 @@ function combinator_update(map_data, comb, reset_display) if new_network ~= old_network then has_changed = true - local stop = map_data.to_stop[comb.unit_number] - if stop and stop.valid then - if station then - --NOTE: these updates have to be queued to occur at tick init since central planning is expecting them not to change between ticks - if not map_data.queue_station_update then - map_data.queue_station_update = {} - end - map_data.queue_station_update[id] = true - else - local depot = map_data.depots[id] - if depot then - if depot.entity_comb == comb then - local train_id = depot.available_train_id - if train_id then - local train = map_data.trains[train_id] - remove_available_train(map_data, train_id, train) - add_available_train_to_depot(map_data, mod_settings, train_id, train, id, depot) - interface_raise_train_status_changed(train_id, STATUS_D, STATUS_D) - end - end - else - local refueler = map_data.refuelers[id] - if refueler and refueler.entity_comb == comb then - set_refueler_from_comb(map_data, mod_settings, id, refueler) - end - end - end + if type == nil then + type, id, entity = comb_to_internal_entity(map_data, comb, unit_number) end - end - if params.second_constant ~= old_params.second_constant then - has_changed = true - if station then + if type == 1 or type == 2 then --NOTE: these updates have to be queued to occur at tick init since central planning is expecting them not to change between ticks if not map_data.queue_station_update then map_data.queue_station_update = {} end map_data.queue_station_update[id] = true - else - local refueler = map_data.refuelers[id] - if refueler then - local pre = refueler.allows_all_trains - set_refueler_from_comb(map_data, mod_settings, id, refueler) - if refueler.allows_all_trains ~= pre then - update_stop_if_auto(map_data, refueler, false) - end + elseif type == 3 then + local depot = entity--[[@as Depot]] + local train_id = depot.available_train_id + if train_id then + local train = map_data.trains[train_id] + remove_available_train(map_data, train_id, train) + add_available_train_to_depot(map_data, mod_settings, train_id, train, id, depot) + interface_raise_train_status_changed(train_id, STATUS_D, STATUS_D) + end + elseif type == 4 then + set_refueler_from_comb(map_data, mod_settings, id, entity--[[@as Refueler]]) + end + end + + if params.second_constant ~= old_params.second_constant then + has_changed = true + + if type == nil then + type, id, entity = comb_to_internal_entity(map_data, comb, unit_number) + end + --depots do not cache any combinator values so we don't have to update them here + if type == 1 or type == 2 then + --NOTE: these updates have to be queued to occur at tick init since central planning is expecting them not to change between ticks + if not map_data.queue_station_update then + map_data.queue_station_update = {} + end + map_data.queue_station_update[id] = true + elseif type == 4 then + local refueler = entity--[[@as Refueler]] + local pre = refueler.allows_all_trains + set_refueler_from_comb(map_data, mod_settings, id, refueler) + if refueler.allows_all_trains ~= pre then + update_stop_if_auto(map_data, refueler, false) end end end + if has_changed then map_data.to_comb_params[unit_number] = params interface_raise_combinator_changed(comb, old_params) From 3bac74cff73c76155b2f18860c63f7bd76453c6c Mon Sep 17 00:00:00 2001 From: Monica Moniot Date: Tue, 10 Oct 2023 20:05:37 -0400 Subject: [PATCH 27/29] made minor improvements --- cybersyn/changelog.txt | 1 + cybersyn/scripts/central-planning.lua | 43 ++++++++++++++------------- cybersyn/scripts/global.lua | 1 + cybersyn/scripts/layout.lua | 2 +- cybersyn/scripts/main.lua | 4 +-- 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/cybersyn/changelog.txt b/cybersyn/changelog.txt index 02d58ee..82b2e00 100644 --- a/cybersyn/changelog.txt +++ b/cybersyn/changelog.txt @@ -11,6 +11,7 @@ Date: 2023-10-10 - Stations with provider item thresholds can no longer generate empty train orders - contributed by svr8450 - Added missing loader entity type to the automatic allow-list - contributed by gillett-hernandez - Fixed a case where combinator changes not being applied for depots and refuelers - contributed by jagoly + - Fixed provide/request orders for the same item getting generated simultaneously - contributed by jagoly - Fixed a crash when opening the manager when adding cybersyn to an existing save - contributed by Mjonir - Fixed a crash when enabling the manager on an existing save - contributed by freyacodes Translation: diff --git a/cybersyn/scripts/central-planning.lua b/cybersyn/scripts/central-planning.lua index 2e52572..37d6617 100644 --- a/cybersyn/scripts/central-planning.lua +++ b/cybersyn/scripts/central-planning.lua @@ -287,6 +287,12 @@ local function tick_dispatch(map_data, mod_settings) goto continue end + --don't request when already providing + local item_deliveries = station.deliveries[item_name] + if item_deliveries and item_deliveries < 0 then + goto continue + end + local threshold = station.r_threshold local prior = station.priority local item_threshold = station.item_thresholds and station.item_thresholds[item_name] or nil @@ -300,16 +306,11 @@ local function tick_dispatch(map_data, mod_settings) goto continue end + --prioritize by last delivery time if priorities are equal if prior == best_r_prior and station.last_delivery_tick > best_timestamp then goto continue end - --don't request when already providing - local item_deliveries = station.deliveries[item_name] - if item_deliveries and item_deliveries < 0 then - goto continue - end - r_station_i = i r_threshold = threshold best_r_prior = prior @@ -362,6 +363,12 @@ local function tick_dispatch(map_data, mod_settings) goto p_continue end + --don't provide when already requesting + item_deliveries = p_station.deliveries[item_name] + if item_deliveries and item_deliveries > 0 then + goto p_continue + end + p_flag = get_network_mask(p_station, network_name) r_flag = get_network_mask(r_station, network_name) netand = band(p_flag, r_flag) @@ -489,12 +496,6 @@ local function tick_dispatch(map_data, mod_settings) goto p_continue end - --don't provide when already requesting - item_deliveries = p_station.deliveries[item_name] - if item_deliveries and item_deliveries > 0 then - goto p_continue - end - p_station_i = j best_train_id = best_p_train_id best_p_prior = p_prior @@ -510,14 +511,16 @@ local function tick_dispatch(map_data, mod_settings) create_delivery(map_data, r_station_id, p_station_id, best_train_id, manifest) return false else - if correctness == 1 then - send_alert_missing_train(r_station.entity_stop, closest_to_correct_p_station.entity_stop) - elseif correctness == 2 then - send_alert_no_train_has_capacity(r_station.entity_stop, closest_to_correct_p_station.entity_stop) - elseif correctness == 3 then - send_alert_no_train_matches_r_layout(r_station.entity_stop, closest_to_correct_p_station.entity_stop) - elseif correctness == 4 then - send_alert_no_train_matches_p_layout(r_station.entity_stop, closest_to_correct_p_station.entity_stop) + if closest_to_correct_p_station then + if correctness == 1 then + send_alert_missing_train(r_station.entity_stop, closest_to_correct_p_station.entity_stop) + elseif correctness == 2 then + send_alert_no_train_has_capacity(r_station.entity_stop, closest_to_correct_p_station.entity_stop) + elseif correctness == 3 then + send_alert_no_train_matches_r_layout(r_station.entity_stop, closest_to_correct_p_station.entity_stop) + elseif correctness == 4 then + send_alert_no_train_matches_p_layout(r_station.entity_stop, closest_to_correct_p_station.entity_stop) + end end if band(r_station.display_state, 2) == 0 then r_station.display_state = r_station.display_state + 2 diff --git a/cybersyn/scripts/global.lua b/cybersyn/scripts/global.lua index e50d3c9..69da833 100644 --- a/cybersyn/scripts/global.lua +++ b/cybersyn/scripts/global.lua @@ -131,6 +131,7 @@ ---@field public react_to_train_early_to_depot boolean --interface setting ---@field public enable_manager boolean ---@field public manager_ups double +---@field public manager_enabled boolean --if this is uncommented it means there are migrations to write diff --git a/cybersyn/scripts/layout.lua b/cybersyn/scripts/layout.lua index bfdea45..730fec7 100644 --- a/cybersyn/scripts/layout.lua +++ b/cybersyn/scripts/layout.lua @@ -215,7 +215,7 @@ function set_p_wagon_combs(map_data, station, train) if carriage.type == "cargo-wagon" then local inv = carriage.get_inventory(defines.inventory.cargo_wagon) if inv then - ---@type ConstantCombinatorParameters + ---@type ConstantCombinatorParameters[] local signals = {} local inv_filter_i = 1 diff --git a/cybersyn/scripts/main.lua b/cybersyn/scripts/main.lua index 50db145..badc983 100644 --- a/cybersyn/scripts/main.lua +++ b/cybersyn/scripts/main.lua @@ -115,7 +115,7 @@ end ---@param map_data MapData ---@param stop LuaEntity ---@param comb1 LuaEntity ----@param comb2 LuaEntity +---@param comb2 LuaEntity? local function on_station_built(map_data, stop, comb1, comb2) --NOTE: only place where new Station local station = { @@ -412,7 +412,7 @@ function combinator_update(map_data, comb, reset_display) local params = control.parameters local old_params = map_data.to_comb_params[unit_number] local has_changed = false - local type, id, entity = nil, nil, nil + local type, id, entity = nil, 0, nil local op = params.operation local is_mode_primary_io = op == MODE_PRIMARY_IO From adf4e128c31bd6486ac8a86d8202069515559b4c Mon Sep 17 00:00:00 2001 From: Monica Moniot Date: Tue, 10 Oct 2023 20:13:23 -0400 Subject: [PATCH 28/29] fixed minor bug --- cybersyn/scripts/main.lua | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cybersyn/scripts/main.lua b/cybersyn/scripts/main.lua index badc983..8951e2d 100644 --- a/cybersyn/scripts/main.lua +++ b/cybersyn/scripts/main.lua @@ -415,11 +415,10 @@ function combinator_update(map_data, comb, reset_display) local type, id, entity = nil, 0, nil local op = params.operation - local is_mode_primary_io = op == MODE_PRIMARY_IO --handle the combinator's display, if it is part of a station - if is_mode_primary_io or op == MODE_PRIMARY_IO_ACTIVE or op == MODE_PRIMARY_IO_FAILED_REQUEST then + if op == MODE_PRIMARY_IO or op == MODE_PRIMARY_IO_ACTIVE or op == MODE_PRIMARY_IO_FAILED_REQUEST then --the follow is only present to fix combinators that have been copy-pasted by blueprint with the wrong operation - local params_op_wasnt_set = true + local set_control_params = true if reset_display then type, id, entity = comb_to_internal_entity(map_data, comb, unit_number) @@ -433,13 +432,13 @@ function combinator_update(map_data, comb, reset_display) else params.operation = MODE_PRIMARY_IO_FAILED_REQUEST end - params_op_wasnt_set = false + set_control_params = false control.parameters = params end end --make sure only MODE_PRIMARY_IO gets stored on map_data.to_comb_params - if params_op_wasnt_set and not is_mode_primary_io then - params.operation = MODE_PRIMARY_IO + params.operation = MODE_PRIMARY_IO + if set_control_params then control.parameters = params end end From ccaec9b006fe87477f9bc03c725c42b63c17aaa2 Mon Sep 17 00:00:00 2001 From: Monica Moniot Date: Thu, 12 Oct 2023 08:52:45 -0400 Subject: [PATCH 29/29] prep for release --- cybersyn/changelog.txt | 2 +- cybersyn/info.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cybersyn/changelog.txt b/cybersyn/changelog.txt index 82b2e00..9526a0c 100644 --- a/cybersyn/changelog.txt +++ b/cybersyn/changelog.txt @@ -2,7 +2,7 @@ Version: 1.3.0 Date: 2023-10-10 Features: - - Added improved combinator display sprites - contributed by jagoly + - Added improved combinator display sprites (further improvements coming) - contributed by jagoly - The manager gui now displays control signals - contributed by Shadowvoices - The manager gui now excludes requests that do not exceed the request threshold - contributed by Shadowvoices Bugfixes: diff --git a/cybersyn/info.lua b/cybersyn/info.lua index 860f838..639a3a2 100644 --- a/cybersyn/info.lua +++ b/cybersyn/info.lua @@ -3,4 +3,4 @@ --- It is used in migrations.lua to determine if any migrations need to be run for beta testers. --- It is expected these are only meaningful between releases during beta testing. --- It should be set to nil for any release version. -return 1 +return nil