added space elevator compat

This commit is contained in:
Monica Moniot
2022-11-25 14:20:37 -05:00
parent 78958f4f22
commit be3f2f1d07
10 changed files with 293 additions and 75 deletions

1
TODO
View File

@@ -6,3 +6,4 @@ models & art
space elevator compat
railloader compat
major bug with copy-paste when the operation is changed by blueprint but it gets copied to the old settings before it's checked for update
go over init and make it agree with type info

View File

@@ -47,3 +47,8 @@ Version: 0.4.4
Date: 2022-11-25
Features:
- Greatly improved automatic train blacklist logic
---------------------------------------------------------------------------------------------------
Version: 0.5.0
Date: 2022-11-25
Features:
- Added SE space elevator compat

View File

@@ -1,12 +1,13 @@
{
"name": "cybersyn",
"version": "0.4.4",
"version": "0.5.0",
"title": "Project Cybersyn",
"author": "Mami",
"factorio_version": "1.1",
"dependencies": [
"base",
"flib >= 0.6.0",
"? space-exploration >= 0.6.90",
"? miniloader"
]
}

View File

@@ -1,5 +1,4 @@
--By Mami
local get_distance = require("__flib__.misc").get_distance
local min = math.min
local max = math.max
local abs = math.abs
@@ -12,12 +11,6 @@ local table_sort = table.sort
local random = math.random
---@param stop0 LuaEntity
---@param stop1 LuaEntity
local function get_stop_dist(stop0, stop1)
return get_distance(stop0.position, stop1.position)
end
---@param map_data MapData
---@param station Station
@@ -217,7 +210,7 @@ local function send_train_between(map_data, r_station_id, p_station_id, depot, p
train.manifest = manifest
train.last_manifest_tick = map_data.total_ticks
train.entity.schedule = create_manifest_schedule(train.depot_name, p_station.entity_stop, r_station.entity_stop, manifest)
set_manifest_schedule(train.entity, depot.entity_stop, p_station.entity_stop, r_station.entity_stop, manifest)
set_comb2(map_data, p_station)
set_comb2(map_data, r_station)
if p_station.entity_comb1.valid then

View File

@@ -34,17 +34,15 @@ STATUS_P_TO_R = 3
STATUS_R = 4
STATUS_R_TO_D = 5
TRAIN_LAYOUT_NA = "N"
TRAIN_LAYOUT_CARGO = "C"
TRAIN_LAYOUT_FLUID = "F"
--TRAIN_LAYOUT_ARTILLERY = "A"
STATION_LAYOUT_NA = "N"
STATION_LAYOUT_ALL = "."
STATION_LAYOUT_NOT_FLUID = "[NC]"
STATION_LAYOUT_NOT_CARGO = "[NF]"
LONGEST_INSERTER_REACH = 2
STATE_INIT = 0
STATE_POLL_STATIONS = 1
STATE_DISPATCH = 2
DIFFERENT_SURFACE_DISTANCE = 1000000000
SE_ELEVATOR_STOP_PROTO_NAME = "se-space-elevator-train-stop"
SE_ELEVATOR_ORBIT_SUFFIX = ""
SE_ELEVATOR_PLANET_SUFFIX = ""
SE_ELEVATOR_SUFFIX_LENGTH = 4

View File

@@ -1,4 +1,5 @@
--By Mami
local get_distance = require("__flib__.misc").get_distance
local abs = math.abs
local floor = math.floor
@@ -10,6 +11,13 @@ function get_stack_size(map_data, item_name)
end
---@param stop0 LuaEntity
---@param stop1 LuaEntity
function get_stop_dist(stop0, stop1)
return get_distance(stop0.position, stop1.position)
end
local create_loading_order_condition = {type = "inactivity", compare_type = "and", ticks = 120}
---@param stop LuaEntity
---@param manifest Manifest
@@ -47,29 +55,50 @@ end
local create_direct_to_station_order_condition = {{type = "time", compare_type = "and", ticks = 1}}
---@param stop LuaEntity
local function create_direct_to_station_order(stop)
return {rail = stop.connected_rail, rail_direction = stop.connected_rail_direction,wait_conditions = create_direct_to_station_order_condition}
function create_direct_to_station_order(stop)
return {rail = stop.connected_rail, rail_direction = stop.connected_rail_direction, wait_conditions = create_direct_to_station_order_condition}
end
---@param train LuaTrain
---@param depot_name string
function create_depot_schedule(depot_name)
return {current = 1, records = {create_inactivity_order(depot_name)}}
function set_depot_schedule(train, depot_name)
train.schedule = {current = 1, records = {create_inactivity_order(depot_name)}}
end
---@param depot_name string
---@param train LuaTrain
function lock_train(train)
train.manual_mode = true
end
--[[
---@param train LuaTrain
---@param depot_stop LuaEntity
---@param p_stop LuaEntity
---@param r_stop LuaEntity
---@param manifest Manifest
function create_manifest_schedule(depot_name, p_stop, r_stop, manifest)
return {current = 1, records = {
create_inactivity_order(depot_name),
function set_manifest_schedule(train, depot_stop, p_stop, r_stop, manifest)
train.schedule = {current = 1, records = {
create_inactivity_order(depot_stop.backer_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),
}}
end
]]
---@param train LuaTrain
---@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
end
end
train.schedule = schedule
end
function get_comb_params(comb)
return comb.get_or_create_control_behavior().parameters--[[@as ArithmeticCombinatorParameters]]
end
@@ -283,3 +312,89 @@ function send_stuck_train_alert(train, depot_name)
end
end
end
--function se_create_placeholder_order()
--end
---@param surface LuaSurface
local function se_get_space_elevator_name(surface)
--TODO: check how expensive the following is and potentially cache it's results
local entity = surface.find_entities_filtered({
name = SE_ELEVATOR_STOP_PROTO_NAME,
type = "train-stop",
limit = 1,
})[1]
if entity and entity.valid then
return string.sub(entity.backer_name, 1, string.len(entity.backer_name) - SE_ELEVATOR_SUFFIX_LENGTH)
end
end
---@param train LuaTrain
---@param depot_stop LuaEntity
---@param p_stop LuaEntity
---@param r_stop LuaEntity
---@param manifest Manifest
function set_manifest_schedule(train, depot_stop, p_stop, r_stop, manifest)
--NOTE: train must be on same surface as depot_stop
local d_surface = depot_stop.surface
local p_surface = p_stop.surface
local r_surface = r_stop.surface
local d_surface_i = d_surface.index
local p_surface_i = p_surface.index
local r_surface_i = r_surface.index
if d_surface_i == p_surface_i and p_surface_i == r_surface_i then
train.schedule = {current = 1, records = {
create_inactivity_order(depot_stop.backer_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),
}}
return
elseif IS_SE_PRESENT and (d_surface_i == p_surface_i or p_surface_i == r_surface_i or r_surface_i == d_surface_i) then
local d_zone = remote.call("space-exploration", "get_zone_from_surface_index", {surface_index = d_surface_i})
local other_zone = remote.call("space-exploration", "get_zone_from_surface_index", {surface_index = (d_surface_i == p_surface_i) and r_surface_i or p_surface_i})
local is_train_in_orbit = other_zone.orbit_index == d_zone.index
if is_train_in_orbit or d_zone.orbit_index == other_zone.index then
local elevator_name = se_get_space_elevator_name(d_surface)
if elevator_name then
local records = {create_inactivity_order(depot_stop.backer_name)}
if d_surface_i == p_surface_i then
records[#records + 1] = create_direct_to_station_order(p_stop)
else
records[#records + 1] = {station = elevator_name..(is_train_in_orbit and SE_ELEVATOR_ORBIT_SUFFIX or SE_ELEVATOR_PLANET_SUFFIX)}
is_train_in_orbit = not is_train_in_orbit
end
records[#records + 1] = create_loading_order(p_stop, manifest)
if p_surface_i ~= r_surface_i then
records[#records + 1] = {station = elevator_name..(is_train_in_orbit and SE_ELEVATOR_ORBIT_SUFFIX or SE_ELEVATOR_PLANET_SUFFIX)}
is_train_in_orbit = not is_train_in_orbit
end
records[#records + 1] = create_unloading_order(r_stop)
if r_surface_i ~= d_surface_i then
records[#records + 1] = {station = elevator_name..(is_train_in_orbit and SE_ELEVATOR_ORBIT_SUFFIX or SE_ELEVATOR_PLANET_SUFFIX)}
is_train_in_orbit = not is_train_in_orbit
end
train.schedule = {current = 1, records = records}
return
end
end
end
--NOTE: create a schedule that cannot be fulfilled, the train will be stuck but it will give the player information what went wrong
train.schedule = {current = 1, records = {
create_inactivity_order(depot_stop.backer_name),
create_loading_order(p_stop, manifest),
create_unloading_order(r_stop),
}}
lock_train(train)
send_lost_train_alert(train, depot_stop.backer_name)
end
---@param stop0 LuaEntity
---@param stop1 LuaEntity
function se_get_stop_dist(stop0, stop1)
local surface0 = stop0.surface.index
local surface1 = stop1.surface.index
return (surface0 == surface1 and get_distance(stop0.position, stop1.position) or DIFFERENT_SURFACE_DISTANCE)
end

View File

@@ -18,6 +18,7 @@
---@field public tick_state uint
---@field public tick_data {}
---@field public economy Economy
---@field public se_tele_old_id {[any]: uint}
---@class Station
---@field public is_p boolean
@@ -63,6 +64,8 @@
---@field public network_name string
---@field public network_flag int
---@field public priority int
---@field public se_awaiting_removal any?
---@field public se_awaiting_rename any?
---@alias Manifest {}[]
---@alias TrainClass {[uint]: true}
@@ -84,6 +87,8 @@
---@type CybersynModSettings
mod_settings = {}
IS_SE_PRESENT = remote.interfaces["space-exploration"] ~= nil
function init_global()
global.total_ticks = 0
global.tick_state = STATE_INIT
@@ -107,4 +112,8 @@ function init_global()
global.layout_train_count = {}
global.layout_top_id = 1
global.is_player_cursor_blueprint = {}
if IS_SE_PRESENT then
global.se_tele_old_id = {}
end
end

View File

@@ -43,7 +43,7 @@ end
---@param train Train
---@param train_id uint
function remove_train(map_data, train, train_id)
if train.depot_id then
if train.status == STATUS_D then
local depot = map_data.depots[train.depot_id]
remove_available_train(map_data, train, depot)
end
@@ -84,7 +84,7 @@ function update_train_layout(map_data, train)
i = i + 1
end
local back_movers = train.entity.locomotives["back_movers"]
if back_movers and #back_movers > 0 then
if #back_movers > 0 then
--mark the layout as reversible
layout[0] = true
end

View File

@@ -1,6 +1,7 @@
--By Mami
local flib_event = require("__flib__.event")
local floor = math.floor
local table_insert = table.insert
---@param map_data MapData
@@ -67,6 +68,7 @@ local function add_available_train(map_data, depot_id, train_id)
network[train_id] = depot_id
end
depot.available_train_id = train_id
train.status = STATUS_D
train.depot_id = depot_id
train.depot_name = depot.entity_stop.backer_name
train.network_name = network_name
@@ -105,7 +107,6 @@ function remove_available_train(map_data, train, depot)
end
end
end
train.depot_id = nil
depot.available_train_id = nil
end
@@ -128,7 +129,7 @@ local function on_depot_broken(map_data, depot)
local train_id = depot.available_train_id
if train_id then
local train = map_data.trains[train_id]
train.entity.schedule = nil
lock_train(train.entity)
send_lost_train_alert(train.entity, depot.entity_stop.backer_name)
remove_available_train(map_data, train, depot)
map_data.trains[train_id] = nil
@@ -181,9 +182,13 @@ local function on_station_broken(map_data, station_id, station)
if (is_r and not is_r_delivery_made) or (is_p and not is_p_delivery_made) then
--train is attempting delivery to a stop that was destroyed, stop it
on_failed_delivery(map_data, train)
train.entity.schedule = nil
if train.entity then
remove_train(map_data, train, train_id)
lock_train(train.entity)
send_lost_train_alert(train.entity, train.depot_name)
else
train.se_awaiting_removal = train_id
end
end
end
end
@@ -510,7 +515,8 @@ local function on_stop_broken(map_data, stop)
end
---@param map_data MapData
---@param stop LuaEntity
local function on_station_rename(map_data, stop)
---@param old_name string
local function on_station_rename(map_data, stop, old_name)
--search for trains coming to the renamed station
local station_id = stop.unit_number
local station = map_data.stations[station_id]
@@ -521,13 +527,21 @@ local function on_station_rename(map_data, stop)
if is_p or is_r then
local is_p_delivery_made = train.status ~= STATUS_D_TO_P and train.status ~= STATUS_P
local is_r_delivery_made = train.status == STATUS_R_TO_D
if (is_r and not is_r_delivery_made) or (is_p and not is_p_delivery_made) then
if is_r and not is_r_delivery_made then
local r_station = map_data.stations[train.r_station_id]
if train.entity then
rename_manifest_schedule(train.entity, r_station.entity_stop, old_name)
elseif IS_SE_PRESENT then
train.se_awaiting_rename = {r_station.entity_stop, old_name}
end
elseif is_p and not is_p_delivery_made then
--train is attempting delivery to a stop that was renamed
local p_station = map_data.stations[train.p_station_id]
local r_station = map_data.stations[train.r_station_id]
local schedule = create_manifest_schedule(train.depot_name, p_station.entity_stop, r_station.entity_stop, train.manifest)
schedule.current = train.entity.schedule.current
train.entity.schedule = schedule
if train.entity then
rename_manifest_schedule(train.entity, p_station.entity_stop, old_name)
elseif IS_SE_PRESENT then
train.se_awaiting_rename = {p_station.entity_stop, old_name}
end
end
end
end
@@ -568,21 +582,19 @@ local function on_train_arrives_depot(map_data, depot_id, train_entity)
train.p_station_id = 0
train.r_station_id = 0
train.manifest = nil
train.status = STATUS_D
add_available_train(map_data, depot_id, train_id)
else
if train.manifest then
on_failed_delivery(map_data, train)
send_unexpected_train_alert(train.entity)
end
train.status = STATUS_D
add_available_train(map_data, depot_id, train_id)
end
if is_train_empty then
train_entity.schedule = create_depot_schedule(train.depot_name)
set_depot_schedule(train_entity, train.depot_name)
else
--train still has cargo
train_entity.schedule = nil
lock_train(train.entity)
remove_train(map_data, train, train_id)
send_nonempty_train_in_depot_alert(train_entity)
end
@@ -596,16 +608,15 @@ local function on_train_arrives_depot(map_data, depot_id, train_entity)
p_station_id = 0,
r_station_id = 0,
last_manifest_tick = map_data.total_ticks,
manifest = nil,
--manifest = nil,
}
update_train_layout(map_data, train)
map_data.trains[train_id] = train
add_available_train(map_data, depot_id, train_id)
local schedule = create_depot_schedule(train.depot_name)
train_entity.schedule = schedule
set_depot_schedule(train_entity, train.depot_name)
else
train_entity.schedule = nil
lock_train(train.entity)
send_nonempty_train_in_depot_alert(train_entity)
end
end
@@ -635,7 +646,7 @@ local function on_train_arrives_buffer(map_data, stop, train)
else
on_failed_delivery(map_data, train)
remove_train(map_data, train, train.entity.id)
train.entity.schedule = nil
lock_train(train.entity)
send_lost_train_alert(train.entity, train.depot_name)
end
else
@@ -674,7 +685,7 @@ local function on_train_leaves_station(map_data, train)
set_comb1(map_data, station, nil)
unset_wagon_combs(map_data, station)
end
elseif train.depot_id then
elseif train.status == STATUS_D then
local depot = map_data.depots[train.depot_id]
remove_available_train(map_data, train, depot)
end
@@ -684,11 +695,12 @@ end
---@param map_data MapData
---@param train Train
local function on_train_broken(map_data, train)
if train.manifest then
--NOTE: train.entity is only absent if the train is climbing a space elevator as of 0.5.0
if train.manifest and train.entity then
on_failed_delivery(map_data, train)
remove_train(map_data, train, train.entity.id)
if train.entity.valid then
train.entity.schedule = nil
lock_train(train.entity)
end
end
end
@@ -697,13 +709,14 @@ end
---@param train_entity LuaEntity
local function on_train_modified(map_data, pre_train_id, train_entity)
local train = map_data.trains[pre_train_id]
if train then
--NOTE: train.entity is only absent if the train is climbing a space elevator as of 0.5.0
if train and train.entity then
if train.manifest then
on_failed_delivery(map_data, train)
end
remove_train(map_data, train, pre_train_id)
if train.entity.valid then
train.entity.schedule = nil
lock_train(train.entity)
end
end
end
@@ -756,7 +769,7 @@ local function on_rotate(event)
end
local function on_rename(event)
if event.entity.name == "train-stop" then
on_station_rename(global, event.entity)
on_station_rename(global, event.entity, event.old_name)
end
end
@@ -771,7 +784,7 @@ local function on_train_built(event)
end
local function on_train_changed(event)
local train_e = event.train
if train_e.valid then
if not train_e.valid then return end
local train = global.trains[train_e.id]
if train_e.state == defines.train_state.wait_station then
local stop = train_e.station
@@ -792,7 +805,6 @@ local function on_train_changed(event)
on_train_leaves_station(global, train)
end
end
end
end
local function on_surface_removed(event)
@@ -800,7 +812,7 @@ local function on_surface_removed(event)
if surface then
local train_stops = surface.find_entities_filtered({type = "train-stop"})
for _, entity in pairs(train_stops) do
if entity.name == "train-stop" then
if entity.valid and entity.name == "train-stop" then
on_stop_broken(global, entity)
end
end
@@ -915,6 +927,87 @@ local function main()
flib_event.on_init(init_global)
flib_event.on_configuration_changed(on_config_changed)
if IS_SE_PRESENT then
flib_event.on_load(function()
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")
flib_event.register(se_on_train_teleport_started_event, function(event)
---@type MapData
local map_data = global
local old_id = event.old_train_id_1
local old_surface_index = event.old_surface_index
--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; very few of our events care about this and the ones that do should be impossible to trigger until teleportation is finished
train.entity = nil
map_data.se_tele_old_id[train_unique_identifier] = old_id
end)
flib_event.register(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
map_data.trains[new_id] = train
map_data.trains[old_id] = nil
train.entity = train_entity
if train.se_awaiting_removal then
remove_train(map_data, train, train.se_awaiting_removal)
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
end)
end)
end
end

View File

@@ -109,10 +109,13 @@ local migrations_table = {
for id, station in pairs(map_data.stations) do
reset_station_layout(map_data, station)
end
end,
end
}
---@param data ConfigurationChangedData
function on_config_changed(data)
flib_migration.on_config_changed(data, migrations_table)
if IS_SE_PRESENT and not global.se_tele_old_id then
global.se_tele_old_id = {}
end
end