diff --git a/cybersyn/scripts/global.lua b/cybersyn/scripts/global.lua index e193d68..d7de169 100644 --- a/cybersyn/scripts/global.lua +++ b/cybersyn/scripts/global.lua @@ -124,7 +124,6 @@ function init_global() global.layout_train_count = {} global.layout_top_id = 1 - IS_SE_PRESENT = remote.interfaces["space-exploration"] ~= nil if IS_SE_PRESENT then global.se_tele_old_id = {} end diff --git a/cybersyn/scripts/main.lua b/cybersyn/scripts/main.lua index 6386a1f..c2fb777 100644 --- a/cybersyn/scripts/main.lua +++ b/cybersyn/scripts/main.lua @@ -947,6 +947,98 @@ local function on_settings_changed(event) end end +local function setup_se_compat() + IS_SE_PRESENT = remote.interfaces["space-exploration"] ~= nil + if not IS_SE_PRESENT then return end + + local se_on_train_teleport_finished_event = remote.call("space-exploration", "get_on_train_teleport_finished_event") + local se_on_train_teleport_started_event = remote.call("space-exploration", "get_on_train_teleport_started_event") + + ---@param event {} + script.on_event(se_on_train_teleport_started_event, function(event) + ---@type MapData + local map_data = global + local old_id = event.old_train_id_1 + --NOTE: this is not guaranteed to be unique, it should be fine since the window of time for another train to mistakenly steal this train's event data is miniscule + --NOTE: please SE dev if you read this fix the issue where se_on_train_teleport_finished_event is returning the wrong old train id + local train_unique_identifier = event.train.front_stock.backer_name + + local train = map_data.trains[old_id] + if not train then return end + --NOTE: IMPORTANT, until se_on_train_teleport_finished_event is called map_data.trains[old_id] will reference an invalid train entity; our events have either been set up to account for this or should be impossible to trigger until teleportation is finished + train.se_is_being_teleported = true + map_data.se_tele_old_id[train_unique_identifier] = old_id + interface_raise_train_teleport_started(old_id) + end) + ---@param event {} + script.on_event(se_on_train_teleport_finished_event, function(event) + ---@type MapData + local map_data = global + ---@type LuaTrain + local train_entity = event.train + ---@type uint + local new_id = train_entity.id + local old_surface_index = event.old_surface_index + local train_unique_identifier = event.train.front_stock.backer_name + + --NOTE: event.old_train_id_1 from this event is useless, it's for one of the many transient trains SE spawns while teleporting the old train, only se_on_train_teleport_started_event returns the correct old train id + --NOTE: please SE dev if you read this fix the issue where se_on_train_teleport_finished_event is returning the wrong old train id + local old_id = map_data.se_tele_old_id[train_unique_identifier] + map_data.se_tele_old_id[train_unique_identifier] = nil + local train = map_data.trains[old_id] + if not train then return end + + if train.is_available then + local network = map_data.available_trains[train.network_name--[[@as string]]] + if network then + network[new_id] = true + network[old_id] = nil + end + end + + map_data.trains[new_id] = train + map_data.trains[old_id] = nil + train.se_is_being_teleported = nil + train.entity = train_entity + + if train.se_awaiting_removal then + remove_train(map_data, train.se_awaiting_removal, train) + lock_train(train.entity) + send_lost_train_alert(train.entity, train.depot_name) + return + elseif train.se_awaiting_rename then + rename_manifest_schedule(train.entity, train.se_awaiting_rename[1], train.se_awaiting_rename[2]) + train.se_awaiting_rename = nil + end + + if not (train.status == STATUS_D_TO_P or train.status == STATUS_P_TO_R) then return end + + local schedule = train_entity.schedule + if schedule then + local p_station = map_data.stations[train.p_station_id] + local p_name = p_station.entity_stop.backer_name + local p_surface_i = p_station.entity_stop.surface.index + local r_station = map_data.stations[train.r_station_id] + local r_name = r_station.entity_stop.backer_name + local r_surface_i = r_station.entity_stop.surface.index + local records = schedule.records + local i = schedule.current + while i <= #records do + if records[i].station == p_name and p_surface_i ~= old_surface_index then + table_insert(records, i, create_direct_to_station_order(p_station.entity_stop)) + i = i + 1 + elseif records[i].station == r_name and r_surface_i ~= old_surface_index then + table_insert(records, i, create_direct_to_station_order(r_station.entity_stop)) + i = i + 1 + end + i = i + 1 + end + train_entity.schedule = schedule + end + interface_raise_train_teleported(new_id, old_id) + end) +end + local filter_built = { {filter = "name", name = "train-stop"}, @@ -1012,102 +1104,14 @@ local function main() register_gui_actions() - script.on_init(init_global) + script.on_init(function() + setup_se_compat() + init_global() + end) script.on_configuration_changed(on_config_changed) - - script.on_load(function() - IS_SE_PRESENT = remote.interfaces["space-exploration"] ~= nil - if not IS_SE_PRESENT then return end - - local se_on_train_teleport_finished_event = remote.call("space-exploration", "get_on_train_teleport_finished_event") - local se_on_train_teleport_started_event = remote.call("space-exploration", "get_on_train_teleport_started_event") - - ---@param event {} - script.on_event(se_on_train_teleport_started_event, function(event) - ---@type MapData - local map_data = global - local old_id = event.old_train_id_1 - --NOTE: this is not guaranteed to be unique, it should be fine since the window of time for another train to mistakenly steal this train's event data is miniscule - --NOTE: please SE dev if you read this fix the issue where se_on_train_teleport_finished_event is returning the wrong old train id - local train_unique_identifier = event.train.front_stock.backer_name - - local train = map_data.trains[old_id] - if not train then return end - --NOTE: IMPORTANT, until se_on_train_teleport_finished_event is called map_data.trains[old_id] will reference an invalid train entity; our events have either been set up to account for this or should be impossible to trigger until teleportation is finished - train.se_is_being_teleported = true - map_data.se_tele_old_id[train_unique_identifier] = old_id - interface_raise_train_teleport_started(old_id) - end) - ---@param event {} - script.on_event(se_on_train_teleport_finished_event, function(event) - ---@type MapData - local map_data = global - ---@type LuaTrain - local train_entity = event.train - ---@type uint - local new_id = train_entity.id - local old_surface_index = event.old_surface_index - local train_unique_identifier = event.train.front_stock.backer_name - - --NOTE: event.old_train_id_1 from this event is useless, it's for one of the many transient trains SE spawns while teleporting the old train, only se_on_train_teleport_started_event returns the correct old train id - --NOTE: please SE dev if you read this fix the issue where se_on_train_teleport_finished_event is returning the wrong old train id - local old_id = map_data.se_tele_old_id[train_unique_identifier] - map_data.se_tele_old_id[train_unique_identifier] = nil - local train = map_data.trains[old_id] - if not train then return end - - if train.is_available then - local network = map_data.available_trains[train.network_name--[[@as string]]] - if network then - network[new_id] = true - network[old_id] = nil - end - end - - map_data.trains[new_id] = train - map_data.trains[old_id] = nil - train.se_is_being_teleported = nil - train.entity = train_entity - - if train.se_awaiting_removal then - remove_train(map_data, train.se_awaiting_removal, train) - lock_train(train.entity) - send_lost_train_alert(train.entity, train.depot_name) - return - elseif train.se_awaiting_rename then - rename_manifest_schedule(train.entity, train.se_awaiting_rename[1], train.se_awaiting_rename[2]) - train.se_awaiting_rename = nil - end - - if not (train.status == STATUS_D_TO_P or train.status == STATUS_P_TO_R) then return end - - local schedule = train_entity.schedule - if schedule then - local p_station = map_data.stations[train.p_station_id] - local p_name = p_station.entity_stop.backer_name - local p_surface_i = p_station.entity_stop.surface.index - local r_station = map_data.stations[train.r_station_id] - local r_name = r_station.entity_stop.backer_name - local r_surface_i = r_station.entity_stop.surface.index - local records = schedule.records - local i = schedule.current - while i <= #records do - if records[i].station == p_name and p_surface_i ~= old_surface_index then - table_insert(records, i, create_direct_to_station_order(p_station.entity_stop)) - i = i + 1 - elseif records[i].station == r_name and r_surface_i ~= old_surface_index then - table_insert(records, i, create_direct_to_station_order(r_station.entity_stop)) - i = i + 1 - end - i = i + 1 - end - train_entity.schedule = schedule - end - interface_raise_train_teleported(new_id, old_id) - end) - end) + script.on_load(setup_se_compat) end