--[[ Copyright (c) 2017 Optera * Part of Logistics Train Network * * See LICENSE.md in the project directory for license information. --]] on_stops_updated_event = script.generate_event_name() on_dispatcher_updated_event = script.generate_event_name() on_dispatcher_no_train_found_event = script.generate_event_name() on_delivery_created_event = script.generate_event_name() on_delivery_pickup_complete_event = script.generate_event_name() on_delivery_completed_event = script.generate_event_name() on_delivery_failed_event = script.generate_event_name() on_provider_missing_cargo_alert = script.generate_event_name() on_provider_unscheduled_cargo_alert = script.generate_event_name() on_requester_unscheduled_cargo_alert = script.generate_event_name() on_requester_remaining_cargo_alert = script.generate_event_name() -- ltn_interface allows mods to register for update events remote.add_interface("logistic-train-network", { -- updates for ltn_stops on_stops_updated = function() return on_stops_updated_event end, -- updates for dispatcher on_dispatcher_updated = function() return on_dispatcher_updated_event end, on_dispatcher_no_train_found = function() return on_dispatcher_no_train_found_event end, on_delivery_created = function() return on_delivery_created_event end, -- update for updated deliveries after leaving provider on_delivery_pickup_complete = function() return on_delivery_pickup_complete_event end, -- update for completing deliveries on_delivery_completed = function() return on_delivery_completed_event end, on_delivery_failed = function() return on_delivery_failed_event end, -- alerts on_provider_missing_cargo = function() return on_provider_missing_cargo_alert end, on_provider_unscheduled_cargo = function() return on_provider_unscheduled_cargo_alert end, on_requester_unscheduled_cargo = function() return on_requester_unscheduled_cargo_alert end, on_requester_remaining_cargo = function() return on_requester_remaining_cargo_alert end, -- surface connections connect_surfaces = ConnectSurfaces, -- function(entity1 :: LuaEntity, entity2 :: LuaEntity, network_id :: int32) disconnect_surfaces = DisconnectSurfaces, -- function(entity1 :: LuaEntity, entity2 :: LuaEntity) clear_all_surface_connections = ClearAllSurfaceConnections, -- Re-assigns a delivery to a different train. reassign_delivery = ReassignDelivery, -- function(old_train_id :: uint, new_train :: LuaTrain) :: bool get_or_create_next_temp_stop = GetOrCreateNextTempStop, -- function(train :: LuaTrain, schedule_index :: uint?) :: uint get_next_logistic_stop = GetNextLogisticStop, -- function(train :: LuaTrain, schedule_index :: uint?) :: uint?, uint?, string? }) --[[ register events from LTN: if remote.interfaces["logistic-train-network"] then script.on_event(remote.call("logistic-train-network", "on_stops_updated"), on_stops_updated) script.on_event(remote.call("logistic-train-network", "on_dispatcher_updated"), on_dispatcher_updated) end ]]-- --[[ EVENTS on_stops_updated Raised every UpdateInterval, after delivery generation -> Contains: logistic_train_stops = { [stop_id :: uint], { -- stop data active_deliveries :: int, entity :: LuaEntity, input :: LuaEntity, output :: LuaEntity, lamp_control :: LuaEntity, error_code :: int, -- control signals is_depot :: bool, depot_priority :: int32, network_id :: int32, max_carriages :: int32, min_carriages :: int32, max_trains :: int32, providing_threshold :: int32, providing_threshold_stacks :: int32, provider_priority :: int32, requesting_threshold :: int32, requesting_threshold_stacks :: int32, requester_priority :: int32, locked_slots :: int32, no_warnings :: bool, -- parked train data parked_train :: LuaTrain, parked_train_id :: uint, parked_train_faces_stop :: bool, }} on_dispatcher_updated Raised every UpdateInterval, after delivery generation -> Contains: update_interval = int -- time in ticks LTN needed to run all updates, varies depending on number of stops and requests provided_by_stop = { [stop_id :: uint], { [item :: string], count :: int } } requests_by_stop = { [stop_id :: uint], { [item :: string], count :: int } } new_deliveries = { uint } -- train_ids of deliveries created this UpdateInterval deliveries = { [train_id :: uint], { force :: LuaForce, train :: LuaTrain, from :: string, from_id :: uint, to :: string, to_id :: uint, network_id: int32, started :: uint, -- tick this delivery was created on surface_connections = { entity1 :: LuaEntity, entity2 :: LuaEntity, network_id :: int32 }, shipment = { [item :: string], count :: int } } } available_trains = { [train_id :: uint], { capacity :: int, fluid_capacity :: int, force :: LuaForce, surface :: LuaSurface, depot_priority :: int32, network_id :: int32, train :: LuaTrain } } on_dispatcher_no_train_found Raised when no train was found to handle a request -> Contains: to :: string -- requester.backer_name to_id :: uint -- requester.unit_number network_id :: int32 (optional) item :: string (optional) from :: string (optional) from_id :: uint (optional) min_carriages :: int32 (optional) max_carriages :: int32 (optional) shipment = { [item :: string], count :: int } on_delivery_pickup_complete Raised when a train leaves provider stop -> Contains: train_id :: uint train :: LuaTrain planned_shipment= { [item :: string], count :: int } actual_shipment = { [item :: string], count :: int } -- shipment updated to train inventory on_delivery_completed Raised when train leaves requester stop -> Contains: train_id :: uint train :: LuaTrain shipment= { [item :: string], count :: int } on_delivery_failed Raised when rolling stock of a train gets removed, the delivery timed out, train enters depot stop with active delivery -> Contains: train_id :: uint shipment= { [item :: string], count :: int } } ---- Alerts ---- on_dispatcher_no_train_found Raised when depot was empty -> Contains: to :: string to_id :: uint network_id :: int32 item :: string -- on_dispatcher_no_train_found Raised when no matching train was found -> Contains: to :: string to_id :: uint network_id :: int32 from :: string from_id :: uint min_carriages :: int32 max_carriages :: int32 shipment = { [item :: string], count :: int } } on_provider_missing_cargo Raised when trains leave provider with less than planned load -> Contains: train :: LuaTrain station :: LuaEntity planned_shipment = { [item :: string], count :: int } } actual_shipment = { [item :: string], count :: int } } on_provider_unscheduled_cargo Raised when trains leave provider with wrong cargo -> Contains: train :: LuaTrain station :: LuaEntity planned_shipment = { [item :: string], count :: int } } unscheduled_load = { [item :: string], count :: int } } on_requester_unscheduled_cargo Raised when trains arrive at requester with wrong cargo -> Contains: train :: LuaTrain station :: LuaEntity planned_shipment = { [item :: string], count :: int } } unscheduled_load = { [item :: string], count :: int } } on_requester_remaining_cargo Raised when trains leave requester with remaining cargo -> Contains: train :: LuaTrain station :: LuaEntity remaining_load = { [item :: string], count :: int } } --]] --[[ REMOTE CALLS usage: if remote.interfaces["logistic-train-network"] then remote.call("logistic-train-network", "", ?) end connect_surfaces(entity1 :: LuaEntity, entity2 :: LuaEntity, network_id :: int32) Designates two entities on different surfaces as forming a surface connection. Connections are bi-directional but not transitive, i.e. surface A -> B implies B -> A, but A -> B and B -> C does not imply A -> C. LTN will generate deliveries between depot and provider on one surface and requester on the other. Network_id acts as additional mask for potential providers. It is the caller's responsibility to ensure: 1) trains are moved between surfaces 2) deliveries are updated to the new train after surface transition, see reassign_delivery() 3) trains return to their original surface depot disconnect_surfaces(entity1 :: LuaEntity, entity2 :: LuaEntity) Removes a surface connection formed by the two given entities. Active deliveries will not be affected. It's not necessary to call this function when deleting one or both entities. clear_all_surface_connections() Clears all surface connections. Active deliveries will not be affected This function exists for debugging purposes, no event is raised to notify connection owners. reassign_delivery(old_train_id :: uint, new_train :: LuaTrain) :: bool Re-assigns a delivery to a different train. Should be called after creating a train based on another train, for example after moving a train to a different surface. Calls with an old_train_id without delivery have no effect. Don't call this function when coupling trains via script, LTN already handles that through Factorio events. This function does not add missing temp stops. See get_or_create_next_temp_stop for that. get_or_create_next_temp_stop(train :: LuaTrain, schedule_index :: uint?) :: uint Ensures the next logistic stop in the schedule has a temporary stop if it is on the same surface as the train. If no schedule_index is given, the search for the next logistic stop starts from train.schedule.current In case the train is currently stopping at that index, the search starts at the next higher index. The result will be the schedule index of the temp stop of the next logistic stop or nil if there is no further logistic stop. get_next_logistic_stop(train :: LuaTrain, schedule_index :: uint?) :: uint?, uint?, string? Finds the next logistic stop in the schedule of the given train. If no schedule_index is given, the search starts from train.schedule.current. In case the train is currently stopping at that index, the search starts at the next higher index. The result will be three values stop_schedule_index, stop_id and either the string "provider" or "requester". If there is no further logistic stop in the schedule, the result will be nil. --]]