diff --git a/cybersyn/changelog.txt b/cybersyn/changelog.txt index 8adddaf..82b2e00 100644 --- a/cybersyn/changelog.txt +++ b/cybersyn/changelog.txt @@ -1,15 +1,19 @@ --------------------------------------------------------------------------------------------------- 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 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: - Swedish language added - contributed by Sharparam - Chinese language update - contributed by luaotix diff --git a/cybersyn/graphics/combinator/cybernetic-displays.png b/cybersyn/graphics/combinator/cybernetic-displays.png index 7d5d36a..97547c2 100644 Binary files a/cybersyn/graphics/combinator/cybernetic-displays.png and b/cybersyn/graphics/combinator/cybernetic-displays.png differ diff --git a/cybersyn/graphics/combinator/hr-cybernetic-displays.png b/cybersyn/graphics/combinator/hr-cybernetic-displays.png index 280cc00..17749ec 100644 Binary files a/cybersyn/graphics/combinator/hr-cybernetic-displays.png and b/cybersyn/graphics/combinator/hr-cybernetic-displays.png differ 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 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..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,6 +306,7 @@ 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 @@ -348,7 +355,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] @@ -356,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) @@ -498,16 +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 == 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) - 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/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/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/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 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) diff --git a/cybersyn/scripts/layout.lua b/cybersyn/scripts/layout.lua index 46b82b1..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 @@ -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 diff --git a/cybersyn/scripts/main.lua b/cybersyn/scripts/main.lua index 978893d..8951e2d 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 = { @@ -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,19 @@ 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, 0, 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 + --handle the combinator's display, if it is part of a station + 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 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 set_control_params = 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 +432,17 @@ function combinator_update(map_data, comb, reset_display) else params.operation = MODE_PRIMARY_IO_FAILED_REQUEST end + set_control_params = false control.parameters = params - should_reset = false end end - if should_reset then - params.operation = MODE_PRIMARY_IO + --make sure only MODE_PRIMARY_IO gets stored on map_data.to_comb_params + params.operation = MODE_PRIMARY_IO + if set_control_params then 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 +450,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 +458,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) 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 diff --git a/dev/hr-cybernetic-displays.xcf b/dev/hr-cybernetic-displays.xcf new file mode 100644 index 0000000..7286673 Binary files /dev/null and b/dev/hr-cybernetic-displays.xcf differ