Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add compatibility with Noxy Multidirectional Trains #227

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cybersyn/info.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"base",
"flib >= 0.15.0",
"? space-exploration >= 0.6.94",
"? Noxys_Multidirectional_Trains >= 0.5.3",
"? miniloader",
"? nullius",
"? pypostprocessing"
Expand Down
3 changes: 2 additions & 1 deletion cybersyn/scripts/global.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
---@field public network_mask int|{[string]: int}

---@class Train
---@field public entity LuaTrain --should only be invalid if se_is_being_teleported is true
---@field public entity LuaTrain --should only be invalid if se_is_being_teleported or is_train_id_volatile is true
---@field public layout_id uint
---@field public item_slot_capacity int
---@field public fluid_capacity int
Expand All @@ -99,6 +99,7 @@
---@field public network_mask int|{[string]: int} --transient
---@field public priority int
---@field public refueler_id uint?
---@field public is_train_id_volatile boolean? --se/noxy only
---@field public se_is_being_teleported true? --se only
---@field public se_awaiting_removal any? --se only
---@field public se_awaiting_rename any? --se only
Expand Down
131 changes: 107 additions & 24 deletions cybersyn/scripts/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,56 @@ local function on_rename(event)
end
end

---Sets the `is_train_id_changing` state for a tracked train with the given `train_id` to the given `value`.
---If no train matching `train_id` is tracked, returns early.
---@param train_id uint
---@param value boolean|nil
local function set_is_train_id_volatile(train_id, value)
---@type MapData
local map_data = storage

local train = map_data.trains[train_id]
if not train then return end

train.is_train_id_volatile = value
end

---@param train_entity LuaTrain
---@param new_id uint
---@param old_id uint
local function migrate_tracked_train_to_new_id(train_entity, new_id, old_id)
---@type MapData
local map_data = storage

local train = map_data.trains[old_id]
if not train then return end

if train.is_available then
local f, a
if train.network_name == NETWORK_EACH then
f, a = next, train.network_mask
else
f, a = once, train.network_name
end
for network_name in f, a do
local network = map_data.available_trains[network_name]
if network then
network[new_id] = true
network[old_id] = nil
if next(network) == nil then
map_data.available_trains[network_name] = nil
end
end
end
end

map_data.trains[new_id] = train
map_data.trains[old_id] = nil
train.entity = train_entity

interface_raise_train_id_changed(new_id, old_id)
end


---@param schedule TrainSchedule
---@param stop LuaEntity
Expand Down Expand Up @@ -837,6 +887,7 @@ local function setup_se_compat()
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
set_is_train_id_volatile(train_id, true)
interface_raise_train_teleport_started(old_id)
end)
---@param event {}
Expand All @@ -850,32 +901,14 @@ local function setup_se_compat()
local old_surface_index = event.old_surface_index

local old_id = event.old_train_id_1
local train = map_data.trains[old_id]
if not train then return end

if train.is_available then
local f, a
if train.network_name == NETWORK_EACH then
f, a = next, train.network_mask
else
f, a = once, train.network_name
end
for network_name in f, a do
local network = map_data.available_trains[network_name]
if network then
network[new_id] = true
network[old_id] = nil
if next(network) == nil then
map_data.available_trains[network_name] = nil
end
end
end
end
migrate_tracked_train_to_new_id(train_entity, new_id, old_id)

local train = map_data.trains[new_id]
if not train then return end

map_data.trains[new_id] = train
map_data.trains[old_id] = nil
train.se_is_being_teleported = nil
train.entity = train_entity
set_is_train_id_volatile(train_id, nil)

if train.se_awaiting_removal then
remove_train(map_data, train.se_awaiting_removal, train)
Expand All @@ -889,7 +922,7 @@ local function setup_se_compat()

local schedule = train_entity.schedule
if schedule then
--this code relies on train chedules being in this specific order to work
--this code relies on train schedules being in this specific order to work
local start = schedule.current
--check depot
if not train.use_any_depot then
Expand Down Expand Up @@ -925,6 +958,54 @@ local function setup_se_compat()
end)
end

local function setup_noxy_compat()
IS_NOXY_MULTIDIRECTIONAL_TRAINS_PRESENT = remote.interfaces["Noxys_Multidirectional_Trains"]
if IS_NOXY_MULTIDIRECTIONAL_TRAINS_PRESENT then
local noxy_on_train_rotating_event = remote.call("Noxys_Multidirectional_Trains", "get_on_train_rotating")--[[@as string]]
local noxy_on_train_locomotive_rotated_event = remote.call("Noxys_Multidirectional_Trains", "get_on_train_locomotive_rotated")--[[@as string]]
local noxy_on_train_rotated_event = remote.call("Noxys_Multidirectional_Trains", "get_on_train_rotated")--[[@as string]]
local noxy_on_train_unrotating_event = remote.call("Noxys_Multidirectional_Trains", "get_on_train_unrotating")--[[@as string]]

---@param event {}
script.on_event(noxy_on_train_rotating_event, function(event)
---@type uint
local train_id = event.train.id
--Noxy will rotate a train a few ticks after it leaves the station, so
--no special handling is required the way there is for arrivals.

--Prevent Cybersyn from removing the train because Noxy is going to
--destroy and rebuild it possibly many times in rapid succession.
set_is_train_id_volatile(train_id, true)
end)
---@param event {}
script.on_event(noxy_on_train_locomotive_rotated_event, function(event)
---@type LuaTrain
local train_entity = event.train
---@type uint
local new_id = train_entity.id
---@type uint
local old_id = event.old_train_id_1
--Every rotation destroys and creates a new train, ensure the train id is migrated
--with each rotation to prevent it from losing track.
migrate_tracked_train_to_new_id(train_entity, new_id, old_id)
end)
---@param event {}
script.on_event(noxy_on_train_rotated_event, function(event)
---@type uint
local train_id = event.train.id
--Clear the volatile tag, Noxy has finished.
set_is_train_id_volatile(train_id, nil)
end)
---@param event {}
script.on_event(noxy_on_train_unrotating_event, function(event)
--Noxy unrotates trains on arrival to stations, which destroys the train and
--prevents Cybersyn from correctly handling train arrivals.
--Forward the change event to Cybersyn's handler.
on_train_changed(event)
end)
end
end

local function setup_picker_dollies_compat()
IS_PICKER_DOLLIES_PRESENT = remote.interfaces["PickerDollies"] and remote.interfaces["PickerDollies"]["add_blacklist_name"]
if IS_PICKER_DOLLIES_PRESENT then
Expand Down Expand Up @@ -1047,6 +1128,7 @@ local function main()
mod_settings.invert_sign = false
init_global()
setup_se_compat()
setup_noxy_compat()
setup_picker_dollies_compat()
if MANAGER_ENABLED then
manager.on_init()
Expand All @@ -1063,6 +1145,7 @@ local function main()

script.on_load(function()
setup_se_compat()
setup_noxy_compat()
setup_picker_dollies_compat()
end)

Expand Down
15 changes: 15 additions & 0 deletions cybersyn/scripts/remote-interface.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ local on_train_dispatch_failed = nil
local on_train_failed_delivery = nil
local on_train_status_changed = nil
local on_train_stuck = nil
local on_train_id_changed = nil
local on_train_teleport_started = nil
local on_train_teleported = nil
local on_tick_init = nil
Expand Down Expand Up @@ -93,6 +94,10 @@ function interface.get_on_train_stuck()
if not on_train_stuck then on_train_stuck = script_generate_event_name() end
return on_train_stuck
end
function interface.get_on_train_id_changed()
if not on_train_id_changed then on_train_id_changed = script_generate_event_name() end
return on_train_id_changed
end
function interface.get_on_train_teleport_started()
if not on_train_teleport_started then on_train_teleport_started = script_generate_event_name() end
return on_train_teleport_started
Expand Down Expand Up @@ -527,6 +532,16 @@ function interface_raise_train_stuck(train_id)
})
end
end
---@param new_train_id uint
---@param old_train_id uint
function interface_raise_train_id_changed(new_train_id, old_train_id)
if on_train_id_changed then
raise_event(on_train_id_changed, {
new_train_id = new_train_id,--this id stores the train
old_train_id = old_train_id,--this id is now invalid
})
end
end
---@param old_train_id uint
function interface_raise_train_teleport_started(old_train_id)
if on_train_teleport_started then
Expand Down
4 changes: 2 additions & 2 deletions cybersyn/scripts/train-events.lua
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ end
---@param train Train
function on_train_broken(map_data, train_id, train)
--NOTE: train.entity is only absent if the train is climbing a space elevator as of 0.5.0
if not train.se_is_being_teleported then
if not train.se_is_being_teleported and not train.is_train_id_volatile then
remove_train(map_data, train_id, train)
end
end
Expand All @@ -416,7 +416,7 @@ end
local function on_train_modified(map_data, pre_train_id)
local train = map_data.trains[pre_train_id]
--NOTE: train.entity is only absent if the train is climbing a space elevator as of 0.5.0
if train and not train.se_is_being_teleported then
if train and not train.se_is_being_teleported and not train.is_train_id_volatile then
remove_train(map_data, pre_train_id, train)
end
end
Expand Down