From 3c80fd0df23b3a022f1e2a4407d473924144df62 Mon Sep 17 00:00:00 2001 From: mamoniot Date: Thu, 22 Dec 2022 23:25:03 -0500 Subject: [PATCH] improved alerts --- TODO | 3 - cybersyn/changelog.txt | 5 +- cybersyn/scripts/central-planning.lua | 11 +- cybersyn/scripts/constants.lua | 1 + cybersyn/scripts/factorio-api.lua | 183 +++++++++++++++++--------- cybersyn/scripts/global.lua | 1 + cybersyn/scripts/train-events.lua | 21 ++- 7 files changed, 147 insertions(+), 78 deletions(-) diff --git a/TODO b/TODO index d1bccb1..5e2b603 100644 --- a/TODO +++ b/TODO @@ -5,14 +5,11 @@ bugs: major: debug output - add request threshold provide override add in game guide move to an event based algorithm models & art add stack threshold setting allow "any" signal for network unions - Leave the train in automatic mode for at least a tick so that I can implement a memory cell to make an alert - Make the alert persistent instead of going away after 10 seconds minor: railloader compat diff --git a/cybersyn/changelog.txt b/cybersyn/changelog.txt index 3686b4a..f43521b 100644 --- a/cybersyn/changelog.txt +++ b/cybersyn/changelog.txt @@ -7,6 +7,8 @@ Date: 2022-12-22 - Forced provide stations to wait until they can service the highest priority request station - Added more detailed missing train alerts - Provide stations now override request thresholds with the per-item thresholds set by their station info combinator + - Nonempty trains in depot are no longer put in manual mode, instead they are forced to park at the depot + - Made several alerts persistent --------------------------------------------------------------------------------------------------- Version: 1.1.7 Date: 2022-12-17 @@ -53,8 +55,7 @@ Date: 2022-12-3 Changes: - Fixed a bug with SE compat preventing players from joining multiplayer games --------------------------------------------------------------------------------------------------- -Version: 1.0.8optional station -optional station +Version: 1.0.8 Changes: - Added depot bypass - Increased inactivity time so burner inserters are fast enough to trigger it diff --git a/cybersyn/scripts/central-planning.lua b/cybersyn/scripts/central-planning.lua index f84a790..d640a6e 100644 --- a/cybersyn/scripts/central-planning.lua +++ b/cybersyn/scripts/central-planning.lua @@ -49,7 +49,7 @@ function create_delivery(map_data, r_station_id, p_station_id, train_id, manifes train.parked_at_depot_id = nil end --NOTE: we assume that the train is not being teleported at this time - if set_manifest_schedule(train.entity, train.depot_name, train.se_depot_surface_i, p_station.entity_stop, r_station.entity_stop, manifest, depot_id ~= nil) then + if set_manifest_schedule(map_data, train.entity, train.depot_name, train.se_depot_surface_i, p_station.entity_stop, r_station.entity_stop, manifest, depot_id ~= nil) then local old_status = train.status train.status = STATUS_TO_P train.p_station_id = p_station_id @@ -567,7 +567,7 @@ local function tick_poll_train(map_data, mod_settings) if train and train.manifest and not train.se_is_being_teleported and train.last_manifest_tick + mod_settings.stuck_train_time*mod_settings.tps < map_data.total_ticks then if mod_settings.stuck_train_alert_enabled then - send_alert_stuck_train(train.entity, train.depot_name) + send_alert_stuck_train(map_data, train.entity) end interface_raise_train_stuck(train_id) end @@ -587,6 +587,13 @@ end ---@param mod_settings CybersynModSettings function tick(map_data, mod_settings) map_data.total_ticks = map_data.total_ticks + 1 + + if map_data.active_alerts then + if map_data.total_ticks%(10*mod_settings.tps) < 1 then + process_active_alerts(map_data) + end + end + if map_data.tick_state == STATE_INIT then map_data.economy.all_p_stations = {} map_data.economy.all_r_stations = {} diff --git a/cybersyn/scripts/constants.lua b/cybersyn/scripts/constants.lua index ee5eeb8..2d15ffd 100644 --- a/cybersyn/scripts/constants.lua +++ b/cybersyn/scripts/constants.lua @@ -24,6 +24,7 @@ MODE_REFUELER = ">>" NETWORK_SIGNAL_DEFAULT = {name="signal-A", type="virtual"} INACTIVITY_TIME = 100 +LOCK_TRAIN_TIME = 60*60*60*24*7 DELTA = 1/2048 diff --git a/cybersyn/scripts/factorio-api.lua b/cybersyn/scripts/factorio-api.lua index 06102e3..8fb9a1c 100644 --- a/cybersyn/scripts/factorio-api.lua +++ b/cybersyn/scripts/factorio-api.lua @@ -93,6 +93,26 @@ end function lock_train(train) train.manual_mode = true end +---@param train LuaTrain +function lock_train_to_depot(train) + local schedule = train.schedule + if schedule then + local record = schedule.records[schedule.current] + if record then + local wait = record.wait_conditions + if wait and wait[1] then + wait[1].ticks = LOCK_TRAIN_TIME + else + record.wait_conditions = {{type = "inactivity", compare_type = "and", ticks = LOCK_TRAIN_TIME}} + end + train.schedule = schedule + else + train.manual_mode = true + end + else + train.manual_mode = true + end +end ---@param train LuaTrain ---@param stop LuaEntity @@ -114,6 +134,7 @@ end function se_create_elevator_order(elevator_name, is_train_in_orbit) return {station = elevator_name..(is_train_in_orbit and SE_ELEVATOR_ORBIT_SUFFIX or SE_ELEVATOR_PLANET_SUFFIX)} end +---@param map_data MapData ---@param train LuaTrain ---@param depot_name string ---@param d_surface_i int @@ -121,7 +142,7 @@ end ---@param r_stop LuaEntity ---@param manifest Manifest ---@param start_at_depot boolean? -function set_manifest_schedule(train, depot_name, d_surface_i, p_stop, r_stop, manifest, start_at_depot) +function set_manifest_schedule(map_data, train, depot_name, d_surface_i, p_stop, r_stop, manifest, start_at_depot) --NOTE: can only return false if start_at_depot is false, it should be incredibly rare that this function returns false local old_schedule if not start_at_depot then @@ -137,13 +158,16 @@ function set_manifest_schedule(train, depot_name, d_surface_i, p_stop, r_stop, m local is_r_on_t = t_surface_i == r_surface_i local is_d_on_t = t_surface_i == d_surface_i if is_p_on_t and is_r_on_t and is_d_on_t then - train.schedule = {current = start_at_depot and 1 or 2--[[@as uint]], records = { - create_inactivity_order(depot_name), - create_direct_to_station_order(p_stop), - create_loading_order(p_stop, manifest), - create_direct_to_station_order(r_stop), - create_unloading_order(r_stop), - }} + train.schedule = { + current = start_at_depot and 1 or 2--[[@as uint]], + records = { + create_inactivity_order(depot_name), + create_direct_to_station_order(p_stop), + create_loading_order(p_stop, manifest), + create_direct_to_station_order(r_stop), + create_unloading_order(r_stop), + } + } if old_schedule and not train.has_path then train.schedule = old_schedule return false @@ -198,14 +222,14 @@ function set_manifest_schedule(train, depot_name, d_surface_i, p_stop, r_stop, m create_unloading_order(r_stop), }} lock_train(train) - send_alert_cannot_path_between_surfaces(train, depot_name) + send_alert_cannot_path_between_surfaces(map_data, train) return true end +---@param map_data MapData ---@param train LuaTrain ---@param stop LuaEntity ----@param depot_name string -function add_refueler_schedule(train, stop, depot_name) +function add_refueler_schedule(map_data, train, stop) local schedule = train.schedule or {current = 1, records = {}} local i = schedule.current if i == 1 then @@ -252,8 +276,8 @@ function add_refueler_schedule(train, stop, depot_name) --create an order that probably cannot be fulfilled and alert the player table_insert(schedule.records, i, create_inactivity_order(stop.backer_name)) lock_train(train) - send_alert_cannot_path_between_surfaces(train, depot_name) train.schedule = schedule + send_alert_cannot_path_between_surfaces(map_data, train) end @@ -459,15 +483,15 @@ end ---@param train LuaTrain ---@param icon {} ----@param message {} -local function send_alert_with_sound(train, icon, message) +---@param message string +local function send_alert_for_train(train, icon, message) local loco = train.front_stock or train.back_stock if loco then for _, player in pairs(loco.force.players) do player.add_custom_alert( loco, icon, - message, + {message}, true) player.play_sound({path = ALERT_SOUND}) end @@ -487,6 +511,16 @@ function send_alert_about_missing_train(r_stop, p_stop, message) end end +---@param train LuaTrain +function send_alert_sounds(train) + local loco = train.front_stock or train.back_stock + if loco then + for _, player in pairs(loco.force.players) do + player.play_sound({path = ALERT_SOUND}) + end + end +end + ---@param r_stop LuaEntity ---@param p_stop LuaEntity @@ -509,64 +543,85 @@ function send_alert_no_train_matches_p_layout(r_stop, p_stop) send_alert_about_missing_train(r_stop, p_stop, "cybersyn-messages.no-train-matches-p-layout") end -local send_lost_train_alert_icon = {name = LOST_TRAIN_NAME, type = "fluid"} + +local send_stuck_train_alert_icon = {name = LOST_TRAIN_NAME, type = "fluid"} +---@param map_data MapData ---@param train LuaTrain ----@param depot_name string -function send_alert_cannot_path_between_surfaces(train, depot_name) - send_alert_with_sound(train, send_lost_train_alert_icon, {"cybersyn-messages.cannot-path-between-surfaces", depot_name}) -end ----@param train LuaTrain ----@param depot_name string -function send_alert_depot_of_train_broken(train, depot_name) - send_alert_with_sound(train, send_lost_train_alert_icon, {"cybersyn-messages.depot-broken", depot_name}) -end ----@param train LuaTrain ----@param depot_name string -function send_alert_refueler_of_train_broken(train, depot_name) - send_alert_with_sound(train, send_lost_train_alert_icon, {"cybersyn-messages.refueler-broken", depot_name}) -end ----@param train LuaTrain ----@param depot_name string -function send_alert_station_of_train_broken(train, depot_name) - send_alert_with_sound(train, send_lost_train_alert_icon, {"cybersyn-messages.station-broken", depot_name}) -end ----@param train LuaTrain ----@param depot_name string -function send_alert_train_at_incorrect_station(train, depot_name) - send_alert_with_sound(train, send_lost_train_alert_icon, {"cybersyn-messages.train-at-incorrect", depot_name}) +function send_alert_stuck_train(map_data, train) + send_alert_for_train(train, send_stuck_train_alert_icon, "cybersyn-messages.stuck-train") + map_data.active_alerts = map_data.active_alerts or {} + map_data.active_alerts[train] = 1 end local send_nonempty_train_in_depot_alert_icon = {name = NONEMPTY_TRAIN_NAME, type = "fluid"} +---@param map_data MapData ---@param train LuaTrain -function send_alert_nonempty_train_in_depot(train) - send_alert_with_sound(train, send_nonempty_train_in_depot_alert_icon, {"cybersyn-messages.nonempty-train"}) +function send_alert_nonempty_train_in_depot(map_data, train) + send_alert_for_train(train, send_nonempty_train_in_depot_alert_icon, "cybersyn-messages.nonempty-train") + map_data.active_alerts = map_data.active_alerts or {} + map_data.active_alerts[train] = 2 +end + +local send_lost_train_alert_icon = {name = LOST_TRAIN_NAME, type = "fluid"} +---@param map_data MapData +---@param train LuaTrain +function send_alert_depot_of_train_broken(map_data, train) + send_alert_for_train(train, send_lost_train_alert_icon, "cybersyn-messages.depot-broken") + map_data.active_alerts = map_data.active_alerts or {} + map_data.active_alerts[train] = 3 +end +---@param map_data MapData +---@param train LuaTrain +function send_alert_station_of_train_broken(map_data, train) + send_alert_for_train(train, send_lost_train_alert_icon, "cybersyn-messages.station-broken") + map_data.active_alerts = map_data.active_alerts or {} + map_data.active_alerts[train] = 4 +end +---@param map_data MapData +---@param train LuaTrain +function send_alert_refueler_of_train_broken(map_data, train) + send_alert_for_train(train, send_lost_train_alert_icon, "cybersyn-messages.refueler-broken") + map_data.active_alerts = map_data.active_alerts or {} + map_data.active_alerts[train] = 5 +end +---@param map_data MapData +---@param train LuaTrain +function send_alert_train_at_incorrect_station(map_data, train) + send_alert_for_train(train, send_lost_train_alert_icon, "cybersyn-messages.train-at-incorrect") + map_data.active_alerts = map_data.active_alerts or {} + map_data.active_alerts[train] = 6 +end +---@param map_data MapData +---@param train LuaTrain +function send_alert_cannot_path_between_surfaces(map_data, train) + send_alert_for_train(train, send_lost_train_alert_icon, "cybersyn-messages.cannot-path-between-surfaces") + map_data.active_alerts = map_data.active_alerts or {} + map_data.active_alerts[train] = 7 end ---@param train LuaTrain function send_alert_unexpected_train(train) - local loco = train.front_stock or train.back_stock - if loco then - for _, player in pairs(loco.force.players) do - player.add_custom_alert( - loco, - send_lost_train_alert_icon, - {"cybersyn-messages.unexpected-train"}, - true) - end - end -end -local send_stuck_train_alert_icon = {name = LOST_TRAIN_NAME, type = "fluid"} ----@param train LuaTrain ----@param depot_name string -function send_alert_stuck_train(train, depot_name) - local loco = train.front_stock or train.back_stock - if loco then - for _, player in pairs(loco.force.players) do - player.add_custom_alert( - loco, - send_stuck_train_alert_icon, - {"cybersyn-messages.stuck-train", depot_name}, - true) + send_alert_for_train(train, send_lost_train_alert_icon, "cybersyn-messages.unexpected-train") +end + + +---@param map_data MapData +function process_active_alerts(map_data) + for train, id in pairs(map_data.active_alerts) do + if id == 1 then + send_alert_for_train(train, send_stuck_train_alert_icon, "cybersyn-messages.stuck-train") + elseif id == 2 then + send_alert_for_train(train, send_nonempty_train_in_depot_alert_icon, "cybersyn-messages.nonempty-train") + elseif id == 3 then + send_alert_for_train(train, send_lost_train_alert_icon, "cybersyn-messages.depot-broken") + elseif id == 4 then + send_alert_for_train(train, send_lost_train_alert_icon, "cybersyn-messages.station-broken") + elseif id == 5 then + send_alert_for_train(train, send_lost_train_alert_icon, "cybersyn-messages.refueler-broken") + elseif id == 6 then + send_alert_for_train(train, send_lost_train_alert_icon, "cybersyn-messages.train-at-incorrect") + elseif id == 7 then + send_alert_for_train(train, send_lost_train_alert_icon, "cybersyn-messages.cannot-path-between-surfaces") end end end diff --git a/cybersyn/scripts/global.lua b/cybersyn/scripts/global.lua index a9be46c..2acf3c7 100644 --- a/cybersyn/scripts/global.lua +++ b/cybersyn/scripts/global.lua @@ -19,6 +19,7 @@ ---@field public tick_state uint ---@field public tick_data {} ---@field public economy Economy +---@field public active_alerts {[LuaTrain]: int}? ---@field public se_tele_old_id {[string]: uint} ---@class Station diff --git a/cybersyn/scripts/train-events.lua b/cybersyn/scripts/train-events.lua index d78d478..a4141a3 100644 --- a/cybersyn/scripts/train-events.lua +++ b/cybersyn/scripts/train-events.lua @@ -167,9 +167,9 @@ local function on_train_arrives_depot(map_data, depot_id, train_entity) else --train still has cargo if mod_settings.react_to_nonempty_train_in_depot then - lock_train(train_entity) + lock_train_to_depot(train_entity) remove_train(map_data, train_id, train) - send_alert_nonempty_train_in_depot(train_entity) + send_alert_nonempty_train_in_depot(map_data, train_entity) end interface_raise_train_nonempty_in_depot(depot_id, train_entity, train_id) end @@ -201,8 +201,7 @@ local function on_train_arrives_depot(map_data, depot_id, train_entity) interface_raise_train_created(train_id, depot_id) else if mod_settings.react_to_nonempty_train_in_depot then - lock_train(train_entity) - send_alert_nonempty_train_in_depot(train_entity) + send_alert_nonempty_train_in_depot(map_data, train_entity) end interface_raise_train_nonempty_in_depot(depot_id, train_entity) end @@ -238,12 +237,12 @@ local function on_train_arrives_station(map_data, station_id, train_id, train) on_failed_delivery(map_data, train_id, train) remove_train(map_data, train_id, train) lock_train(train.entity) - send_alert_train_at_incorrect_station(train.entity, train.depot_name) + send_alert_train_at_incorrect_station(map_data, train.entity) end elseif mod_settings.react_to_train_at_incorrect_station then --train is lost somehow, probably from player intervention remove_train(map_data, train_id, train) - send_alert_train_at_incorrect_station(train.entity, train.depot_name) + send_alert_train_at_incorrect_station(map_data, train.entity) end end @@ -350,7 +349,7 @@ local function on_train_leaves_stop(map_data, mod_settings, train_id, train) train.refueler_id = best_refueler_id local refueler = map_data.refuelers[best_refueler_id] refueler.trains_total = refueler.trains_total + 1 - add_refueler_schedule(train.entity, refueler.entity_stop, train.depot_name) + add_refueler_schedule(map_data, train.entity, refueler.entity_stop) interface_raise_train_status_changed(train_id, STATUS_R, STATUS_TO_F) return end @@ -417,6 +416,14 @@ end function on_train_changed(event) local train_e = event.train--[[@as LuaTrain]] if not train_e.valid then return end + + if global.active_alerts and global.active_alerts[train_e] then + global.active_alerts[train_e] = nil + if next(global.active_alerts) == nil then + global.active_alerts = nil + end + end + local train_id = train_e.id if train_e.state == defines.train_state.wait_station then local stop = train_e.station