diff --git a/cybersyn/scripts/central-planning.lua b/cybersyn/scripts/central-planning.lua index 33863ca..4fb97d5 100644 --- a/cybersyn/scripts/central-planning.lua +++ b/cybersyn/scripts/central-planning.lua @@ -42,71 +42,93 @@ function create_delivery(map_data, r_station_id, p_station_id, train_id, manifes local train = map_data.trains[train_id] local depot = map_data.depots[train.depot_id] - local is_at_depot = remove_available_train(map_data, train_id, train) - --NOTE: we assume that the train is not being teleported at this time - --NOTE: set_manifest_schedule is allowed to cancel the delivery at the last second if applying the schedule to the train makes it lost - if set_manifest_schedule(map_data, train.entity, depot.entity_stop, not train.use_any_depot, p_station.entity_stop, p_station.enable_inactive, r_station.entity_stop, mod_settings.allow_cargo_in_depot and r_station.enable_inactive--[[@as boolean]], manifest, is_at_depot) then - local old_status = train.status - train.status = STATUS_TO_P - train.p_station_id = p_station_id - train.r_station_id = r_station_id - train.manifest = manifest - train.last_manifest_tick = map_data.total_ticks - - r_station.last_delivery_tick = map_data.total_ticks - p_station.last_delivery_tick = map_data.total_ticks - - r_station.deliveries_total = r_station.deliveries_total + 1 - p_station.deliveries_total = p_station.deliveries_total + 1 - - local r_is_each = r_station.network_name == NETWORK_EACH - local p_is_each = p_station.network_name == NETWORK_EACH - for item_i, item in ipairs(manifest) do - assert(item.count > 0, "main.lua error, transfer amount was not positive") - - r_station.deliveries[item.name] = (r_station.deliveries[item.name] or 0) + item.count - p_station.deliveries[item.name] = (p_station.deliveries[item.name] or 0) - item.count - - if item_i > 1 or r_is_each or p_is_each then - local f, a - if r_is_each then - f, a = pairs(r_station.network_flag--[[@as {[string]: int}]]) - if p_is_each then - for network_name, _ in f, a do - local item_network_name = network_name..":"..item.name - economy.all_r_stations[item_network_name] = nil - economy.all_p_stations[item_network_name] = nil - end - f, a = pairs(p_station.network_flag--[[@as {[string]: int}]]) - end - elseif p_is_each then - f, a = pairs(p_station.network_flag--[[@as {[string]: int}]]) - else - f, a = once, r_station.network_name - end - --prevent deliveries from being processed for these items until their stations are re-polled - --if we don't wait until they are repolled a duplicate delivery might be generated for stations that share inventories - for network_name, _ in f, a do - local item_network_name = network_name..":"..item.name - economy.all_r_stations[item_network_name] = nil - economy.all_p_stations[item_network_name] = nil - end - end + if not train.entity.valid then + on_train_broken(map_data, train_id, train) + interface_raise_train_dispatch_failed(train_id) + return + end + if not depot.entity_stop.valid then + on_depot_broken(map_data, train.depot_id, depot) + interface_raise_train_dispatch_failed(train_id) + return + end + if not p_station.entity_stop.valid then + on_station_broken(map_data, p_station_id, p_station) + interface_raise_train_dispatch_failed(train_id) + return + end + if not r_station.entity_stop.valid then + on_station_broken(map_data, r_station_id, r_station) + interface_raise_train_dispatch_failed(train_id) + return end - set_comb2(map_data, p_station) - set_comb2(map_data, r_station) + local is_at_depot = remove_available_train(map_data, train_id, train) + --NOTE: we assume that the train is not being teleported at this time + --NOTE: set_manifest_schedule is allowed to cancel the delivery at the last second if applying the schedule to the train makes it lost and is_at_depot == false + local r_enable_inactive = mod_settings.allow_cargo_in_depot and r_station.enable_inactive--[[@as boolean]] + if set_manifest_schedule(map_data, train.entity, depot.entity_stop, not train.use_any_depot, p_station.entity_stop, p_station.enable_inactive, r_station.entity_stop, r_enable_inactive, manifest, is_at_depot) then + local old_status = train.status + train.status = STATUS_TO_P + train.p_station_id = p_station_id + train.r_station_id = r_station_id + train.manifest = manifest + train.last_manifest_tick = map_data.total_ticks - p_station.display_state = 1 - update_display(map_data, p_station) - r_station.display_state = 1 - update_display(map_data, r_station) + r_station.last_delivery_tick = map_data.total_ticks + p_station.last_delivery_tick = map_data.total_ticks - interface_raise_train_status_changed(train_id, old_status, STATUS_TO_P) -else - interface_raise_train_dispatch_failed(train_id) -end + r_station.deliveries_total = r_station.deliveries_total + 1 + p_station.deliveries_total = p_station.deliveries_total + 1 + + local r_is_each = r_station.network_name == NETWORK_EACH + local p_is_each = p_station.network_name == NETWORK_EACH + for item_i, item in ipairs(manifest) do + assert(item.count > 0, "main.lua error, transfer amount was not positive") + + r_station.deliveries[item.name] = (r_station.deliveries[item.name] or 0) + item.count + p_station.deliveries[item.name] = (p_station.deliveries[item.name] or 0) - item.count + + if item_i > 1 or r_is_each or p_is_each then + local f, a + if r_is_each then + f, a = pairs(r_station.network_flag--[[@as {[string]: int}]]) + if p_is_each then + for network_name, _ in f, a do + local item_network_name = network_name..":"..item.name + economy.all_r_stations[item_network_name] = nil + economy.all_p_stations[item_network_name] = nil + end + f, a = pairs(p_station.network_flag--[[@as {[string]: int}]]) + end + elseif p_is_each then + f, a = pairs(p_station.network_flag--[[@as {[string]: int}]]) + else + f, a = once, r_station.network_name + end + --prevent deliveries from being processed for these items until their stations are re-polled + --if we don't wait until they are repolled a duplicate delivery might be generated for stations that share inventories + for network_name, _ in f, a do + local item_network_name = network_name..":"..item.name + economy.all_r_stations[item_network_name] = nil + economy.all_p_stations[item_network_name] = nil + end + end + end + + set_comb2(map_data, p_station) + set_comb2(map_data, r_station) + + p_station.display_state = 1 + update_display(map_data, p_station) + r_station.display_state = 1 + update_display(map_data, r_station) + + interface_raise_train_status_changed(train_id, old_status, STATUS_TO_P) + else + interface_raise_train_dispatch_failed(train_id) + end end ---@param map_data MapData ---@param r_station_id uint @@ -255,7 +277,7 @@ local function tick_dispatch(map_data, mod_settings) for i, id in ipairs(r_stations) do local station = stations[id] --NOTE: the station at r_station_id could have been deleted and reregistered since last poll, this check here prevents it from being processed for a delivery in that case - if not station or station.deliveries_total >= station.entity_stop.trains_limit then + if not station or station.deliveries_total >= station.trains_limit then goto continue end @@ -331,7 +353,7 @@ local function tick_dispatch(map_data, mod_settings) local p_station_id = p_stations[j] local p_station = stations[p_station_id] - if not p_station or p_station.deliveries_total >= p_station.entity_stop.trains_limit then + if not p_station or p_station.deliveries_total >= p_station.trains_limit then goto p_continue end @@ -403,7 +425,8 @@ local function tick_dispatch(map_data, mod_settings) end --check if path is shortest so we prioritize locality - local t_to_p_dist = get_stop_dist(train.entity.front_stock, p_station.entity_stop) - DEPOT_PRIORITY_MULT*train.priority + local t = get_any_train_entity(train.entity) + local t_to_p_dist = t and p_station.entity_stop.valid and (get_dist(t, p_station.entity_stop) - DEPOT_PRIORITY_MULT*train.priority) or INF if capacity == best_capacity and t_to_p_dist > best_t_to_p_dist then goto train_continue end @@ -443,7 +466,7 @@ local function tick_dispatch(map_data, mod_settings) goto p_continue end - best_p_dist = best_t_to_p_dist + get_stop_dist(p_station.entity_stop, r_station.entity_stop) + best_p_dist = p_station.entity_stop.valid and r_station.entity_stop.valid and (best_t_to_p_dist + get_dist(p_station.entity_stop, r_station.entity_stop)) or INF if p_prior == best_p_prior and best_p_dist > best_dist then goto p_continue end @@ -501,11 +524,7 @@ local function tick_poll_station(map_data, mod_settings) station_id = map_data.active_station_ids[tick_data.i] station = map_data.stations[station_id] if station then - if station_id == 70487 then - local i = 0 - end - --NOTE: polling trains_limit here is expensive and not strictly necessary but using it to early out saves more ups - if station.network_name and station.deliveries_total < station.entity_stop.trains_limit then + if station.network_name then break end else @@ -514,6 +533,12 @@ local function tick_poll_station(map_data, mod_settings) tick_data.i = tick_data.i - 1 end end + if station.entity_stop.valid and station.entity_comb1.valid and (not station.entity_comb2 or station.entity_comb2.valid) then + station.trains_limit = station.entity_stop.trains_limit + else + on_station_broken(map_data, station_id, station) + return false + end station.r_threshold = mod_settings.r_threshold station.priority = mod_settings.priority station.item_priority = nil @@ -673,13 +698,22 @@ function tick_poll_entities(map_data, mod_settings) local refueler_id, _ = next(map_data.each_refuelers, tick_data.last_refueler) tick_data.last_refueler = refueler_id if refueler_id then - set_refueler_from_comb(map_data, mod_settings, refueler_id) + local refueler = map_data.refuelers[refueler_id] + if refueler.entity_stop.valid and refueler.entity_comb.valid then + set_refueler_from_comb(map_data, mod_settings, refueler_id, refueler) + else + on_refueler_broken(map_data, refueler_id, refueler) + end end else local comb_id, comb = next(map_data.to_comb, tick_data.last_comb) tick_data.last_comb = comb_id - if comb and comb.valid then - combinator_update(map_data, comb, true) + if comb then + if comb.valid then + combinator_update(map_data, comb, true) + else + map_data.to_comb[comb_id] = nil + end end end end @@ -697,7 +731,11 @@ function tick_init(map_data, mod_settings) if station.last_delivery_tick + mod_settings.warmup_time*mod_settings.tps < map_data.total_ticks then map_data.active_station_ids[#map_data.active_station_ids + 1] = id map_data.warmup_station_ids[i] = nil - combinator_update(map_data, station.entity_comb1) + if station.entity_comb1.valid then + combinator_update(map_data, station.entity_comb1) + else + on_station_broken(map_data, id, station) + end end else map_data.warmup_station_ids[i] = nil @@ -708,9 +746,13 @@ function tick_init(map_data, mod_settings) local station = map_data.stations[id] if station then local pre = station.allows_all_trains - set_station_from_comb(station) - if station.allows_all_trains ~= pre then - update_stop_if_auto(map_data, station, true) + if station.entity_comb1.valid then + set_station_from_comb(station) + if station.allows_all_trains ~= pre then + update_stop_if_auto(map_data, station, true) + end + else + on_station_broken(map_data, id, station) end end end diff --git a/cybersyn/scripts/factorio-api.lua b/cybersyn/scripts/factorio-api.lua index 2f5e785..d8c0ab0 100644 --- a/cybersyn/scripts/factorio-api.lua +++ b/cybersyn/scripts/factorio-api.lua @@ -15,10 +15,10 @@ function get_stack_size(map_data, item_name) return game.item_prototypes[item_name].stack_size end - +---NOTE: does not check .valid ---@param entity0 LuaEntity ---@param entity1 LuaEntity -function get_stop_dist(entity0, entity1) +function get_dist(entity0, entity1) local surface0 = entity0.surface.index local surface1 = entity1.surface.index return (surface0 == surface1 and get_distance(entity0.position, entity1.position) or DIFFERENT_SURFACE_DISTANCE) @@ -41,7 +41,7 @@ end ---@param train LuaTrain function get_any_train_entity(train) - return train.front_stock or train.back_stock or train.carriages[1] + return train.valid and (train.front_stock or train.back_stock or train.carriages[1]) or nil end @@ -109,31 +109,37 @@ end ---@param train LuaTrain ---@param depot_name string function set_depot_schedule(train, depot_name) - train.schedule = {current = 1, records = {create_inactivity_order(depot_name)}} + if train.valid then + train.schedule = {current = 1, records = {create_inactivity_order(depot_name)}} + end end ---@param train LuaTrain function lock_train(train) - train.manual_mode = true + if train.valid then + train.manual_mode = true + end 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 + if train.valid then + 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 - record.wait_conditions = {{type = "inactivity", compare_type = "and", ticks = LOCK_TRAIN_TIME}} + train.manual_mode = true end - train.schedule = schedule else train.manual_mode = true end - else - train.manual_mode = true end end @@ -141,15 +147,17 @@ end ---@param stop LuaEntity ---@param old_name string function rename_manifest_schedule(train, stop, old_name) - local new_name = stop.backer_name - local schedule = train.schedule - if not schedule then return end - for i, record in ipairs(schedule.records) do - if record.station == old_name then - record.station = new_name + if train.valid then + local new_name = stop.backer_name + local schedule = train.schedule + if not schedule then return end + for i, record in ipairs(schedule.records) do + if record.station == old_name then + record.station = new_name + end end + train.schedule = schedule end - train.schedule = schedule end ---@param elevator_name string @@ -157,6 +165,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 +---NOTE: does not check .valid ---@param map_data MapData ---@param train LuaTrain ---@param depot_stop LuaEntity @@ -281,6 +290,7 @@ function set_manifest_schedule(map_data, train, depot_stop, same_depot, p_stop, return true end +---NOTE: does not check .valid ---@param map_data MapData ---@param train LuaTrain ---@param stop LuaEntity @@ -355,14 +365,8 @@ end function get_comb_params(comb) return comb.get_or_create_control_behavior().parameters--[[@as ArithmeticCombinatorParameters]] end ----@param comb LuaEntity -function get_comb_network_name(comb) - local params = get_comb_params(comb) - local signal = params.first_signal - - return signal and signal.name or nil -end +---NOTE: does not check .valid ---@param station Station function set_station_from_comb(station) --NOTE: this does nothing to update currently active deliveries @@ -387,6 +391,7 @@ function set_station_from_comb(station) station.network_flag = {} end end +---NOTE: does not check .valid ---@param mod_settings CybersynModSettings ---@param train Train ---@param comb LuaEntity @@ -437,9 +442,9 @@ end ---@param map_data MapData ---@param mod_settings CybersynModSettings ---@param id uint -function set_refueler_from_comb(map_data, mod_settings, id) +---@param refueler Refueler +function set_refueler_from_comb(map_data, mod_settings, id, refueler) --NOTE: this does nothing to update currently active deliveries - local refueler = map_data.refuelers[id] local params = get_comb_params(refueler.entity_comb) local bits = params.second_constant or 0 local signal = params.first_signal @@ -620,7 +625,6 @@ end ---@param station Station function get_signals(station) - --NOTE: the combinator must be valid, but checking for valid every time is too slow local comb1 = station.entity_comb1 local status1 = comb1.status ---@type Signal[]? @@ -693,7 +697,7 @@ end ---@param train LuaTrain function send_alert_sounds(train) - local loco = train.front_stock or train.back_stock + local loco = get_any_train_entity(train) if loco then for _, player in pairs(loco.force.players) do player.play_sound({path = ALERT_SOUND}) diff --git a/cybersyn/scripts/global.lua b/cybersyn/scripts/global.lua index f11e453..a0ad3b2 100644 --- a/cybersyn/scripts/global.lua +++ b/cybersyn/scripts/global.lua @@ -34,6 +34,7 @@ ---@field public allows_all_trains true? ---@field public deliveries_total int ---@field public last_delivery_tick int +---@field public trains_limit int --transient ---@field public priority int --transient ---@field public item_priority int? --transient ---@field public r_threshold int >= 0 --transient diff --git a/cybersyn/scripts/layout.lua b/cybersyn/scripts/layout.lua index a01c017..5c9497b 100644 --- a/cybersyn/scripts/layout.lua +++ b/cybersyn/scripts/layout.lua @@ -596,14 +596,15 @@ function update_stop_from_rail(map_data, rail, forbidden_entity, force) return end if entity.name == "train-stop" then - local id = entity.unit_number + local id = entity.unit_number--[[@as uint]] local is_station = true + ---@type Station|Refueler local stop = map_data.stations[id] if not stop then stop = map_data.refuelers[id] is_station = false end - if stop then + if stop and stop.entity_stop.valid then if force then reset_stop_layout(map_data, stop, is_station, forbidden_entity) elseif not stop.allows_all_trains then diff --git a/cybersyn/scripts/main.lua b/cybersyn/scripts/main.lua index 55ccc35..260fe76 100644 --- a/cybersyn/scripts/main.lua +++ b/cybersyn/scripts/main.lua @@ -21,17 +21,19 @@ end ---@param map_data MapData ---@param depot_id uint ---@param depot Depot -local function on_depot_broken(map_data, depot_id, depot) +function on_depot_broken(map_data, depot_id, depot) for train_id, train in pairs(map_data.trains) do if train.depot_id == depot_id then if train.use_any_depot then local e = get_any_train_entity(train.entity) - local stops = e.force.get_train_stops({name = depot.entity_stop.backer_name, surface = e.surface}) - for stop in rnext_consume, stops do - local new_depot_id = stop.unit_number - if map_data.depots[new_depot_id] then - train.depot_id = new_depot_id--[[@as uint]] - goto continue + if e then + local stops = e.force.get_train_stops({name = depot.entity_stop.backer_name, surface = e.surface}) + for stop in rnext_consume, stops do + local new_depot_id = stop.unit_number + if map_data.depots[new_depot_id] then + train.depot_id = new_depot_id--[[@as uint]] + goto continue + end end end end @@ -63,14 +65,14 @@ local function on_refueler_built(map_data, stop, comb) } local id = stop.unit_number--[[@as uint]] map_data.refuelers[id] = refueler - set_refueler_from_comb(map_data, mod_settings, id) + set_refueler_from_comb(map_data, mod_settings, id, refueler) update_stop_if_auto(map_data, refueler, false) interface_raise_refueler_created(id) end ---@param map_data MapData ---@param refueler_id uint ---@param refueler Refueler -local function on_refueler_broken(map_data, refueler_id, refueler) +function on_refueler_broken(map_data, refueler_id, refueler) if refueler.trains_total > 0 then --search for trains coming to the destroyed refueler for train_id, train in pairs(map_data.trains) do @@ -121,6 +123,7 @@ local function on_station_built(map_data, stop, comb1, comb2) --allows_all_trains = set_station_from_comb, deliveries_total = 0, last_delivery_tick = map_data.total_ticks, + trains_limit = math.huge, priority = 0, item_priotity = nil, r_threshold = 0, @@ -150,7 +153,7 @@ end ---@param map_data MapData ---@param station_id uint ---@param station Station -local function on_station_broken(map_data, station_id, station) +function on_station_broken(map_data, station_id, station) if station.deliveries_total > 0 then --search for trains coming to the destroyed station for train_id, train in pairs(map_data.trains) do @@ -430,7 +433,7 @@ function combinator_update(map_data, comb, reset_display) else local refueler = map_data.refuelers[id] if refueler and refueler.entity_comb == comb then - set_refueler_from_comb(map_data, mod_settings, id) + set_refueler_from_comb(map_data, mod_settings, id, refueler) end end end @@ -448,7 +451,7 @@ function combinator_update(map_data, comb, reset_display) local refueler = map_data.refuelers[id] if refueler then local pre = refueler.allows_all_trains - set_refueler_from_comb(map_data, mod_settings, id) + 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 @@ -757,19 +760,27 @@ local function setup_se_compat() if schedule then if train.status == STATUS_TO_P then local stop = map_data.stations[train.p_station_id].entity_stop - se_add_direct_to_station_order(schedule, stop, old_surface_index) + if stop.valid then + se_add_direct_to_station_order(schedule, stop, old_surface_index) + end end if train.status == STATUS_TO_P or train.status == STATUS_TO_R then local stop = map_data.stations[train.r_station_id].entity_stop - se_add_direct_to_station_order(schedule, stop, old_surface_index) + if stop.valid then + se_add_direct_to_station_order(schedule, stop, old_surface_index) + end end if train.status == STATUS_TO_F then local stop = map_data.refuelers[train.refueler_id].entity_stop - se_add_direct_to_station_order(schedule, stop, old_surface_index) + if stop.valid then + se_add_direct_to_station_order(schedule, stop, old_surface_index) + end end if not train.use_any_depot then - local depot = map_data.depots[train.depot_id] - se_add_direct_to_station_order(schedule, depot.entity_stop, old_surface_index) + local stop = map_data.depots[train.depot_id].entity_stop + if stop.valid then + se_add_direct_to_station_order(schedule, stop, old_surface_index) + end end train_entity.schedule = schedule end diff --git a/cybersyn/scripts/train-events.lua b/cybersyn/scripts/train-events.lua index 0103f22..4777677 100644 --- a/cybersyn/scripts/train-events.lua +++ b/cybersyn/scripts/train-events.lua @@ -34,18 +34,22 @@ function on_failed_delivery(map_data, train_id, train) local is_r_in_progress = is_p_in_progress or train.status == STATUS_TO_R or train.status == STATUS_R if is_p_in_progress then local station = map_data.stations[p_station_id] - remove_manifest(map_data, station, manifest, 1) - if train.status == STATUS_P then - set_comb1(map_data, station, nil) - unset_wagon_combs(map_data, station) + if station.entity_comb1.valid and (not station.entity_comb2 or station.entity_comb2.valid) then + remove_manifest(map_data, station, manifest, 1) + if train.status == STATUS_P then + set_comb1(map_data, station, nil) + unset_wagon_combs(map_data, station) + end end end if is_r_in_progress then local station = map_data.stations[r_station_id] - remove_manifest(map_data, station, manifest, -1) - if train.status == STATUS_R then - set_comb1(map_data, station, nil) - unset_wagon_combs(map_data, station) + if station.entity_comb1.valid and (not station.entity_comb2 or station.entity_comb2.valid) then + remove_manifest(map_data, station, manifest, -1) + if train.status == STATUS_R then + set_comb1(map_data, station, nil) + unset_wagon_combs(map_data, station) + end end end if train.has_filtered_wagon then @@ -100,7 +104,9 @@ end ---@param train Train function add_available_train_to_depot(map_data, mod_settings, train_id, train, depot_id, depot) local comb = depot.entity_comb - set_train_from_comb(mod_settings, train, comb) + if comb.valid then + set_train_from_comb(mod_settings, train, comb) + end depot.available_train_id = train_id train.depot_id = depot_id train.status = STATUS_D @@ -141,8 +147,9 @@ end ---@param map_data MapData ---@param depot_id uint +---@param depot Depot ---@param train_entity LuaTrain -local function on_train_arrives_depot(map_data, depot_id, train_entity) +local function on_train_arrives_depot(map_data, depot_id, depot, train_entity) local is_train_empty = next(train_entity.get_contents()) == nil and next(train_entity.get_fluid_contents()) == nil local train_id = train_entity.id local train = map_data.trains[train_id] @@ -161,7 +168,6 @@ local function on_train_arrives_depot(map_data, depot_id, train_entity) end if is_train_empty or mod_settings.allow_cargo_in_depot then local old_status = train.status - local depot = map_data.depots[depot_id] add_available_train_to_depot(map_data, mod_settings, train_id, train, depot_id, depot) set_depot_schedule(train_entity, depot.entity_stop.backer_name) interface_raise_train_status_changed(train_id, old_status, STATUS_D) @@ -194,7 +200,6 @@ local function on_train_arrives_depot(map_data, depot_id, train_entity) }--[[@as Train]] set_train_layout(map_data, train) map_data.trains[train_id] = train - local depot = map_data.depots[depot_id] add_available_train_to_depot(map_data, mod_settings, train_id, train, depot_id, depot) set_depot_schedule(train_entity, depot.entity_stop.backer_name) @@ -208,20 +213,18 @@ local function on_train_arrives_depot(map_data, depot_id, train_entity) end end ---@param map_data MapData ----@param station_id uint +---@param station Station ---@param train_id uint ---@param train Train -local function on_train_arrives_station(map_data, station_id, train_id, train) +local function on_train_arrives_station(map_data, station, train_id, train) ---@type uint if train.status == STATUS_TO_P then train.status = STATUS_P - local station = map_data.stations[station_id] set_comb1(map_data, station, train.manifest, mod_settings.invert_sign and 1 or -1) set_p_wagon_combs(map_data, station, train) interface_raise_train_status_changed(train_id, STATUS_TO_P, STATUS_P) elseif train.status == STATUS_TO_R then train.status = STATUS_R - local station = map_data.stations[station_id] set_comb1(map_data, station, train.manifest, mod_settings.invert_sign and -1 or 1) set_r_wagon_combs(map_data, station, train) interface_raise_train_status_changed(train_id, STATUS_TO_R, STATUS_R) @@ -229,12 +232,11 @@ local function on_train_arrives_station(map_data, station_id, train_id, train) end ---@param map_data MapData ----@param refueler_id uint +---@param refueler Refueler ---@param train_id uint ---@param train Train -local function on_train_arrives_refueler(map_data, refueler_id, train_id, train) +local function on_train_arrives_refueler(map_data, refueler, train_id, train) if train.status == STATUS_TO_F then - local refueler = map_data.refuelers[refueler_id] train.status = STATUS_F set_refueler_combs(map_data, refueler, train) interface_raise_train_status_changed(train_id, STATUS_TO_F, STATUS_F) @@ -319,21 +321,23 @@ local function on_train_leaves_stop(map_data, mod_settings, train_id, train) local best_prior = -INF for id, _ in pairs(refuelers) do local refueler = map_data.refuelers[id] - set_refueler_from_comb(map_data, mod_settings, id) + if not refueler.entity_stop.valid or not refueler.entity_comb.valid then + on_refueler_broken(map_data, id, refueler) + else + set_refueler_from_comb(map_data, mod_settings, id, refueler) - local refueler_network_flag = get_network_flag(refueler, network_name) - local train_network_flag = get_network_flag(train, network_name) - if btest(train_network_flag, refueler_network_flag) and (refueler.allows_all_trains or refueler.accepted_layouts[train.layout_id]) and refueler.trains_total < refueler.entity_stop.trains_limit then - local accepted = false - local dist = nil - if refueler.priority == best_prior then - dist = get_stop_dist(train.entity.front_stock, refueler.entity_stop) - accepted = dist < best_dist - end - if accepted or refueler.priority > best_prior then - best_refueler_id = id - best_dist = dist or get_stop_dist(train.entity.front_stock, refueler.entity_stop) - best_prior = refueler.priority + local refueler_network_flag = get_network_flag(refueler, network_name) + local train_network_flag = get_network_flag(train, network_name) + if btest(train_network_flag, refueler_network_flag) and (refueler.allows_all_trains or refueler.accepted_layouts[train.layout_id]) and refueler.trains_total < refueler.entity_stop.trains_limit then + if refueler.priority >= best_prior then + local t = get_any_train_entity(train.entity) + local dist = t and get_dist(t, refueler.entity_stop) or INF + if refueler.priority > best_prior or dist < best_dist then + best_refueler_id = id + best_dist = dist + best_prior = refueler.priority + end + end end end end @@ -358,7 +362,9 @@ local function on_train_leaves_stop(map_data, mod_settings, train_id, train) train.refueler_id = nil refueler.trains_total = refueler.trains_total - 1 unset_wagon_combs(map_data, refueler) - set_combinator_output(map_data, refueler.entity_comb, nil) + if refueler.entity_comb.valid then + set_combinator_output(map_data, refueler.entity_comb, nil) + end if not train.disable_bypass then train.status = STATUS_TO_D_BYPASS add_available_train(map_data, train_id, train) @@ -427,8 +433,13 @@ function on_train_changed(event) local stop = train_e.station if stop and stop.valid and stop.name == "train-stop" then local id = stop.unit_number--[[@as uint]] - if map_data.depots[id] then - on_train_arrives_depot(map_data, id, train_e) + local depot = map_data.depots[id] + if depot then + if depot.entity_comb.valid and depot.entity_stop.valid then + on_train_arrives_depot(map_data, id, depot, train_e) + else + on_depot_broken(map_data, id, depot) + end end else local train = map_data.trains[train_id] @@ -451,11 +462,13 @@ function on_train_changed(event) station = map_data.refuelers[id] is_station = false end - if id and station.entity_stop.connected_rail == rail then + if id and station.entity_stop.valid and station.entity_stop.connected_rail == rail then if is_station then - on_train_arrives_station(map_data, id, train_id, train) - else - on_train_arrives_refueler(map_data, id, train_id, train) + if station.entity_comb1 and (not station.entity_comb2 or station.entity_comb2.valid) then + on_train_arrives_station(map_data, station, train_id, train) + end + elseif station.entity_comb.valid then + on_train_arrives_refueler(map_data, station, train_id, train) end end end