@@ -4,6 +4,19 @@ Behold one of the most feature-rich and performant train logistics network mods
|
||||
|
||||

|
||||
|
||||
## Quick Start Guide
|
||||
|
||||
Within Project Cybersyn, you can think of requester stations as requester chests, provider stations as passive provider chests, depots as roboports and trains as the logistics bots. There is a direct correspondence between the Cybersyn train network and Factorio's robot logistics network.
|
||||
|
||||
A bare minimum Cybersyn train network consists of 2 components: depots and stations. Both are created by placing a cybernetic combinator adjacent to a train stop. Select the "Control Mode" of the combinator to "Station" to create a station, and to "Depot" to create a depot. Create a basic train and order it to park at the depot you just created, it is now controlled by the Cybersyn network. Depots and stations can have any train stop name, names do not impact their function. The circuit network input of a station's cybernetic combinator determines what items that station will request or provide to the Cybersyn network. A positive item signal is interpreted as that station providing that item to the network; A negative item signal is interpreted as that station requesting that item from the network.
|
||||
|
||||

|
||||

|
||||
|
||||
To make a basic provider station, create an item buffer of chests or tanks adjacent to the station's tracks, and connect that buffer by wire to the input of the cybernetic combinator. To make a basic requester station, repeat the same, except reverse the direction of the inserters or pumps so they are *unloading* instead of loading; then connect a constant combinator to the same circuit network, set it to output the number of item you want this requester station to keep loaded in its item buffer, and flip the sign of each so the signal strength is negative. Once the provider station contains the item being requested, a train will automatically be sent to deliver that item from the provider station to the requester station. The requester station's buffer will automatically be topped up on the item being requested.
|
||||
|
||||
Follow the above directions and you have set up a bare minimum Cybersyn network! You may continue adding onto it with more stations and depots and Cybersyn will automatically manage all of them for you. At some point you may notice small hiccups within this network, like trains attempting to deliver a tiny amount of an item instead of a full cargo load, or you may want to extend your network with things like multi-item stations or centralized train refueling. In either case refer to **Mod Details** below for a in depth explanation of every feature within this mod.
|
||||
|
||||
## Features
|
||||
|
||||

|
||||
@@ -24,6 +37,10 @@ These all combine to make it possible to **create "universal" stations**; statio
|
||||
|
||||
Stations can **automatically build allow-lists for trains** they can load or unload. Inserters or pumps adjacent to the station's tracks are auto-detected. No more deadlocks caused by trains mistakenly attempting to fulfill a delivery to a station that cannot unload it. This feature is compatible with miniloaders.
|
||||
|
||||
Trains can automatically visit **centralized fuel loaders**. It is not required that every single depot loads trains with fuel.
|
||||
|
||||
Trains can **bypass visiting the depot** if they have enough fuel. Trains spend far more time productively making deliveries rather than travelling to and from their depot. Fewer reserve trains are needed as a result.
|
||||
|
||||
**Easy and versatile ways to define separate train networks.** Bitwise network masks are now optional! Networks are identified by signal id first, then by signal strength.
|
||||
|
||||

|
||||
@@ -48,25 +65,35 @@ If you like my work, consider supporting me on [ko-fi](https://ko-fi.com/lesbian
|
||||
|
||||
This mod adds a single new entity to the game, the cybernetic combinator. This combinator can be in one of 4 different possible control modes. While each mode has a purpose, the only modes you have to use are primary station control and depot control.
|
||||
|
||||
### Primary station control combinator
|
||||
### Station mode
|
||||
|
||||

|
||||
|
||||
When placed adjacent to a vanilla train stop, a Cybersyn station is created. This station can provide or request items to your train network. Connect the input of the combinator to a circuit network; When a positive item signal is received, this station will provide that item to the network, when a negative signal is received, this station will request that item from the network. When a station is providing an item that another station is requesting, a train order will automatically be generated to transfer those items from the providing station to the requesting station. When a train arrives to fulfill this order, the output of the combinator will give the full list of items expected to be loaded (positive) or unloaded (negative) from the train.
|
||||
|
||||
### Depot control combinator
|
||||
Stations can automatically build allow-lists. When this option is enabled, only trains that can be loaded or unloaded by this station will be allowed to make deliveries to it. Stations determine this based on what inserters or pumps are present at this station along its tracks. When disabled, all trains within the network are allowed.
|
||||
|
||||
Stations can be set to provide only or request only. By default stations can both provide and request, but when one of these options is chosen either requesting is disabled or providing is disabled.
|
||||
|
||||
### Depot mode
|
||||
|
||||

|
||||
|
||||
When placed adjacent to a vanilla train stop, a Cybersyn depot is created. Any train which parks at this depot will automatically be added to the train network. Whenever a train order is generated, if this train has the cargo capacity to fulfill it, and is allow-listed by both stations, then it will automatically be dispatched to fulfill the order. When the order is completed, the train will return to any train stop with the same name as the depot it first parked in. This almost always means it returns to a Cybersyn depot where it will again await to fulfill a new order. To save on UPS the input of a depot control combinator is only read when a train parks at the depot; this only matters for networks which make extensive use of network masks on depots.
|
||||
When placed adjacent to a vanilla train stop, a Cybersyn depot is created. Any train which parks at this depot will automatically be added to the train network. Whenever a train order is generated, if this train has the cargo capacity to fulfill it, and is allow-listed by both stations, then it will automatically be dispatched to fulfill the order. When the order is completed, the train will return to any train stop with the same name as the depot it first parked in. This almost always means it returns to a Cybersyn depot where it will again await to fulfill a new order. To save on UPS the input of a depot control combinator is only read when a train parks at the depot; this is only relevant for networks which make extensive use of network masks on depots.
|
||||
|
||||
### Optional station control combinator
|
||||
### Fuel loader mode
|
||||
|
||||
When placed adjacent to a vanilla train stop, a Cybersyn fuel loader is created. Whenever a train completes a delivery, if it is running low on fuel (configurable in mod settings), it will attempt to visit a fuel loader before returning to the depot. The train will search for a fuel loader within its network that has not exceeded its train limit and that it is allow-listed for. If one is found it will schedule a detour to it to stock back up on fuel.
|
||||
|
||||
Fuel loaders can automatically build allow-lists. When this option is enabled, trains will be prevented from parking at this station if one of their cargo wagons would be filled with fuel.
|
||||
|
||||
### Station info mode
|
||||
|
||||

|
||||
|
||||
When placed adjacent to the train stop of an already existing Cybersyn station, this combinator will provide a second set of inputs and outputs that can be used to more precisely control this station. The combinator input allows for request thresholds to be set per-item. Any non-zero item signal given on the input circuit network will override the station's request thresholds for just that item. The output of the combinator gives the sum total of all item loading or unloading orders in progress for the station. The very tick a train is dispatched for a new order to the station, that order is added to the output of this combinator, and it is removed as soon as the train leaves the station. The primary use case for this is to prevent duplicate orders from being generated for stations that provide the same pool of items. Only one train can be dispatched per-tick per-item specifically to accommodate this.
|
||||
|
||||
### Wagon control combinator
|
||||
### Wagon info mode
|
||||
|
||||

|
||||
|
||||
@@ -76,7 +103,9 @@ When placed adjacent to the tracks of an already existing Cybersyn station, this
|
||||
|
||||

|
||||
|
||||
Stations and depots can be set to belong to a particular network by setting that network on the control combinator. By default all combinators belong to the "signal-A" network. By setting a different signal Id, the combinator will belong to that different network. Networks identified with different signal Ids do not share any trains or items; Orders will never be generated to transfer items between separate networks. In addition, if the combinator receives as input a signal of the same Id as its network signal Id, then the value of this signal will be interpreted as a bitmask to give 32 "sub-networks" to choose from. Each station can belong to any set of sub-networks based on its mask signal. A delivery will only be made between two stations if any bit matches between the two masks, i.e. if `mask1 & mask2 > 0`. When a network id is an item, that item will be ignored by stations, its signal will only ever be interpreted as the network mask.
|
||||
Stations and depots can be set to belong to a particular network by setting that network on the control combinator. By default all combinators belong to the "signal-A" network. By setting a different signal Id, the combinator will belong to that different network. Networks identified with different signal Ids do not share any trains or items; Orders will never be generated to transfer items between separate networks.
|
||||
|
||||
In addition, if the combinator receives as input a signal of the same Id as its network signal Id, then the value of this signal will be interpreted as a bitmask to give 32 "sub-networks" to choose from. Each station can belong to any set of sub-networks based on its mask. A delivery will only be made between two stations if any two bits match between the two masks, i.e. if `mask1 & mask2 > 0`. When a network Id is an item, that item will be ignored by stations, its signal will only ever be interpreted as the network mask.
|
||||
|
||||
### Request threshold
|
||||
|
||||
@@ -90,8 +119,10 @@ After an order has been generated, enough items will be subtracted from that ord
|
||||
|
||||
### Priority
|
||||
|
||||
Orders will be generated first for stations and depots which are receiving a higher priority signal than the others. If stations have the same priority, the least recently used request station will be prioritized, and the provide station closest to the request station will be prioritized. So in times of item shortage (front-pressure), round robin distribution will be used, and in times of item surplus (back-pressure), minimum travel distance distribution will be used.
|
||||
Orders will be generated first for stations, depots and fuel loaders which are receiving a higher priority signal than the others. If stations have the same priority, the least recently used requester station will be prioritized, and the provider station closest to the requester station will be prioritized. So in times of item shortage (front-pressure), round robin distribution will be used, and in times of item surplus (back-pressure), minimum travel distance distribution will be used.
|
||||
|
||||
If a combinator set to station info mode receives a priority signal, for each item signal input to the combinator, items of that type will have its priority overridden in addition to its request threshold. This effectively allows you to choose one of two possible priorities for each item that a station processes.
|
||||
|
||||
### Train limits
|
||||
|
||||
Works based off of the train limit set on the train stop in the same way it does in vanilla Factorio. Only a number of trains up to the train limit will be allowed to dispatch to the station by the central planner. Useful to reduce the need for train stackers and prevent deadlocks.
|
||||
Works based off of the train limit set on the train stop in the same way it does in vanilla Factorio. Only a number of trains up to the train limit will be allowed to dispatch to the station by the central planner. Useful to reduce the need for train stackers and to prevent deadlocks.
|
||||
|
||||
@@ -111,3 +111,12 @@ Version: 1.0.9
|
||||
Date: 2022-12-3
|
||||
Features:
|
||||
- Fixed a bug with SE compat preventing players from joining multiplayer games
|
||||
---------------------------------------------------------------------------------------------------
|
||||
Version: 1.1.0
|
||||
Date: 2022-12-5
|
||||
Features:
|
||||
- Added the ability to use the priority signal as input to optional station control so one can override priority on items with optional station control thresholds
|
||||
- Added refueler stations
|
||||
- Slightly more permissive allow-list logic
|
||||
- Fixed a crash relating to wagon control combinators on request stations
|
||||
- Made non-backwards compatible improvements and bugfixes to the modding interface
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
require("scripts.constants")
|
||||
require("scripts.global")
|
||||
require("scripts.factorio-api")
|
||||
require("scripts.central-planning")
|
||||
require("scripts.layout")
|
||||
require("scripts.central-planning")
|
||||
require("scripts.train-events")
|
||||
require("scripts.gui")
|
||||
require("scripts.migrations")
|
||||
require("scripts.main")
|
||||
|
||||
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 19 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cybersyn",
|
||||
"version": "1.0.9",
|
||||
"version": "1.1.0",
|
||||
"title": "Project Cybersyn",
|
||||
"author": "Mami",
|
||||
"factorio_version": "1.1",
|
||||
|
||||
@@ -3,16 +3,18 @@ cybersyn-ticks-per-second=Central planning updates per second
|
||||
cybersyn-update-rate=Central planning update rate
|
||||
cybersyn-request-threshold=Default requester threshold
|
||||
cybersyn-network-flag=Default network mask
|
||||
cybersyn-depot-bypass-threshold=Depot bypass fuel threshold
|
||||
cybersyn-fuel-threshold=Fuel threshold
|
||||
cybersyn-depot-bypass-enabled=Depot bypass enabled
|
||||
cybersyn-warmup-time=Station warmup time (sec)
|
||||
cybersyn-stuck-train-time=Stuck train timeout (sec)
|
||||
|
||||
[mod-setting-description]
|
||||
cybersyn-ticks-per-second=How many times per second the central planner should update the state of the network and schedule deliveries. This value will be rounded up to a divisor of 60.
|
||||
cybersyn-ticks-per-second=How many times per second the central planner should update the state of the network and schedule deliveries. This value will be rounded up to a divisor of 60. Setting this to 0 will stop all dispatches.
|
||||
cybersyn-update-rate=How many stations per tick can be polled at once or can have deliveries scheduled at once. Larger number allow the central planner to keep more up to date on the current state of the network, but at the cost of performance.
|
||||
cybersyn-request-threshold=The default request threshold when a request threshold signal is not given to a station. When a station receives a negative item signal that surpasses its request threshold, so long as any station exists with a positive signal greater than the request threshold, a delivery of that item will be scheduled between the two stations.
|
||||
cybersyn-network-flag=The default set of sub-networks a station will service when no network signal is given to a station. This integer is interpretted bit-wise to give 32 possible sub-networks to choose from.
|
||||
cybersyn-depot-bypass-threshold=What percentage of the fuel inventory of the a train must be full to activate depot bypass. When a train qualifies for depot bypass, it may take a new order from the network before having to return to its depot, dramatically reducing travel time. If this is set to 1, depot bypass will be disabled.
|
||||
cybersyn-fuel-threshold=What percentage of a train's fuel inventory must be full to skip refueling. If this is set to 1, trains will always visit a fuel loader after completing a delivery.
|
||||
cybersyn-depot-bypass-enabled=If checked, when a train completes a delivery and refueling, it may take a new order from the network before having to return to its depot.
|
||||
cybersyn-warmup-time=How many seconds a cybernetic combinator will wait before connecting to the Cybersyn network. This is a grace period to modify or correct the circuit network before trains start dispatching to a newly blueprinted station.
|
||||
cybersyn-stuck-train-time=After this many seconds from a train's dispatch, an alert will be sent to let you know a train is probably stuck and has not completed its delivery. The player will likely have to debug their network to get the train unstuck.
|
||||
|
||||
@@ -49,11 +51,12 @@ stuck-train=A train from depot __1__ is stuck
|
||||
|
||||
[cybersyn-gui]
|
||||
combinator-title=Cybernetic combinator
|
||||
operation=Mode
|
||||
comb1=Primary station control
|
||||
comb2=Optional station control
|
||||
depot=Depot control
|
||||
wagon-manifest=Wagon control
|
||||
operation=Control Mode
|
||||
comb1=Station
|
||||
depot=Depot
|
||||
refueler=Fuel loader
|
||||
comb2=Station info
|
||||
wagon-manifest=Wagon info
|
||||
network=Network
|
||||
network-tooltip=A signal is used to identify which network this combinator is a member of. Trains will only be dispatched from depots to provide and request stations if they are all identified with the same signal.
|
||||
auto-tooltip=When checked trains in the network are automatically added to the allow-list if every wagon of the train is able to be loaded or unloaded by this station. When unchecked the allow-list is not used and all trains are allowed to park here.
|
||||
|
||||
@@ -212,6 +212,7 @@ combinator_entity.divide_symbol_sprites = create_combinator_display(30, 0, { 0,
|
||||
combinator_entity.modulo_symbol_sprites = create_combinator_display(45, 0, { 0, -0.140625, }, { 0, -0.328125, })
|
||||
combinator_entity.power_symbol_sprites = create_combinator_display(0, 11, { 0, -0.140625, }, { 0, -0.328125, })
|
||||
combinator_entity.left_shift_symbol_sprites = create_combinator_display(15, 11, { 0, -0.140625, }, { 0, -0.328125, })
|
||||
combinator_entity.right_shift_symbol_sprites = create_combinator_display(30, 11, { 0, -0.140625, }, { 0, -0.328125, })
|
||||
combinator_entity.multiply_symbol_sprites = combinator_entity.divide_symbol_sprites
|
||||
|
||||
|
||||
|
||||
@@ -95,9 +95,8 @@ end
|
||||
---@param r_station_id uint
|
||||
---@param p_station_id uint
|
||||
---@param train_id uint
|
||||
---@param primary_item_name string?
|
||||
function send_train_between(map_data, r_station_id, p_station_id, train_id, primary_item_name)
|
||||
--trains and stations expected to be of the same network
|
||||
---@param manifest Manifest
|
||||
function create_delivery(map_data, r_station_id, p_station_id, train_id, manifest)
|
||||
local economy = map_data.economy
|
||||
local r_station = map_data.stations[r_station_id]
|
||||
local p_station = map_data.stations[p_station_id]
|
||||
@@ -105,6 +104,69 @@ function send_train_between(map_data, r_station_id, p_station_id, train_id, prim
|
||||
---@type string
|
||||
local network_name = r_station.network_name
|
||||
|
||||
remove_available_train(map_data, train_id, train)
|
||||
local depot_id = train.parked_at_depot_id
|
||||
if depot_id then
|
||||
map_data.depots[depot_id].available_train_id = nil
|
||||
train.parked_at_depot_id = nil
|
||||
end
|
||||
--NOTE: we assume that the train is not being teleported at this time
|
||||
if set_manifest_schedule(train.entity, train.depot_name, train.se_depot_surface_i, p_station.entity_stop, r_station.entity_stop, manifest, depot_id ~= nil) 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
|
||||
|
||||
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 then
|
||||
--prevent deliveries from being processed for these items until their stations are re-polled
|
||||
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
|
||||
|
||||
set_comb2(map_data, p_station)
|
||||
set_comb2(map_data, r_station)
|
||||
|
||||
if p_station.display_state < 2 then
|
||||
p_station.display_state = 2
|
||||
update_display(map_data, p_station)
|
||||
end
|
||||
if r_station.display_state < 2 then
|
||||
r_station.display_state = 2
|
||||
update_display(map_data, r_station)
|
||||
end
|
||||
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
|
||||
---@param p_station_id uint
|
||||
---@param train_id uint
|
||||
---@param primary_item_name string?
|
||||
function create_manifest(map_data, r_station_id, p_station_id, train_id, primary_item_name)
|
||||
--trains and stations expected to be of the same network
|
||||
local r_station = map_data.stations[r_station_id]
|
||||
local p_station = map_data.stations[p_station_id]
|
||||
local train = map_data.trains[train_id]
|
||||
|
||||
---@type Manifest
|
||||
local manifest = {}
|
||||
|
||||
for k, v in pairs(r_station.tick_signals) do
|
||||
@@ -114,8 +176,8 @@ function send_train_between(map_data, r_station_id, p_station_id, train_id, prim
|
||||
local r_item_count = v.count
|
||||
local r_effective_item_count = r_item_count + (r_station.deliveries[item_name] or 0)
|
||||
if r_effective_item_count < 0 and r_item_count < 0 then
|
||||
local r_threshold = r_station.p_count_or_r_threshold_per_item[item_name]
|
||||
local p_effective_item_count = p_station.p_count_or_r_threshold_per_item[item_name]
|
||||
local r_threshold = r_station.item_thresholds and r_station.item_thresholds[item_name] or r_station.r_threshold
|
||||
local p_effective_item_count = p_station.item_p_counts[item_name]
|
||||
--could be an item that is not present at the station
|
||||
if p_effective_item_count and p_effective_item_count >= r_threshold then
|
||||
local item = {name = item_name, type = item_type, count = min(-r_effective_item_count, p_effective_item_count)}
|
||||
@@ -167,55 +229,7 @@ function send_train_between(map_data, r_station_id, p_station_id, train_id, prim
|
||||
end
|
||||
end
|
||||
|
||||
remove_available_train(map_data, train_id, train)
|
||||
local depot_id = train.parked_at_depot_id
|
||||
if depot_id then
|
||||
map_data.depots[depot_id].available_train_id = nil
|
||||
train.parked_at_depot_id = nil
|
||||
end
|
||||
--NOTE: we assume that the train is not being teleported at this time
|
||||
if set_manifest_schedule(train.entity, train.depot_name, train.se_depot_surface_i, p_station.entity_stop, r_station.entity_stop, manifest, depot_id ~= nil) then
|
||||
train.status = STATUS_D_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
|
||||
|
||||
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 then
|
||||
--prevent deliveries from being processed for these items until their stations are re-polled
|
||||
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
|
||||
|
||||
set_comb2(map_data, p_station)
|
||||
set_comb2(map_data, r_station)
|
||||
|
||||
if p_station.display_state < 2 then
|
||||
p_station.display_state = 2
|
||||
update_display(map_data, p_station)
|
||||
end
|
||||
if r_station.display_state < 2 then
|
||||
r_station.display_state = 2
|
||||
update_display(map_data, r_station)
|
||||
end
|
||||
interface_raise_train_dispatched(train_id)
|
||||
else
|
||||
interface_raise_train_dispatch_failed(train_id)
|
||||
end
|
||||
return manifest
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
@@ -282,11 +296,19 @@ local function tick_dispatch(map_data, mod_settings)
|
||||
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 station and station.deliveries_total < station.entity_stop.trains_limit then
|
||||
local threshold = station.p_count_or_r_threshold_per_item[item_name]
|
||||
if threshold <= max_threshold and (station.priority > best_prior or (station.priority == best_prior and station.last_delivery_tick < best_lru)) then
|
||||
local item_threshold = station.item_thresholds and station.item_thresholds[item_name] or nil
|
||||
local threshold = station.r_threshold
|
||||
local prior = station.priority
|
||||
if item_threshold then
|
||||
threshold = item_threshold
|
||||
if station.item_priority then
|
||||
prior = station.item_priority--[[@as int]]
|
||||
end
|
||||
end
|
||||
if threshold <= max_threshold and (prior > best_prior or (prior == best_prior and station.last_delivery_tick < best_lru)) then
|
||||
r_station_i = i
|
||||
r_threshold = threshold
|
||||
best_prior = station.priority
|
||||
best_prior = prior
|
||||
best_lru = station.last_delivery_tick
|
||||
end
|
||||
end
|
||||
@@ -314,9 +336,13 @@ local function tick_dispatch(map_data, mod_settings)
|
||||
for j, p_station_id in ipairs(p_stations) do
|
||||
local p_station = stations[p_station_id]
|
||||
if p_station and p_station.deliveries_total < p_station.entity_stop.trains_limit then
|
||||
local effective_count = p_station.p_count_or_r_threshold_per_item[item_name]
|
||||
local effective_count = p_station.item_p_counts[item_name]
|
||||
if effective_count >= r_threshold then
|
||||
local item_threshold = p_station.item_thresholds and p_station.item_thresholds[item_name] or nil
|
||||
local prior = p_station.priority
|
||||
if item_threshold then
|
||||
prior = p_station.item_priority--[[@as int]]
|
||||
end
|
||||
local slot_threshold = item_type == "fluid" and r_threshold or ceil(r_threshold/get_stack_size(map_data, item_name))
|
||||
local train, d = get_valid_train(map_data, r_station_id, p_station_id, item_type, slot_threshold)
|
||||
if prior > best_prior or (prior == best_prior and d < best_dist) then
|
||||
@@ -338,7 +364,9 @@ local function tick_dispatch(map_data, mod_settings)
|
||||
end
|
||||
end
|
||||
if best_train then
|
||||
send_train_between(map_data, r_station_id, table_remove(p_stations, best_i), best_train, item_name)
|
||||
local p_station_id = table_remove(p_stations, best_i)
|
||||
local manifest = create_manifest(map_data, r_station_id, p_station_id, best_train, item_name)
|
||||
create_delivery(map_data, r_station_id, p_station_id, best_train, manifest)
|
||||
return false
|
||||
else
|
||||
if can_be_serviced and mod_settings.missing_train_alert_enabled then
|
||||
@@ -385,13 +413,34 @@ local function tick_poll_station(map_data, mod_settings)
|
||||
end
|
||||
station.r_threshold = mod_settings.r_threshold
|
||||
station.priority = 0
|
||||
station.item_priority = nil
|
||||
station.locked_slots = 0
|
||||
station.network_flag = mod_settings.network_flag
|
||||
local signals = get_signals(station)
|
||||
station.tick_signals = signals
|
||||
station.p_count_or_r_threshold_per_item = {}
|
||||
if signals then
|
||||
for k, v in pairs(signals) do
|
||||
local comb1_signals, comb2_signals = get_signals(station)
|
||||
station.tick_signals = comb1_signals
|
||||
station.item_p_counts = {}
|
||||
|
||||
if comb1_signals then
|
||||
if comb2_signals then
|
||||
station.item_thresholds = {}
|
||||
for k, v in pairs(comb2_signals) do
|
||||
local item_name = v.signal.name
|
||||
local item_count = v.count
|
||||
local item_type = v.signal.type
|
||||
if item_name then
|
||||
if item_type == "virtual" then
|
||||
if item_name == SIGNAL_PRIORITY then
|
||||
station.item_priority = item_count
|
||||
end
|
||||
else
|
||||
station.item_thresholds[item_name] = abs(item_count)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
station.item_thresholds = nil
|
||||
end
|
||||
for k, v in pairs(comb1_signals) do
|
||||
local item_name = v.signal.name
|
||||
local item_count = v.count
|
||||
local item_type = v.signal.type
|
||||
@@ -405,18 +454,18 @@ local function tick_poll_station(map_data, mod_settings)
|
||||
elseif item_name == LOCKED_SLOTS then
|
||||
station.locked_slots = max(item_count, 0)
|
||||
end
|
||||
signals[k] = nil
|
||||
comb1_signals[k] = nil
|
||||
end
|
||||
if item_name == station.network_name then
|
||||
station.network_flag = item_count
|
||||
signals[k] = nil
|
||||
comb1_signals[k] = nil
|
||||
end
|
||||
else
|
||||
signals[k] = nil
|
||||
comb1_signals[k] = nil
|
||||
end
|
||||
end
|
||||
local is_requesting_nothing = true
|
||||
for k, v in pairs(signals) do
|
||||
for k, v in pairs(comb1_signals) do
|
||||
---@type string
|
||||
local item_name = v.signal.name
|
||||
local item_count = v.count
|
||||
@@ -424,7 +473,7 @@ local function tick_poll_station(map_data, mod_settings)
|
||||
|
||||
local is_not_requesting = true
|
||||
if station.is_r then
|
||||
local r_threshold = get_threshold(map_data, station, v.signal)
|
||||
local r_threshold = station.item_thresholds and station.item_thresholds[item_name] or station.r_threshold
|
||||
if -effective_item_count >= r_threshold and -item_count >= r_threshold then
|
||||
is_not_requesting = false
|
||||
is_requesting_nothing = false
|
||||
@@ -437,7 +486,6 @@ local function tick_poll_station(map_data, mod_settings)
|
||||
all_names[#all_names + 1] = v.signal
|
||||
end
|
||||
stations[#stations + 1] = station_id
|
||||
station.p_count_or_r_threshold_per_item[item_name] = r_threshold
|
||||
end
|
||||
end
|
||||
if is_not_requesting then
|
||||
@@ -449,9 +497,9 @@ local function tick_poll_station(map_data, mod_settings)
|
||||
all_p_stations[item_network_name] = stations
|
||||
end
|
||||
stations[#stations + 1] = station_id
|
||||
station.p_count_or_r_threshold_per_item[item_name] = effective_item_count
|
||||
station.item_p_counts[item_name] = effective_item_count
|
||||
else
|
||||
signals[k] = nil
|
||||
comb1_signals[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,13 +13,14 @@ COMBINATOR_OUT_NAME = "cybersyn-combinator-output"
|
||||
COMBINATOR_CLOSE_SOUND = "entity-close/cybersyn-combinator"
|
||||
ALERT_SOUND = "utility/console_message"
|
||||
|
||||
OPERATION_DEFAULT = "*"
|
||||
OPERATION_PRIMARY_IO = "/"
|
||||
OPERATION_PRIMARY_IO_FAILED_REQUEST = "^"
|
||||
OPERATION_PRIMARY_IO_ACTIVE = "<<"
|
||||
OPERATION_SECONDARY_IO = "%"
|
||||
OPERATION_DEPOT = "+"
|
||||
OPERATION_WAGON_MANIFEST = "-"
|
||||
MODE_DEFAULT = "*"
|
||||
MODE_PRIMARY_IO = "/"
|
||||
MODE_PRIMARY_IO_FAILED_REQUEST = "^"
|
||||
MODE_PRIMARY_IO_ACTIVE = "<<"
|
||||
MODE_SECONDARY_IO = "%"
|
||||
MODE_DEPOT = "+"
|
||||
MODE_WAGON_MANIFEST = "-"
|
||||
MODE_REFUELER = ">>"
|
||||
|
||||
NETWORK_SIGNAL_DEFAULT = {name="signal-A", type="virtual"}
|
||||
INACTIVITY_TIME = 100
|
||||
@@ -29,11 +30,14 @@ DELTA = 1/2048
|
||||
DEPOT_PRIORITY_MULT = 2048
|
||||
|
||||
STATUS_D = 0
|
||||
STATUS_D_TO_P = 1
|
||||
STATUS_TO_P = 1
|
||||
STATUS_P = 2
|
||||
STATUS_P_TO_R = 3
|
||||
STATUS_TO_R = 3
|
||||
STATUS_R = 4
|
||||
STATUS_R_TO_D = 5
|
||||
STATUS_TO_D = 5
|
||||
STATUS_TO_D_BYPASS = 6
|
||||
STATUS_TO_F = 7
|
||||
STATUS_F = 8
|
||||
STATUS_CUSTOM = 256 --this status and any status greater than it can be used by other mods (I've reserved the lower integers for myself in case I want to add more statuses)
|
||||
|
||||
LONGEST_INSERTER_REACH = 2
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
--By Mami
|
||||
local get_distance = require("__flib__.misc").get_distance
|
||||
local abs = math.abs
|
||||
local floor = math.floor
|
||||
local table_insert = table.insert
|
||||
local DEFINES_WORKING = defines.entity_status.working
|
||||
local DEFINES_LOW_POWER = defines.entity_status.low_power
|
||||
local DEFINES_COMBINATOR_INPUT = defines.circuit_connector_id.combinator_input
|
||||
|
||||
|
||||
---@param map_data MapData
|
||||
@@ -130,7 +133,10 @@ function set_manifest_schedule(train, depot_name, d_surface_i, p_stop, r_stop, m
|
||||
local t_surface_i = t_surface.index
|
||||
local p_surface_i = p_surface.index
|
||||
local r_surface_i = r_surface.index
|
||||
if t_surface_i == p_surface_i and p_surface_i == r_surface_i then
|
||||
local is_p_on_t = t_surface_i == p_surface_i
|
||||
local is_r_on_t = t_surface_i == r_surface_i
|
||||
local is_d_on_t = t_surface_i == d_surface_i
|
||||
if is_p_on_t and is_r_on_t and is_d_on_t then
|
||||
train.schedule = {current = start_at_depot and 1 or 2, records = {
|
||||
create_inactivity_order(depot_name),
|
||||
create_direct_to_station_order(p_stop),
|
||||
@@ -144,37 +150,43 @@ function set_manifest_schedule(train, depot_name, d_surface_i, p_stop, r_stop, m
|
||||
else
|
||||
return true
|
||||
end
|
||||
elseif IS_SE_PRESENT and (t_surface_i == p_surface_i or p_surface_i == r_surface_i or r_surface_i == t_surface_i) then
|
||||
local t_zone = remote.call("space-exploration", "get_zone_from_surface_index", {surface_index = t_surface_i})
|
||||
local other_zone = remote.call("space-exploration", "get_zone_from_surface_index", {surface_index = (t_surface_i == p_surface_i) and r_surface_i or p_surface_i})
|
||||
local is_train_in_orbit = other_zone.orbit_index == t_zone.index
|
||||
if is_train_in_orbit or t_zone.orbit_index == other_zone.index then
|
||||
local elevator_name = se_get_space_elevator_name(t_surface)
|
||||
if elevator_name then
|
||||
local records = {create_inactivity_order(depot_name)}
|
||||
if t_surface_i == p_surface_i then
|
||||
records[#records + 1] = create_direct_to_station_order(p_stop)
|
||||
else
|
||||
records[#records + 1] = se_create_elevator_order(elevator_name, is_train_in_orbit)
|
||||
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] = se_create_elevator_order(elevator_name, is_train_in_orbit)
|
||||
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] = se_create_elevator_order(elevator_name, is_train_in_orbit)
|
||||
is_train_in_orbit = not is_train_in_orbit
|
||||
end
|
||||
elseif IS_SE_PRESENT then
|
||||
local other_surface_i = (not is_p_on_t and p_surface_i) or (not is_r_on_t and r_surface_i) or d_surface_i
|
||||
if (is_p_on_t or p_surface_i == other_surface_i) and (is_r_on_t or r_surface_i == other_surface_i) and (is_d_on_t or d_surface_i == other_surface_i) then
|
||||
local t_zone = remote.call("space-exploration", "get_zone_from_surface_index", {surface_index = t_surface_i})
|
||||
local other_zone = remote.call("space-exploration", "get_zone_from_surface_index", {surface_index = other_surface_i})
|
||||
local is_train_in_orbit = other_zone.orbit_index == t_zone.index
|
||||
if is_train_in_orbit or t_zone.orbit_index == other_zone.index then
|
||||
local elevator_name = se_get_space_elevator_name(t_surface)
|
||||
if elevator_name then
|
||||
local records = {create_inactivity_order(depot_name)}
|
||||
if t_surface_i == p_surface_i then
|
||||
records[#records + 1] = create_direct_to_station_order(p_stop)
|
||||
else
|
||||
records[#records + 1] = se_create_elevator_order(elevator_name, is_train_in_orbit)
|
||||
is_train_in_orbit = not is_train_in_orbit
|
||||
end
|
||||
records[#records + 1] = create_loading_order(p_stop, manifest)
|
||||
|
||||
train.schedule = {current = start_at_depot and 1 or 2, records = records}
|
||||
if old_schedule and not train.has_path then
|
||||
train.schedule = old_schedule
|
||||
return false
|
||||
else
|
||||
return true
|
||||
if p_surface_i ~= r_surface_i then
|
||||
records[#records + 1] = se_create_elevator_order(elevator_name, is_train_in_orbit)
|
||||
is_train_in_orbit = not is_train_in_orbit
|
||||
elseif t_surface_i == r_surface_i then
|
||||
records[#records + 1] = create_direct_to_station_order(r_stop)
|
||||
end
|
||||
records[#records + 1] = create_unloading_order(r_stop)
|
||||
if r_surface_i ~= d_surface_i then
|
||||
records[#records + 1] = se_create_elevator_order(elevator_name, is_train_in_orbit)
|
||||
is_train_in_orbit = not is_train_in_orbit
|
||||
end
|
||||
|
||||
train.schedule = {current = start_at_depot and 1 or 2, records = records}
|
||||
if old_schedule and not train.has_path then
|
||||
train.schedule = old_schedule
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -190,6 +202,60 @@ function set_manifest_schedule(train, depot_name, d_surface_i, p_stop, r_stop, m
|
||||
return true
|
||||
end
|
||||
|
||||
---@param train LuaTrain
|
||||
---@param stop LuaEntity
|
||||
---@param depot_name string
|
||||
function add_refueler_schedule(train, stop, depot_name)
|
||||
local schedule = train.schedule or {current = 1, records = {}}
|
||||
local i = schedule.current
|
||||
if i == 1 then
|
||||
i = #schedule.records + 1--[[@as uint]]
|
||||
schedule.current = i
|
||||
end
|
||||
|
||||
local t_surface = train.front_stock.surface
|
||||
local f_surface = stop.surface
|
||||
local t_surface_i = t_surface.index
|
||||
local f_surface_i = f_surface.index
|
||||
if t_surface_i == f_surface_i then
|
||||
table_insert(schedule.records, i, create_direct_to_station_order(stop))
|
||||
i = i + 1
|
||||
table_insert(schedule.records, i, create_inactivity_order(stop.backer_name))
|
||||
|
||||
train.schedule = schedule
|
||||
return
|
||||
elseif IS_SE_PRESENT then
|
||||
local t_zone = remote.call("space-exploration", "get_zone_from_surface_index", {surface_index = t_surface_i})
|
||||
local other_zone = remote.call("space-exploration", "get_zone_from_surface_index", {surface_index = f_surface_i})
|
||||
local is_train_in_orbit = other_zone.orbit_index == t_zone.index
|
||||
if is_train_in_orbit or t_zone.orbit_index == other_zone.index then
|
||||
local elevator_name = se_get_space_elevator_name(t_surface)
|
||||
local cur_order = schedule.records[i]
|
||||
local is_elevator_in_orders_already = cur_order and cur_order.station == elevator_name..(is_train_in_orbit and SE_ELEVATOR_ORBIT_SUFFIX or SE_ELEVATOR_PLANET_SUFFIX)
|
||||
if not is_elevator_in_orders_already then
|
||||
table_insert(schedule.records, i, se_create_elevator_order(elevator_name, is_train_in_orbit))
|
||||
end
|
||||
i = i + 1
|
||||
is_train_in_orbit = not is_train_in_orbit
|
||||
table_insert(schedule.records, i, create_inactivity_order(stop.backer_name))
|
||||
i = i + 1
|
||||
if not is_elevator_in_orders_already then
|
||||
table_insert(schedule.records, i, se_create_elevator_order(elevator_name, is_train_in_orbit))
|
||||
i = i + 1
|
||||
is_train_in_orbit = not is_train_in_orbit
|
||||
end
|
||||
|
||||
train.schedule = schedule
|
||||
return
|
||||
end
|
||||
end
|
||||
--create an order that probably cannot be fulfilled and alert the player
|
||||
table_insert(schedule.records, i, create_inactivity_order(stop.backer_name))
|
||||
lock_train(train)
|
||||
send_lost_train_alert(train, depot_name)
|
||||
train.schedule = schedule
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--[[combinators]]--
|
||||
@@ -223,14 +289,16 @@ function get_comb_gui_settings(comb)
|
||||
switch_state = "right"
|
||||
end
|
||||
|
||||
if op == OPERATION_PRIMARY_IO or op == OPERATION_PRIMARY_IO_ACTIVE or op == OPERATION_PRIMARY_IO_FAILED_REQUEST then
|
||||
if op == MODE_PRIMARY_IO or op == MODE_PRIMARY_IO_ACTIVE or op == MODE_PRIMARY_IO_FAILED_REQUEST then
|
||||
selected_index = 1
|
||||
elseif op == OPERATION_SECONDARY_IO then
|
||||
elseif op == MODE_DEPOT then
|
||||
selected_index = 2
|
||||
elseif op == OPERATION_DEPOT then
|
||||
elseif op == MODE_REFUELER then
|
||||
selected_index = 3
|
||||
elseif op == OPERATION_WAGON_MANIFEST then
|
||||
elseif op == MODE_SECONDARY_IO then
|
||||
selected_index = 4
|
||||
elseif op == MODE_WAGON_MANIFEST then
|
||||
selected_index = 5
|
||||
end
|
||||
return selected_index, params.first_signal, not allows_all_trains, switch_state
|
||||
end
|
||||
@@ -253,45 +321,49 @@ function set_station_from_comb_state(station)
|
||||
station.is_p = is_pr_state == 0 or is_pr_state == 1
|
||||
station.is_r = is_pr_state == 0 or is_pr_state == 2
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param unit_number uint
|
||||
---@param params ArithmeticCombinatorParameters
|
||||
local function has_comb_params_changed(map_data, unit_number, params)
|
||||
local old_params = map_data.to_comb_params[unit_number]
|
||||
---@param mod_settings CybersynModSettings
|
||||
---@param refueler Refueler
|
||||
function set_refueler_from_comb(mod_settings, refueler)
|
||||
--NOTE: this does nothing to update currently active deliveries
|
||||
local params = get_comb_params(refueler.entity_comb)
|
||||
local bits = params.second_constant or 0
|
||||
local signal = params.first_signal
|
||||
refueler.network_name = signal and signal.name or nil
|
||||
refueler.allows_all_trains = bits%2 == 1
|
||||
|
||||
if params.operation ~= old_params.operation then
|
||||
if (old_params.operation == OPERATION_PRIMARY_IO) and (params.operation == OPERATION_PRIMARY_IO_ACTIVE or params.operation == OPERATION_PRIMARY_IO_FAILED_REQUEST) then
|
||||
else
|
||||
return true
|
||||
local signals = refueler.entity_comb.get_merged_signals(DEFINES_COMBINATOR_INPUT)
|
||||
refueler.priority = 0
|
||||
refueler.network_flag = mod_settings.network_flag
|
||||
if not signals then return end
|
||||
for k, v in pairs(signals) do
|
||||
local item_name = v.signal.name
|
||||
local item_count = v.count
|
||||
if item_name then
|
||||
if item_name == SIGNAL_PRIORITY then
|
||||
refueler.priority = item_count
|
||||
end
|
||||
if item_name == refueler.network_name then
|
||||
refueler.network_flag = item_count
|
||||
end
|
||||
end
|
||||
end
|
||||
local new_signal = params.first_signal
|
||||
local old_signal = old_params.first_signal
|
||||
local new_network = new_signal and new_signal.name or nil
|
||||
local old_network = old_signal and old_signal.name or nil
|
||||
if new_network ~= old_network then
|
||||
return true
|
||||
end
|
||||
if params.second_constant ~= old_params.second_constant then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param station Station
|
||||
function update_display(map_data, station)
|
||||
local comb = station.entity_comb1
|
||||
if comb.valid then
|
||||
local unit_number = comb.unit_number--[[@as uint]]
|
||||
local control = get_comb_control(comb)
|
||||
local params = control.parameters
|
||||
if not has_comb_params_changed(map_data, unit_number, params) then
|
||||
--NOTE: the following check can cause a bug where the display desyncs if the player changes the operation of the combinator and then changes it back before the mod can notice, however removing it causes a bug where the user's change is overwritten and ignored. Everything's bad we need an event to catch copy-paste by blueprint.
|
||||
if params.operation == MODE_PRIMARY_IO or params.operation == MODE_PRIMARY_IO_ACTIVE or params.operation == MODE_PRIMARY_IO_FAILED_REQUEST then
|
||||
if station.display_state >= 2 then
|
||||
params.operation = OPERATION_PRIMARY_IO_ACTIVE
|
||||
params.operation = MODE_PRIMARY_IO_ACTIVE
|
||||
elseif station.display_state == 1 then
|
||||
params.operation = OPERATION_PRIMARY_IO_FAILED_REQUEST
|
||||
params.operation = MODE_PRIMARY_IO_FAILED_REQUEST
|
||||
else
|
||||
params.operation = OPERATION_PRIMARY_IO
|
||||
params.operation = MODE_PRIMARY_IO
|
||||
end
|
||||
control.parameters = params
|
||||
end
|
||||
@@ -344,18 +416,26 @@ function set_combinator_output(map_data, comb, signals)
|
||||
end
|
||||
end
|
||||
|
||||
local DEFINES_WORKING = defines.entity_status.working
|
||||
local DEFINES_LOW_POWER = defines.entity_status.low_power
|
||||
local DEFINES_COMBINATOR_INPUT = defines.circuit_connector_id.combinator_input
|
||||
---@param station Station
|
||||
function get_signals(station)
|
||||
--NOTE: the combinator must be valid, but checking for valid every time is too slow
|
||||
local comb = station.entity_comb1
|
||||
local status = comb.status
|
||||
if status == DEFINES_WORKING or status == DEFINES_LOW_POWER then
|
||||
return comb.get_merged_signals(DEFINES_COMBINATOR_INPUT)
|
||||
local comb1 = station.entity_comb1
|
||||
local status1 = comb1.status
|
||||
---@type Signal[]?
|
||||
local comb1_signals = nil
|
||||
---@type Signal[]?
|
||||
local comb2_signals = nil
|
||||
if status1 == DEFINES_WORKING or status1 == DEFINES_LOW_POWER then
|
||||
comb1_signals = comb1.get_merged_signals(DEFINES_COMBINATOR_INPUT)
|
||||
end
|
||||
return nil
|
||||
local comb2 = station.entity_comb2
|
||||
if comb2 then
|
||||
local status2 = comb2.status
|
||||
if status2 == DEFINES_WORKING or status2 == DEFINES_LOW_POWER then
|
||||
comb2_signals = comb2.get_merged_signals(DEFINES_COMBINATOR_INPUT)
|
||||
end
|
||||
end
|
||||
return comb1_signals, comb2_signals
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
@@ -373,22 +453,6 @@ function set_comb2(map_data, station)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@param map_data MapData
|
||||
---@param station Station
|
||||
---@param signal SignalID
|
||||
function get_threshold(map_data, station, signal)
|
||||
local comb2 = station.entity_comb2
|
||||
if comb2 then
|
||||
local count = comb2.get_merged_signal(signal, defines.circuit_connector_id.combinator_input)
|
||||
if count ~= 0 then
|
||||
return abs(count)
|
||||
end
|
||||
end
|
||||
return station.r_threshold
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--[[alerts]]--
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
@@ -10,14 +10,16 @@
|
||||
---@field public active_station_ids uint[]
|
||||
---@field public warmup_station_ids uint[]
|
||||
---@field public depots {[uint]: Depot}
|
||||
---@field public refuelers {[uint]: Refueler}
|
||||
---@field public trains {[uint]: Train}
|
||||
---@field public available_trains {[string]: {[uint]: true?}} --{[network_name]: {[train_id]: depot_id}}
|
||||
---@field public available_trains {[string]: {[uint]: true?}} --{[network_name]: {[train_id]: true}}
|
||||
---@field public to_refuelers {[string]: {[uint]: true?}} --{[network_name]: {[refeuler_id]: true}}
|
||||
---@field public layouts {[uint]: (0|1|2)[]}
|
||||
---@field public layout_train_count {[uint]: int}
|
||||
---@field public tick_state uint
|
||||
---@field public tick_data {}
|
||||
---@field public economy Economy
|
||||
---@field public se_tele_old_id {[any]: uint}
|
||||
---@field public se_tele_old_id {[string]: uint}
|
||||
|
||||
---@class Station
|
||||
---@field public entity_stop LuaEntity
|
||||
@@ -29,6 +31,7 @@
|
||||
---@field public deliveries_total int
|
||||
---@field public last_delivery_tick int
|
||||
---@field public priority int --transient
|
||||
---@field public item_priority int? --transient
|
||||
---@field public r_threshold int >= 0 --transient
|
||||
---@field public locked_slots int >= 0 --transient
|
||||
---@field public network_name string?
|
||||
@@ -38,7 +41,8 @@
|
||||
---@field public accepted_layouts {[uint]: true?}
|
||||
---@field public layout_pattern (0|1|2|3)[]?
|
||||
---@field public tick_signals {[uint]: Signal}? --transient
|
||||
---@field public p_count_or_r_threshold_per_item {[string]: int} --transient
|
||||
---@field public item_p_counts {[string]: int} --transient
|
||||
---@field public item_thresholds {[string]: int}? --transient
|
||||
---@field public display_state 0|1|2|3 --low bit is if this station's request has failed, high bit is if a train is heading to this station
|
||||
|
||||
---@class Depot
|
||||
@@ -46,15 +50,27 @@
|
||||
---@field public entity_comb LuaEntity
|
||||
---@field public available_train_id uint?--train_id
|
||||
|
||||
---@class Refueler
|
||||
---@field public entity_stop LuaEntity
|
||||
---@field public entity_comb LuaEntity
|
||||
---@field public trains_total int
|
||||
---@field public accepted_layouts {[uint]: true?}
|
||||
---@field public layout_pattern (0|1|2|3)[]?
|
||||
---@field public wagon_combs {[int]: LuaEntity}?--NOTE: allowed to be invalid entities or combinators with the wrong operation, these must be checked and lazy deleted when found
|
||||
---@field public allows_all_trains boolean
|
||||
---@field public priority int
|
||||
---@field public network_name string?
|
||||
---@field public network_flag int
|
||||
|
||||
---@class Train
|
||||
---@field public entity LuaTrain --should only be invalid if se_is_being_teleported is true
|
||||
---@field public layout_id uint
|
||||
---@field public item_slot_capacity int
|
||||
---@field public fluid_capacity int
|
||||
---@field public status int
|
||||
---@field public p_station_id uint
|
||||
---@field public r_station_id uint
|
||||
---@field public manifest Manifest
|
||||
---@field public status uint
|
||||
---@field public p_station_id uint?
|
||||
---@field public r_station_id uint?
|
||||
---@field public manifest Manifest?
|
||||
---@field public last_manifest_tick int
|
||||
---@field public has_filtered_wagon true?
|
||||
---@field public is_available true?
|
||||
@@ -63,6 +79,7 @@
|
||||
---@field public network_name string? --can only be nil when the train is parked at a depot
|
||||
---@field public network_flag int
|
||||
---@field public priority int
|
||||
---@field public refueler_id uint?
|
||||
---@field public se_depot_surface_i uint --se only
|
||||
---@field public se_is_being_teleported true? --se only
|
||||
---@field public se_awaiting_removal any? --se only
|
||||
@@ -72,7 +89,7 @@
|
||||
---@class ManifestEntry
|
||||
---@field public type string
|
||||
---@field public name string
|
||||
---@field public count uint
|
||||
---@field public count int
|
||||
|
||||
---@class Economy
|
||||
---could contain invalid stations or stations with modified settings from when they were first appended
|
||||
@@ -80,7 +97,8 @@
|
||||
---@field public all_p_stations {[string]: uint[]} --{["network_name:item_name"]: station_id}
|
||||
---@field public all_names (string|SignalID)[]
|
||||
|
||||
--NOTE: any setting labeled as an interface setting can only be changed through the remote-interface, these settings are not save and have to be set at initialization
|
||||
--NOTE: any setting labeled as an "interface setting" can only be changed through the remote-interface, these settings are not save and have to be set at initialization
|
||||
--As a modder using the remote-interface, you may override any of these settings, including user settings. They will have to be overriden at initialization and whenever a user tries to change one.
|
||||
---@class CybersynModSettings
|
||||
---@field public tps double
|
||||
---@field public update_rate int
|
||||
@@ -88,7 +106,8 @@
|
||||
---@field public network_flag int
|
||||
---@field public warmup_time double
|
||||
---@field public stuck_train_time double
|
||||
---@field public depot_bypass_threshold double
|
||||
---@field public fuel_threshold double
|
||||
---@field public depot_bypass_enabled boolean
|
||||
---@field public missing_train_alert_enabled boolean --interface setting
|
||||
---@field public stuck_train_alert_enabled boolean --interface setting
|
||||
---@field public react_to_nonempty_train_in_depot boolean --interface setting
|
||||
|
||||
@@ -60,8 +60,9 @@ function gui_opened(comb, player)
|
||||
on_selection_state_changed={"drop-down", comb.unit_number}
|
||||
}, selected_index=selected_index, items={
|
||||
{"cybersyn-gui.comb1"},
|
||||
{"cybersyn-gui.comb2"},
|
||||
{"cybersyn-gui.depot"},
|
||||
{"cybersyn-gui.refueler"},
|
||||
{"cybersyn-gui.comb2"},
|
||||
{"cybersyn-gui.wagon-manifest"},
|
||||
}},
|
||||
{type="switch", name="switch", ref={"switch"}, allow_none_state=true, switch_state=switch_state, left_label_caption={"cybersyn-gui.switch-provide"}, right_label_caption={"cybersyn-gui.switch-request"}, left_label_tooltip={"cybersyn-gui.switch-provide-tooltip"}, right_label_tooltip={"cybersyn-gui.switch-request-tooltip"}, actions={
|
||||
@@ -88,10 +89,12 @@ function gui_opened(comb, player)
|
||||
window.preview.entity = comb
|
||||
window.titlebar.drag_target = window.main_window
|
||||
window.main_window.force_auto_center()
|
||||
window.network.visible = selected_index == 1 or selected_index == 3
|
||||
window.network_label.visible = selected_index == 1 or selected_index == 3
|
||||
window.radio_button.visible = selected_index == 1
|
||||
window.radio_label.visible = selected_index == 1
|
||||
local uses_network = selected_index == 1 or selected_index == 3 or selected_index == 4
|
||||
local uses_allow_list = selected_index == 1 or selected_index == 4
|
||||
window.network.visible = uses_network
|
||||
window.network_label.visible = uses_network
|
||||
window.radio_button.visible = uses_allow_list
|
||||
window.radio_label.visible = uses_allow_list
|
||||
window.switch.visible = selected_index == 1
|
||||
|
||||
player.opened = window.main_window
|
||||
@@ -142,28 +145,35 @@ function register_gui_actions()
|
||||
local bottom_flow = all_flow.bottom
|
||||
local param
|
||||
if element.selected_index == 1 then
|
||||
set_comb_operation(comb, OPERATION_PRIMARY_IO)
|
||||
set_comb_operation(comb, MODE_PRIMARY_IO)
|
||||
top_flow["switch"].visible = true
|
||||
all_flow["network_label"].visible = true
|
||||
bottom_flow["network"].visible = true
|
||||
bottom_flow["radio_button"].visible = true
|
||||
bottom_flow["radio_label"].visible = true
|
||||
elseif element.selected_index == 2 then
|
||||
set_comb_operation(comb, OPERATION_SECONDARY_IO)
|
||||
top_flow["switch"].visible = false
|
||||
all_flow["network_label"].visible = false
|
||||
bottom_flow["network"].visible = false
|
||||
bottom_flow["radio_button"].visible = false
|
||||
bottom_flow["radio_label"].visible = false
|
||||
elseif element.selected_index == 3 then
|
||||
set_comb_operation(comb, OPERATION_DEPOT)
|
||||
set_comb_operation(comb, MODE_DEPOT)
|
||||
top_flow["switch"].visible = false
|
||||
all_flow["network_label"].visible = true
|
||||
bottom_flow["network"].visible = true
|
||||
bottom_flow["radio_button"].visible = false
|
||||
bottom_flow["radio_label"].visible = false
|
||||
elseif element.selected_index == 3 then
|
||||
set_comb_operation(comb, MODE_REFUELER)
|
||||
top_flow["switch"].visible = false
|
||||
all_flow["network_label"].visible = true
|
||||
bottom_flow["network"].visible = true
|
||||
bottom_flow["radio_button"].visible = true
|
||||
bottom_flow["radio_label"].visible = true
|
||||
elseif element.selected_index == 4 then
|
||||
set_comb_operation(comb, OPERATION_WAGON_MANIFEST)
|
||||
set_comb_operation(comb, MODE_SECONDARY_IO)
|
||||
top_flow["switch"].visible = false
|
||||
all_flow["network_label"].visible = false
|
||||
bottom_flow["network"].visible = false
|
||||
bottom_flow["radio_button"].visible = false
|
||||
bottom_flow["radio_label"].visible = false
|
||||
elseif element.selected_index == 5 then
|
||||
set_comb_operation(comb, MODE_WAGON_MANIFEST)
|
||||
top_flow["switch"].visible = false
|
||||
all_flow["network_label"].visible = false
|
||||
bottom_flow["network"].visible = false
|
||||
|
||||
@@ -17,24 +17,30 @@ local function table_compare(t0, t1)
|
||||
return true
|
||||
end
|
||||
|
||||
---@param a any[]
|
||||
---@param i uint
|
||||
local function iterr(a, i)
|
||||
i = i + 1
|
||||
if i <= #a then
|
||||
return i, a[#a - i + 1]
|
||||
local r = a[#a - i + 1]
|
||||
return i, r
|
||||
else
|
||||
return nil, nil
|
||||
end
|
||||
end
|
||||
|
||||
---@param a any[]
|
||||
local function irpairs(a)
|
||||
return iterr, a, 0
|
||||
end
|
||||
|
||||
---@param layout_pattern (0|1|2|3)[]
|
||||
---@param layout (0|1|2)[]
|
||||
function is_layout_accepted(layout_pattern, layout)
|
||||
function is_refuel_layout_accepted(layout_pattern, layout)
|
||||
local valid = true
|
||||
for i, v in ipairs(layout) do
|
||||
local p = layout_pattern[i] or 0
|
||||
if (v == 0 and p == 2) or (v == 1 and (p == 0 or p == 2)) or (v == 2 and (p == 0 or p == 1)) then
|
||||
if (v == 1 and (p == 1 or p == 3)) or (v == 2 and (p == 2 or p == 3)) then
|
||||
valid = false
|
||||
break
|
||||
end
|
||||
@@ -42,7 +48,28 @@ function is_layout_accepted(layout_pattern, layout)
|
||||
if valid or not layout[0] then return valid end
|
||||
for i, v in irpairs(layout) do
|
||||
local p = layout_pattern[i] or 0
|
||||
if (v == 0 and p == 2) or (v == 1 and (p == 0 or p == 2)) or (v == 2 and (p == 0 or p == 1)) then
|
||||
if (v == 1 and (p == 1 or p == 3)) or (v == 2 and (p == 2 or p == 3)) then
|
||||
valid = false
|
||||
break
|
||||
end
|
||||
end
|
||||
return valid
|
||||
end
|
||||
---@param layout_pattern (0|1|2|3)[]
|
||||
---@param layout (0|1|2)[]
|
||||
function is_layout_accepted(layout_pattern, layout)
|
||||
local valid = true
|
||||
for i, v in ipairs(layout) do
|
||||
local p = layout_pattern[i] or 0
|
||||
if (v == 1 and not (p == 1 or p == 3)) or (v == 2 and not (p == 2 or p == 3)) then
|
||||
valid = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if valid or not layout[0] then return valid end
|
||||
for i, v in irpairs(layout) do
|
||||
local p = layout_pattern[i] or 0
|
||||
if (v == 1 and not (p == 1 or p == 3)) or (v == 2 and not (p == 2 or p == 3)) then
|
||||
valid = false
|
||||
break
|
||||
end
|
||||
@@ -142,7 +169,7 @@ end
|
||||
function set_p_wagon_combs(map_data, station, train)
|
||||
if not station.wagon_combs or not next(station.wagon_combs) then return end
|
||||
local carriages = train.entity.carriages
|
||||
local manifest = train.manifest
|
||||
local manifest = train.manifest--[[@as Manifest]]
|
||||
|
||||
local is_reversed = get_train_direction(station.entity_stop, train.entity)
|
||||
|
||||
@@ -288,7 +315,7 @@ function set_r_wagon_combs(map_data, station, train)
|
||||
local stack = inv[stack_i]
|
||||
if stack.valid_for_read then
|
||||
local i = #signals + 1
|
||||
signals[i] = {index = i, signal = {type = stack.type, name = stack.name}, count = -stack.count}
|
||||
signals[i] = {index = i, signal = {type = "item", name = stack.name}, count = -stack.count}
|
||||
end
|
||||
end
|
||||
set_combinator_output(map_data, comb, signals)
|
||||
@@ -306,76 +333,140 @@ function set_r_wagon_combs(map_data, station, train)
|
||||
end
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param station Station
|
||||
function unset_wagon_combs(map_data, station)
|
||||
if not station.wagon_combs then return end
|
||||
|
||||
for i, comb in pairs(station.wagon_combs) do
|
||||
---@param map_data MapData
|
||||
---@param refueler Refueler
|
||||
---@param train Train
|
||||
function set_refueler_combs(map_data, refueler, train)
|
||||
if not refueler.wagon_combs then return end
|
||||
local carriages = train.entity.carriages
|
||||
|
||||
local signals = {}
|
||||
|
||||
local is_reversed = get_train_direction(refueler.entity_stop, train.entity)
|
||||
local ivpairs = is_reversed and irpairs or ipairs
|
||||
for carriage_i, carriage in ivpairs(carriages) do
|
||||
---@type LuaEntity?
|
||||
local comb = refueler.wagon_combs[carriage_i]
|
||||
if comb and not comb.valid then
|
||||
comb = nil
|
||||
refueler.wagon_combs[carriage_i] = nil
|
||||
if next(refueler.wagon_combs) == nil then
|
||||
refueler.wagon_combs = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
local inv = carriage.get_fuel_inventory()
|
||||
if inv then
|
||||
local wagon_signals
|
||||
if comb then
|
||||
wagon_signals = {}
|
||||
local array = carriage.prototype.items_to_place_this
|
||||
if array then
|
||||
local a = array[1]
|
||||
local name
|
||||
if type(a) == "string" then
|
||||
name = a
|
||||
else
|
||||
name = a.name
|
||||
end
|
||||
if game.item_prototypes[name] then
|
||||
wagon_signals[1] = {index = 1, signal = {type = "item", name = a.name}, count = 1}
|
||||
end
|
||||
end
|
||||
end
|
||||
for stack_i = 1, #inv do
|
||||
local stack = inv[stack_i]
|
||||
if stack.valid_for_read then
|
||||
if comb then
|
||||
local i = #wagon_signals + 1
|
||||
wagon_signals[i] = {index = i, signal = {type = "item", name = stack.name}, count = stack.count}
|
||||
end
|
||||
local j = #signals + 1
|
||||
signals[j] = {index = j, signal = {type = "item", name = stack.name}, count = stack.count}
|
||||
end
|
||||
end
|
||||
if comb then
|
||||
set_combinator_output(map_data, comb, wagon_signals)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
set_combinator_output(map_data, refueler.entity_comb, signals)
|
||||
end
|
||||
|
||||
|
||||
---@param map_data MapData
|
||||
---@param stop Station|Refueler
|
||||
function unset_wagon_combs(map_data, stop)
|
||||
if not stop.wagon_combs then return end
|
||||
|
||||
for i, comb in pairs(stop.wagon_combs) do
|
||||
if comb.valid then
|
||||
set_combinator_output(map_data, comb, nil)
|
||||
else
|
||||
station.wagon_combs[i] = nil
|
||||
stop.wagon_combs[i] = nil
|
||||
end
|
||||
end
|
||||
if next(station.wagon_combs) == nil then
|
||||
station.wagon_combs = nil
|
||||
if next(stop.wagon_combs) == nil then
|
||||
stop.wagon_combs = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@param map_data MapData
|
||||
---@param station Station
|
||||
---@param stop Station|Refueler
|
||||
---@param is_station_or_refueler boolean
|
||||
---@param forbidden_entity LuaEntity?
|
||||
function reset_station_layout(map_data, station, forbidden_entity)
|
||||
function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_entity)
|
||||
--NOTE: station must be in auto mode
|
||||
local station_rail = station.entity_stop.connected_rail
|
||||
if station_rail == nil then
|
||||
local stop_rail = stop.entity_stop.connected_rail
|
||||
if stop_rail == nil then
|
||||
--cannot accept deliveries
|
||||
station.layout_pattern = nil
|
||||
station.accepted_layouts = {}
|
||||
stop.layout_pattern = nil
|
||||
stop.accepted_layouts = {}
|
||||
return
|
||||
end
|
||||
local rail_direction_from_station
|
||||
if station.entity_stop.connected_rail_direction == defines.rail_direction.front then
|
||||
rail_direction_from_station = defines.rail_direction.back
|
||||
local rail_direction_from_stop
|
||||
if stop.entity_stop.connected_rail_direction == defines.rail_direction.front then
|
||||
rail_direction_from_stop = defines.rail_direction.back
|
||||
else
|
||||
rail_direction_from_station = defines.rail_direction.front
|
||||
rail_direction_from_stop = defines.rail_direction.front
|
||||
end
|
||||
local station_direction = station.entity_stop.direction
|
||||
local surface = station.entity_stop.surface
|
||||
local middle_x = station_rail.position.x
|
||||
local middle_y = station_rail.position.y
|
||||
local stop_direction = stop.entity_stop.direction
|
||||
local surface = stop.entity_stop.surface
|
||||
local middle_x = stop_rail.position.x
|
||||
local middle_y = stop_rail.position.y
|
||||
local reach = LONGEST_INSERTER_REACH + 1
|
||||
local search_area
|
||||
local area_delta
|
||||
local is_ver
|
||||
if station_direction == defines.direction.north then
|
||||
if stop_direction == defines.direction.north then
|
||||
search_area = {left_top = {x = middle_x - reach, y = middle_y}, right_bottom = {x = middle_x + reach, y = middle_y + 6}}
|
||||
area_delta = {x = 0, y = 7}
|
||||
is_ver = true
|
||||
elseif station_direction == defines.direction.east then
|
||||
elseif stop_direction == defines.direction.east then
|
||||
search_area = {left_top = {y = middle_y - reach, x = middle_x - 6}, right_bottom = {y = middle_y + reach, x = middle_x}}
|
||||
area_delta = {x = -7, y = 0}
|
||||
is_ver = false
|
||||
elseif station_direction == defines.direction.south then
|
||||
elseif stop_direction == defines.direction.south then
|
||||
search_area = {left_top = {x = middle_x - reach, y = middle_y - 6}, right_bottom = {x = middle_x + reach, y = middle_y}}
|
||||
area_delta = {x = 0, y = -7}
|
||||
is_ver = true
|
||||
elseif station_direction == defines.direction.west then
|
||||
elseif stop_direction == defines.direction.west then
|
||||
search_area = {left_top = {y = middle_y - reach, x = middle_x}, right_bottom = {y = middle_y + reach, x = middle_x + 6}}
|
||||
area_delta = {x = 7, y = 0}
|
||||
is_ver = false
|
||||
else
|
||||
assert(false, "cybersyn: invalid station direction")
|
||||
assert(false, "cybersyn: invalid stop direction")
|
||||
end
|
||||
local length = 2
|
||||
local pre_rail = station_rail
|
||||
local pre_rail = stop_rail
|
||||
local layout_pattern = {0}
|
||||
local type_filter = {"inserter", "pump", "arithmetic-combinator"}
|
||||
local wagon_number = 0
|
||||
for i = 1, 112 do
|
||||
local rail, rail_direction, rail_connection_direction = pre_rail.get_connected_rail({rail_direction = rail_direction_from_station, rail_connection_direction = defines.rail_connection_direction.straight})
|
||||
local rail, rail_direction, rail_connection_direction = pre_rail.get_connected_rail({rail_direction = rail_direction_from_stop, rail_connection_direction = defines.rail_connection_direction.straight})
|
||||
if not rail or rail_connection_direction ~= defines.rail_connection_direction.straight or not rail.valid then
|
||||
is_break = true
|
||||
break
|
||||
@@ -428,7 +519,7 @@ function reset_station_layout(map_data, station, forbidden_entity)
|
||||
end
|
||||
elseif entity.name == COMBINATOR_NAME then
|
||||
local param = map_data.to_comb_params[entity.unit_number]
|
||||
if param.operation == OPERATION_WAGON_MANIFEST then
|
||||
if param.operation == MODE_WAGON_MANIFEST then
|
||||
local pos = entity.position
|
||||
local is_there
|
||||
if is_ver then
|
||||
@@ -437,10 +528,10 @@ function reset_station_layout(map_data, station, forbidden_entity)
|
||||
is_there = middle_y - 2.1 <= pos.y and pos.y <= middle_y + 2.1
|
||||
end
|
||||
if is_there then
|
||||
if not station.wagon_combs then
|
||||
station.wagon_combs = {}
|
||||
if not stop.wagon_combs then
|
||||
stop.wagon_combs = {}
|
||||
end
|
||||
station.wagon_combs[wagon_number] = entity
|
||||
stop.wagon_combs[wagon_number] = entity
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -461,18 +552,25 @@ function reset_station_layout(map_data, station, forbidden_entity)
|
||||
search_area = area.move(search_area, area_delta)
|
||||
end
|
||||
end
|
||||
station.layout_pattern = layout_pattern
|
||||
for id, layout in pairs(map_data.layouts) do
|
||||
station.accepted_layouts[id] = is_layout_accepted(layout_pattern, layout) or nil
|
||||
stop.layout_pattern = layout_pattern
|
||||
if is_station_or_refueler then
|
||||
for id, layout in pairs(map_data.layouts) do
|
||||
stop.accepted_layouts[id] = is_layout_accepted(layout_pattern, layout) or nil
|
||||
end
|
||||
else
|
||||
for id, layout in pairs(map_data.layouts) do
|
||||
stop.accepted_layouts[id] = is_refuel_layout_accepted(layout_pattern, layout) or nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param station Station
|
||||
---@param stop Station|Refueler
|
||||
---@param is_station_or_refueler boolean
|
||||
---@param forbidden_entity LuaEntity?
|
||||
function update_station_if_auto(map_data, station, forbidden_entity)
|
||||
if not station.allows_all_trains then
|
||||
reset_station_layout(map_data, station, forbidden_entity)
|
||||
function update_stop_if_auto(map_data, stop, is_station_or_refueler, forbidden_entity)
|
||||
if not stop.allows_all_trains then
|
||||
reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_entity)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -480,7 +578,7 @@ end
|
||||
---@param rail LuaEntity
|
||||
---@param forbidden_entity LuaEntity?
|
||||
---@param force boolean?
|
||||
function update_station_from_rail(map_data, rail, forbidden_entity, force)
|
||||
function update_stop_from_rail(map_data, rail, forbidden_entity, force)
|
||||
--NOTE: is this a correct way to figure out the direction?
|
||||
---@type defines.rail_direction
|
||||
local rail_direction = defines.rail_direction.back
|
||||
@@ -494,12 +592,18 @@ function update_station_from_rail(map_data, rail, forbidden_entity, force)
|
||||
return
|
||||
end
|
||||
if entity.name == "train-stop" then
|
||||
local station = map_data.stations[entity.unit_number]
|
||||
if station then
|
||||
local id = entity.unit_number
|
||||
local is_station = true
|
||||
local stop = map_data.stations[id]
|
||||
if not stop then
|
||||
stop = map_data.refuelers[id]
|
||||
is_station = false
|
||||
end
|
||||
if stop then
|
||||
if force then
|
||||
reset_station_layout(map_data, station, forbidden_entity)
|
||||
else
|
||||
update_station_if_auto(map_data, station, forbidden_entity)
|
||||
reset_stop_layout(map_data, stop, is_station, forbidden_entity)
|
||||
elseif not stop.allows_all_trains then
|
||||
reset_stop_layout(map_data, stop, is_station, forbidden_entity)
|
||||
end
|
||||
end
|
||||
return
|
||||
@@ -516,15 +620,15 @@ end
|
||||
---@param map_data MapData
|
||||
---@param pump LuaEntity
|
||||
---@param forbidden_entity LuaEntity?
|
||||
function update_station_from_pump(map_data, pump, forbidden_entity)
|
||||
function update_stop_from_pump(map_data, pump, forbidden_entity)
|
||||
if pump.pump_rail_target then
|
||||
update_station_from_rail(map_data, pump.pump_rail_target, forbidden_entity)
|
||||
update_stop_from_rail(map_data, pump.pump_rail_target, forbidden_entity)
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param inserter LuaEntity
|
||||
---@param forbidden_entity LuaEntity?
|
||||
function update_station_from_inserter(map_data, inserter, forbidden_entity)
|
||||
function update_stop_from_inserter(map_data, inserter, forbidden_entity)
|
||||
local surface = inserter.surface
|
||||
|
||||
--NOTE: we don't use find_entity solely for miniloader compat
|
||||
@@ -534,7 +638,7 @@ function update_station_from_inserter(map_data, inserter, forbidden_entity)
|
||||
radius = 1,
|
||||
})
|
||||
if rails[1] then
|
||||
update_station_from_rail(map_data, rails[1], forbidden_entity)
|
||||
update_stop_from_rail(map_data, rails[1], forbidden_entity)
|
||||
end
|
||||
rails = surface.find_entities_filtered({
|
||||
type = "straight-rail",
|
||||
@@ -542,6 +646,6 @@ function update_station_from_inserter(map_data, inserter, forbidden_entity)
|
||||
radius = 1,
|
||||
})
|
||||
if rails[1] then
|
||||
update_station_from_rail(map_data, rails[1], forbidden_entity)
|
||||
update_stop_from_rail(map_data, rails[1], forbidden_entity)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,138 +4,6 @@ local ceil = math.ceil
|
||||
local table_insert = table.insert
|
||||
|
||||
|
||||
---@param map_data MapData
|
||||
---@param station Station
|
||||
---@param manifest Manifest
|
||||
---@param sign int?
|
||||
local function set_comb1(map_data, station, manifest, sign)
|
||||
local comb = station.entity_comb1
|
||||
if comb.valid then
|
||||
if manifest then
|
||||
local signals = {}
|
||||
for i, item in ipairs(manifest) do
|
||||
signals[i] = {index = i, signal = {type = item.type, name = item.name}, count = sign*item.count}
|
||||
end
|
||||
set_combinator_output(map_data, comb, signals)
|
||||
else
|
||||
set_combinator_output(map_data, comb, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
function on_failed_delivery(map_data, train_id, train)
|
||||
--NOTE: must either change this train's status or remove it after this call
|
||||
local p_station_id = train.p_station_id
|
||||
local r_station_id = train.r_station_id
|
||||
local manifest = train.manifest
|
||||
local is_p_in_progress = train.status == STATUS_D_TO_P or train.status == STATUS_P
|
||||
local is_r_in_progress = is_p_in_progress or train.status == STATUS_P_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)
|
||||
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)
|
||||
end
|
||||
end
|
||||
train.r_station_id = 0
|
||||
train.p_station_id = 0
|
||||
train.manifest = nil
|
||||
interface_raise_train_failed_delivery(train_id, is_p_in_progress, p_station_id, is_r_in_progress, r_station_id, manifest)
|
||||
end
|
||||
|
||||
|
||||
|
||||
---@param map_data MapData
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
function add_available_train(map_data, train_id, train)
|
||||
local network_name = train.network_name
|
||||
if network_name then
|
||||
local network = map_data.available_trains[network_name]
|
||||
if not network then
|
||||
network = {}
|
||||
map_data.available_trains[network_name] = network
|
||||
end
|
||||
network[train_id] = true
|
||||
train.is_available = true
|
||||
interface_raise_train_available(train_id)
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param mod_settings CybersynModSettings
|
||||
---@param depot_id uint
|
||||
---@param depot Depot
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
function add_available_train_to_depot(map_data, mod_settings, train_id, train, depot_id, depot)
|
||||
local comb = depot.entity_comb
|
||||
local network_name = get_comb_network_name(comb)
|
||||
if network_name then
|
||||
local network = map_data.available_trains[network_name]
|
||||
if not network then
|
||||
network = {}
|
||||
map_data.available_trains[network_name] = network
|
||||
end
|
||||
network[train_id] = true
|
||||
train.is_available = true
|
||||
end
|
||||
depot.available_train_id = train_id
|
||||
train.status = STATUS_D
|
||||
train.parked_at_depot_id = depot_id
|
||||
train.depot_name = depot.entity_stop.backer_name
|
||||
train.se_depot_surface_i = depot.entity_stop.surface.index
|
||||
train.network_name = network_name
|
||||
train.network_flag = mod_settings.network_flag
|
||||
train.priority = 0
|
||||
if network_name then
|
||||
local signals = comb.get_merged_signals(defines.circuit_connector_id.combinator_input)
|
||||
if signals then
|
||||
for k, v in pairs(signals) do
|
||||
local item_name = v.signal.name
|
||||
local item_count = v.count
|
||||
if item_name then
|
||||
if item_name == SIGNAL_PRIORITY then
|
||||
train.priority = item_count
|
||||
end
|
||||
if item_name == network_name then
|
||||
train.network_flag = item_count
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
interface_raise_train_available(train_id)
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
function remove_available_train(map_data, train_id, train)
|
||||
---@type uint
|
||||
if train.is_available and train.network_name then
|
||||
local network = map_data.available_trains[train.network_name--[[@as string]]]
|
||||
if network then
|
||||
network[train_id] = nil
|
||||
if next(network) == nil then
|
||||
map_data.available_trains[train.network_name] = nil
|
||||
end
|
||||
end
|
||||
train.is_available = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@param map_data MapData
|
||||
---@param stop LuaEntity
|
||||
---@param comb LuaEntity
|
||||
@@ -152,8 +20,9 @@ local function on_depot_built(map_data, stop, comb)
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param depot_id uint
|
||||
---@param depot Depot
|
||||
local function on_depot_broken(map_data, depot)
|
||||
local function on_depot_broken(map_data, depot_id, depot)
|
||||
local train_id = depot.available_train_id
|
||||
if train_id then
|
||||
local train = map_data.trains[train_id]
|
||||
@@ -161,11 +30,70 @@ local function on_depot_broken(map_data, depot)
|
||||
send_lost_train_alert(train.entity, depot.entity_stop.backer_name)
|
||||
remove_train(map_data, train_id, train)
|
||||
end
|
||||
local depot_id = depot.entity_stop.unit_number--[[@as uint]]
|
||||
map_data.depots[depot_id] = nil
|
||||
interface_raise_depot_removed(depot_id, depot)
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param stop LuaEntity
|
||||
---@param comb LuaEntity
|
||||
local function on_refueler_built(map_data, stop, comb)
|
||||
--NOTE: only place where new Depot
|
||||
local refueler = {
|
||||
entity_stop = stop,
|
||||
entity_comb = comb,
|
||||
trains_total = 0,
|
||||
accepted_layouts = {},
|
||||
layout_pattern = {},
|
||||
--allows_all_trains = set_refueler_from_comb,
|
||||
--priority = set_refueler_from_comb,
|
||||
--network_name = set_refueler_from_comb,
|
||||
--network_flag = set_refueler_from_comb,
|
||||
}
|
||||
set_refueler_from_comb(mod_settings, refueler)
|
||||
local id = stop.unit_number--[[@as uint]]
|
||||
map_data.refuelers[id] = refueler
|
||||
update_stop_if_auto(map_data, refueler, false)
|
||||
if refueler.network_name then
|
||||
local network = map_data.to_refuelers[refueler.network_name]
|
||||
if not network then
|
||||
network = {}
|
||||
map_data.to_refuelers[refueler.network_name] = network
|
||||
end
|
||||
network[id] = true
|
||||
end
|
||||
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)
|
||||
if refueler.trains_total > 0 then
|
||||
--search for trains coming to the destroyed refueler
|
||||
for train_id, train in pairs(map_data.trains) do
|
||||
local is_f = train.refueler_id == refueler_id
|
||||
if is_f then
|
||||
if not train.se_is_being_teleported then
|
||||
remove_train(map_data, train_id, train)
|
||||
lock_train(train.entity)
|
||||
send_lost_train_alert(train.entity, train.depot_name)
|
||||
else
|
||||
train.se_awaiting_removal = train_id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if refueler.network_name then
|
||||
local network = map_data.to_refuelers[refueler.network_name]
|
||||
network[refueler_id] = nil
|
||||
if next(network) == nil then
|
||||
map_data.to_refuelers[refueler.network_name] = nil
|
||||
end
|
||||
end
|
||||
map_data.stations[refueler_id] = nil
|
||||
interface_raise_refueler_removed(refueler_id, refueler)
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param stop LuaEntity
|
||||
---@param comb1 LuaEntity
|
||||
@@ -182,6 +110,7 @@ local function on_station_built(map_data, stop, comb1, comb2)
|
||||
deliveries_total = 0,
|
||||
last_delivery_tick = map_data.total_ticks,
|
||||
priority = 0,
|
||||
item_priotity = nil,
|
||||
r_threshold = 0,
|
||||
locked_slots = 0,
|
||||
--network_name = set_station_from_comb_state,
|
||||
@@ -191,7 +120,8 @@ local function on_station_built(map_data, stop, comb1, comb2)
|
||||
accepted_layouts = {},
|
||||
layout_pattern = nil,
|
||||
tick_signals = nil,
|
||||
p_count_or_r_threshold_per_item = {},
|
||||
item_p_counts = {},
|
||||
item_thresholds = nil,
|
||||
display_state = 0,
|
||||
}
|
||||
set_station_from_comb_state(station)
|
||||
@@ -199,7 +129,7 @@ local function on_station_built(map_data, stop, comb1, comb2)
|
||||
map_data.stations[id] = station
|
||||
map_data.warmup_station_ids[#map_data.warmup_station_ids + 1] = id
|
||||
|
||||
update_station_if_auto(map_data, station, nil)
|
||||
update_stop_if_auto(map_data, station, true)
|
||||
interface_raise_station_created(id)
|
||||
end
|
||||
---@param map_data MapData
|
||||
@@ -213,8 +143,8 @@ local function on_station_broken(map_data, station_id, station)
|
||||
local is_p = train.p_station_id == station_id
|
||||
if is_p or is_r then
|
||||
|
||||
local is_p_in_progress = train.status == STATUS_D_TO_P or train.status == STATUS_P
|
||||
local is_r_in_progress = is_p_in_progress or train.status == STATUS_P_TO_R or train.status == STATUS_R
|
||||
local is_p_in_progress = train.status == STATUS_TO_P or train.status == STATUS_P
|
||||
local is_r_in_progress = is_p_in_progress or train.status == STATUS_TO_R or train.status == STATUS_R
|
||||
if (is_p and is_p_in_progress) or (is_r and is_r_in_progress) then
|
||||
--train is attempting delivery to a stop that was destroyed, stop it
|
||||
on_failed_delivery(map_data, train_id, train)
|
||||
@@ -311,13 +241,13 @@ local function on_combinator_built(map_data, comb)
|
||||
local params = control.parameters
|
||||
local op = params.operation
|
||||
|
||||
if op == OPERATION_DEFAULT then
|
||||
op = OPERATION_PRIMARY_IO
|
||||
if op == MODE_DEFAULT then
|
||||
op = MODE_PRIMARY_IO
|
||||
params.operation = op
|
||||
params.first_signal = NETWORK_SIGNAL_DEFAULT
|
||||
control.parameters = params
|
||||
elseif op ~= OPERATION_PRIMARY_IO and op ~= OPERATION_SECONDARY_IO and op ~= OPERATION_DEPOT and op ~= OPERATION_WAGON_MANIFEST then
|
||||
op = OPERATION_PRIMARY_IO
|
||||
elseif op ~= MODE_PRIMARY_IO and op ~= MODE_SECONDARY_IO and op ~= MODE_DEPOT and op ~= MODE_REFUELER and op ~= MODE_WAGON_MANIFEST then
|
||||
op = MODE_PRIMARY_IO
|
||||
params.operation = op
|
||||
control.parameters = params
|
||||
end
|
||||
@@ -327,43 +257,39 @@ local function on_combinator_built(map_data, comb)
|
||||
map_data.to_output[comb.unit_number] = out
|
||||
map_data.to_stop[comb.unit_number] = stop
|
||||
|
||||
if op == OPERATION_WAGON_MANIFEST then
|
||||
if op == MODE_WAGON_MANIFEST then
|
||||
if rail then
|
||||
update_station_from_rail(map_data, rail, nil, true)
|
||||
update_stop_from_rail(map_data, rail, nil, true)
|
||||
end
|
||||
elseif op == OPERATION_DEPOT then
|
||||
if stop then
|
||||
local station = map_data.stations[stop.unit_number]
|
||||
---@type Depot
|
||||
local depot = map_data.depots[stop.unit_number]
|
||||
if depot or station then
|
||||
--NOTE: repeated combinators are ignored
|
||||
else
|
||||
elseif stop then
|
||||
local id = stop.unit_number--[[@as uint]]
|
||||
local station = map_data.stations[id]
|
||||
local depot = map_data.depots[id]
|
||||
local refueler = map_data.refuelers[id]
|
||||
if op == MODE_DEPOT then
|
||||
if refueler then
|
||||
on_refueler_broken(map_data, id, refueler)
|
||||
end
|
||||
if not station and not depot then
|
||||
on_depot_built(map_data, stop, comb)
|
||||
end
|
||||
end
|
||||
elseif op == OPERATION_SECONDARY_IO then
|
||||
if stop then
|
||||
local station = map_data.stations[stop.unit_number]
|
||||
elseif op == MODE_REFUELER then
|
||||
if not station and not depot and not refueler then
|
||||
on_refueler_built(map_data, stop, comb)
|
||||
end
|
||||
elseif op == MODE_SECONDARY_IO then
|
||||
if station and not station.entity_comb2 then
|
||||
station.entity_comb2 = comb
|
||||
end
|
||||
end
|
||||
elseif op == OPERATION_PRIMARY_IO then
|
||||
if stop then
|
||||
local station = map_data.stations[stop.unit_number]
|
||||
if station then
|
||||
--NOTE: repeated combinators are ignored
|
||||
else
|
||||
local depot = map_data.depots[stop.unit_number]
|
||||
if depot then
|
||||
on_depot_broken(map_data, depot)
|
||||
end
|
||||
--no station or depot
|
||||
--add station
|
||||
|
||||
local comb2 = search_for_station_combinator(map_data, stop, OPERATION_SECONDARY_IO, comb)
|
||||
|
||||
elseif op == MODE_PRIMARY_IO then
|
||||
if refueler then
|
||||
on_refueler_broken(map_data, id, refueler)
|
||||
end
|
||||
if depot then
|
||||
on_depot_broken(map_data, id, depot)
|
||||
end
|
||||
if not station then
|
||||
local comb2 = search_for_station_combinator(map_data, stop, MODE_SECONDARY_IO, comb)
|
||||
on_station_built(map_data, stop, comb, comb2)
|
||||
end
|
||||
end
|
||||
@@ -376,20 +302,43 @@ function on_combinator_network_updated(map_data, comb, network_name)
|
||||
local stop = map_data.to_stop[comb.unit_number]
|
||||
|
||||
if stop and stop.valid then
|
||||
local station = map_data.stations[stop.unit_number]
|
||||
local id = stop.unit_number
|
||||
local station = map_data.stations[id]
|
||||
if station then
|
||||
if station.entity_comb1 == comb then
|
||||
station.network_name = network_name
|
||||
end
|
||||
else
|
||||
local depot_id = stop.unit_number
|
||||
local depot = map_data.depots[depot_id]
|
||||
if depot and depot.entity_comb == comb then
|
||||
local train_id = depot.available_train_id
|
||||
if train_id then
|
||||
local train = map_data.trains[train_id]
|
||||
remove_available_train(map_data, train_id, train)
|
||||
add_available_train_to_depot(map_data, mod_settings, train_id, train, depot_id, depot)
|
||||
local depot = map_data.depots[id]
|
||||
if depot then
|
||||
if depot.entity_comb == comb then
|
||||
local train_id = depot.available_train_id
|
||||
if train_id then
|
||||
local train = map_data.trains[train_id]
|
||||
remove_available_train(map_data, train_id, train)
|
||||
add_available_train_to_depot(map_data, mod_settings, train_id, train, id, depot)
|
||||
interface_raise_train_status_changed(train_id, STATUS_D, STATUS_D)
|
||||
end
|
||||
end
|
||||
else
|
||||
local refueler = map_data.refuelers[id]
|
||||
if refueler and refueler.entity_comb == comb then
|
||||
if refueler.network_name then
|
||||
local network = map_data.to_refuelers[refueler.network_name]
|
||||
network[id] = nil
|
||||
if next(network) == nil then
|
||||
map_data.to_refuelers[refueler.network_name] = nil
|
||||
end
|
||||
end
|
||||
refueler.network_name = network_name
|
||||
if network_name then
|
||||
local network = map_data.to_refuelers[network_name]
|
||||
if network == nil then
|
||||
network = {}
|
||||
map_data.to_refuelers[network_name] = network
|
||||
end
|
||||
network[id] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -405,33 +354,27 @@ function on_combinator_broken(map_data, comb)
|
||||
local stop = map_data.to_stop[comb_id]
|
||||
|
||||
if stop and stop.valid then
|
||||
local station = map_data.stations[stop.unit_number]
|
||||
local id = stop.unit_number--[[@as uint]]
|
||||
local station = map_data.stations[id]
|
||||
if station then
|
||||
if station.entity_comb1 == comb then
|
||||
local comb1 = search_for_station_combinator(map_data, stop, OPERATION_PRIMARY_IO, comb)
|
||||
if comb1 then
|
||||
station.entity_comb1 = comb1
|
||||
set_station_from_comb_state(station)
|
||||
update_station_if_auto(map_data, station)
|
||||
else
|
||||
on_station_broken(map_data, stop.unit_number, station)
|
||||
local depot_comb = search_for_station_combinator(map_data, stop, OPERATION_DEPOT, comb)
|
||||
if depot_comb then
|
||||
on_depot_built(map_data, stop, depot_comb)
|
||||
end
|
||||
end
|
||||
on_station_broken(map_data, id, station)
|
||||
on_stop_built(map_data, stop, comb)
|
||||
elseif station.entity_comb2 == comb then
|
||||
station.entity_comb2 = search_for_station_combinator(map_data, stop, OPERATION_SECONDARY_IO, comb)
|
||||
station.entity_comb2 = search_for_station_combinator(map_data, stop, MODE_SECONDARY_IO, comb)
|
||||
end
|
||||
else
|
||||
local depot = map_data.depots[stop.unit_number]
|
||||
if depot and depot.entity_comb == comb then
|
||||
--NOTE: this will disrupt deliveries in progress that where dispatched from this station in a minor way
|
||||
local depot_comb = search_for_station_combinator(map_data, stop, OPERATION_DEPOT, comb)
|
||||
if depot_comb then
|
||||
depot.entity_comb = depot_comb
|
||||
else
|
||||
on_depot_broken(map_data, depot)
|
||||
local depot = map_data.depots[id]
|
||||
if depot then
|
||||
if depot.entity_comb == comb then
|
||||
on_depot_broken(map_data, id, depot)
|
||||
on_stop_built(map_data, stop, comb)
|
||||
end
|
||||
else
|
||||
local refueler = map_data.refuelers[id]
|
||||
if refueler and refueler.entity_comb == comb then
|
||||
on_refueler_broken(map_data, id, depot)
|
||||
on_stop_built(map_data, stop, comb)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -449,17 +392,16 @@ end
|
||||
---@param map_data MapData
|
||||
---@param comb LuaEntity
|
||||
function combinator_update(map_data, comb)
|
||||
---@type uint
|
||||
local unit_number = comb.unit_number
|
||||
local unit_number = comb.unit_number--[[@as uint]]
|
||||
local control = get_comb_control(comb)
|
||||
local params = control.parameters
|
||||
local old_params = map_data.to_comb_params[unit_number]
|
||||
local has_changed = false
|
||||
|
||||
if params.operation ~= old_params.operation then
|
||||
if (old_params.operation == OPERATION_PRIMARY_IO) and (params.operation == OPERATION_PRIMARY_IO_ACTIVE or params.operation == OPERATION_PRIMARY_IO_FAILED_REQUEST) then
|
||||
--make sure only OPERATION_PRIMARY_IO gets stored on map_data.to_comb_params
|
||||
params.operation = OPERATION_PRIMARY_IO
|
||||
if (old_params.operation == MODE_PRIMARY_IO) and (params.operation == MODE_PRIMARY_IO_ACTIVE or params.operation == MODE_PRIMARY_IO_FAILED_REQUEST) then
|
||||
--make sure only MODE_PRIMARY_IO gets stored on map_data.to_comb_params
|
||||
params.operation = MODE_PRIMARY_IO
|
||||
else
|
||||
--NOTE: This is rather dangerous, we may need to actually implement operation changing
|
||||
on_combinator_broken(map_data, comb)
|
||||
@@ -473,21 +415,29 @@ function combinator_update(map_data, comb)
|
||||
local new_network = new_signal and new_signal.name or nil
|
||||
local old_network = old_signal and old_signal.name or nil
|
||||
if new_network ~= old_network then
|
||||
has_changed = true
|
||||
on_combinator_network_updated(map_data, comb, new_network)
|
||||
end
|
||||
if params.second_constant ~= old_params.second_constant then
|
||||
local stop = global.to_stop[comb.unit_number]
|
||||
has_changed = true
|
||||
local stop = map_data.to_stop[comb.unit_number]
|
||||
if stop then
|
||||
local station = global.stations[stop.unit_number]
|
||||
local id = stop.unit_number
|
||||
local station = map_data.stations[id]
|
||||
if station then
|
||||
local bits = params.second_constant
|
||||
local is_pr_state = floor(bits/2)%3
|
||||
station.is_p = is_pr_state == 0 or is_pr_state == 1
|
||||
station.is_r = is_pr_state == 0 or is_pr_state == 2
|
||||
local allows_all_trains = bits%2 == 1
|
||||
if station.allows_all_trains ~= allows_all_trains then
|
||||
station.allows_all_trains = allows_all_trains
|
||||
update_station_if_auto(map_data, station)
|
||||
local pre = station.allows_all_trains
|
||||
set_station_from_comb_state(station)
|
||||
if station.allows_all_trains ~= pre then
|
||||
update_stop_if_auto(map_data, station, true)
|
||||
end
|
||||
else
|
||||
local refueler = map_data.refuelers[id]
|
||||
if refueler then
|
||||
local pre = refueler.allows_all_trains
|
||||
set_refueler_from_comb(mod_settings, refueler)
|
||||
if refueler.allows_all_trains ~= pre then
|
||||
update_stop_if_auto(map_data, refueler, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -500,7 +450,8 @@ end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param stop LuaEntity
|
||||
local function on_stop_built(map_data, stop)
|
||||
---@param comb_forbidden LuaEntity?
|
||||
function on_stop_built(map_data, stop, comb_forbidden)
|
||||
local pos_x = stop.position.x
|
||||
local pos_y = stop.position.y
|
||||
|
||||
@@ -511,18 +462,21 @@ local function on_stop_built(map_data, stop)
|
||||
local comb2 = nil
|
||||
local comb1 = nil
|
||||
local depot_comb = nil
|
||||
local refueler_comb = nil
|
||||
local entities = stop.surface.find_entities(search_area)
|
||||
for _, entity in pairs(entities) do
|
||||
if entity.valid and entity.name == COMBINATOR_NAME and map_data.to_stop[entity.unit_number] == nil then
|
||||
if entity.valid and entity ~= comb_forbidden and entity.name == COMBINATOR_NAME and map_data.to_stop[entity.unit_number] == nil then
|
||||
map_data.to_stop[entity.unit_number] = stop
|
||||
local param = get_comb_params(entity)
|
||||
local op = param.operation
|
||||
if op == OPERATION_PRIMARY_IO then
|
||||
if op == MODE_PRIMARY_IO then
|
||||
comb1 = entity
|
||||
elseif op == OPERATION_SECONDARY_IO then
|
||||
elseif op == MODE_SECONDARY_IO then
|
||||
comb2 = entity
|
||||
elseif op == OPERATION_DEPOT then
|
||||
elseif op == MODE_DEPOT then
|
||||
depot_comb = entity
|
||||
elseif op == MODE_REFUELER then
|
||||
refueler_comb = entity
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -530,6 +484,8 @@ local function on_stop_built(map_data, stop)
|
||||
on_station_built(map_data, stop, comb1, comb2)
|
||||
elseif depot_comb then
|
||||
on_depot_built(map_data, stop, depot_comb)
|
||||
elseif refueler_comb then
|
||||
on_refueler_built(map_data, stop, refueler_comb)
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
@@ -549,20 +505,26 @@ local function on_stop_broken(map_data, stop)
|
||||
end
|
||||
end
|
||||
|
||||
local station = map_data.stations[stop.unit_number]
|
||||
local id = stop.unit_number--[[@as uint]]
|
||||
local station = map_data.stations[id]
|
||||
if station then
|
||||
on_station_broken(map_data, stop.unit_number, station)
|
||||
on_station_broken(map_data, id, station)
|
||||
else
|
||||
local depot = map_data.depots[stop.unit_number]
|
||||
local depot = map_data.depots[id]
|
||||
if depot then
|
||||
on_depot_broken(map_data, depot)
|
||||
on_depot_broken(map_data, id, depot)
|
||||
else
|
||||
local refueler = map_data.refuelers[id]
|
||||
if refueler then
|
||||
on_refueler_broken(map_data, id, refueler)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param stop LuaEntity
|
||||
---@param old_name string
|
||||
local function on_station_rename(map_data, stop, old_name)
|
||||
local function on_stop_rename(map_data, stop, old_name)
|
||||
--search for trains coming to the renamed station
|
||||
local station_id = stop.unit_number--[[@as uint]]
|
||||
local station = map_data.stations[station_id]
|
||||
@@ -571,8 +533,8 @@ local function on_station_rename(map_data, stop, old_name)
|
||||
local is_p = train.p_station_id == station_id
|
||||
local is_r = train.r_station_id == station_id
|
||||
if is_p or is_r then
|
||||
local is_p_in_progress = train.status == STATUS_D_TO_P or train.status == STATUS_P
|
||||
local is_r_in_progress = is_p_in_progress or train.status == STATUS_P_TO_R or train.status == STATUS_R
|
||||
local is_p_in_progress = train.status == STATUS_TO_P or train.status == STATUS_P
|
||||
local is_r_in_progress = is_p_in_progress or train.status == STATUS_TO_R or train.status == STATUS_R
|
||||
if is_r and is_r_in_progress then
|
||||
local r_station = map_data.stations[train.r_station_id]
|
||||
if not train.se_is_being_teleported then
|
||||
@@ -614,209 +576,6 @@ local function find_and_add_all_stations_from_nothing(map_data)
|
||||
end
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param depot_id uint
|
||||
---@param train_entity LuaTrain
|
||||
local function on_train_arrives_depot(map_data, depot_id, train_entity)
|
||||
local contents = train_entity.get_contents()
|
||||
local fluid_contents = train_entity.get_fluid_contents()
|
||||
local is_train_empty = next(contents) == nil and next(fluid_contents) == nil
|
||||
local train_id = train_entity.id
|
||||
local train = map_data.trains[train_id]
|
||||
if train then
|
||||
if train.manifest then
|
||||
if train.status == STATUS_R_TO_D then
|
||||
--succeeded delivery
|
||||
train.p_station_id = 0
|
||||
train.r_station_id = 0
|
||||
train.manifest = nil
|
||||
elseif mod_settings.react_to_train_early_to_depot then
|
||||
on_failed_delivery(map_data, train_id, train)
|
||||
send_unexpected_train_alert(train.entity)
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
if is_train_empty then
|
||||
remove_available_train(map_data, train_id, train)
|
||||
add_available_train_to_depot(map_data, mod_settings, train_id, train, depot_id, map_data.depots[depot_id])
|
||||
set_depot_schedule(train_entity, train.depot_name)
|
||||
interface_raise_train_parked_at_depot(train_id, depot_id)
|
||||
else
|
||||
--train still has cargo
|
||||
if mod_settings.react_to_nonempty_train_in_depot then
|
||||
lock_train(train_entity)
|
||||
remove_train(map_data, train_id, train)
|
||||
send_nonempty_train_in_depot_alert(train_entity)
|
||||
end
|
||||
interface_raise_train_nonempty_in_depot(depot_id, train_entity, train_id)
|
||||
end
|
||||
elseif is_train_empty then
|
||||
--NOTE: only place where new Train
|
||||
train = {
|
||||
entity = train_entity,
|
||||
--layout_id = set_train_layout,
|
||||
--item_slot_capacity = set_train_layout,
|
||||
--fluid_capacity = set_train_layout,
|
||||
--status = add_available_train_to_depot,
|
||||
p_station_id = 0,
|
||||
r_station_id = 0,
|
||||
manifest = nil,
|
||||
last_manifest_tick = map_data.total_ticks,
|
||||
has_filtered_wagon = nil,
|
||||
--is_available = add_available_train_to_depot,
|
||||
--parked_at_depot_id = add_available_train_to_depot,
|
||||
--depot_name = add_available_train_to_depot,
|
||||
--network_name = add_available_train_to_depot,
|
||||
--network_flag = add_available_train_to_depot,
|
||||
--priority = add_available_train_to_depot,
|
||||
}
|
||||
set_train_layout(map_data, train)
|
||||
map_data.trains[train_id] = train
|
||||
add_available_train_to_depot(map_data, mod_settings, train_id, train, depot_id, map_data.depots[depot_id])
|
||||
|
||||
set_depot_schedule(train_entity, train.depot_name)
|
||||
interface_raise_train_created(train_id, depot_id)
|
||||
else
|
||||
if mod_settings.react_to_nonempty_train_in_depot then
|
||||
lock_train(train_entity)
|
||||
send_nonempty_train_in_depot_alert(train_entity)
|
||||
end
|
||||
interface_raise_train_nonempty_in_depot(depot_id, train_entity)
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param stop LuaEntity
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
local function on_train_arrives_buffer(map_data, stop, train_id, train)
|
||||
if train.manifest then
|
||||
---@type uint
|
||||
local station_id = stop.unit_number
|
||||
if train.status == STATUS_D_TO_P then
|
||||
if train.p_station_id == station_id then
|
||||
train.status = STATUS_P
|
||||
local station = map_data.stations[station_id]
|
||||
set_comb1(map_data, station, train.manifest, 1)
|
||||
set_p_wagon_combs(map_data, station, train)
|
||||
end
|
||||
elseif train.status == STATUS_P_TO_R then
|
||||
if train.r_station_id == station_id then
|
||||
train.status = STATUS_R
|
||||
local station = map_data.stations[station_id]
|
||||
set_comb1(map_data, station, train.manifest, -1)
|
||||
set_r_wagon_combs(map_data, station, train)
|
||||
end
|
||||
elseif train.status == STATUS_P and train.p_station_id == station_id then
|
||||
--this player intervention that is considered valid
|
||||
elseif (train.status == STATUS_R or train.status == STATUS_R_TO_D) and train.r_station_id == station_id then
|
||||
--this player intervention that is considered valid
|
||||
elseif mod_settings.react_to_train_at_incorrect_station then
|
||||
on_failed_delivery(map_data, train_id, train)
|
||||
remove_train(map_data, train_id, train)
|
||||
lock_train(train.entity)
|
||||
send_lost_train_alert(train.entity, train.depot_name)
|
||||
end
|
||||
elseif mod_settings.react_to_train_at_incorrect_station then
|
||||
--train is lost somehow, probably from player intervention
|
||||
remove_train(map_data, train_id, train)
|
||||
send_lost_train_alert(train.entity, train.depot_name)
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param mod_settings CybersynModSettings
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
local function on_train_leaves_station(map_data, mod_settings, train_id, train)
|
||||
if train.manifest then
|
||||
if train.status == STATUS_P then
|
||||
train.status = STATUS_P_TO_R
|
||||
local station = map_data.stations[train.p_station_id]
|
||||
remove_manifest(map_data, station, train.manifest, 1)
|
||||
set_comb1(map_data, station, nil)
|
||||
unset_wagon_combs(map_data, station)
|
||||
if train.has_filtered_wagon then
|
||||
train.has_filtered_wagon = nil
|
||||
for carriage_i, carriage in ipairs(train.entity.cargo_wagons) do
|
||||
local inv = carriage.get_inventory(defines.inventory.cargo_wagon)
|
||||
if inv and inv.is_filtered() then
|
||||
---@type uint
|
||||
for i = 1, #inv do
|
||||
inv.set_filter(i, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
interface_raise_train_completed_provide(train_id)
|
||||
elseif train.status == STATUS_R then
|
||||
train.status = STATUS_R_TO_D
|
||||
local station = map_data.stations[train.r_station_id]
|
||||
remove_manifest(map_data, station, train.manifest, -1)
|
||||
set_comb1(map_data, station, nil)
|
||||
unset_wagon_combs(map_data, station)
|
||||
--add to available trains for depot bypass
|
||||
local fuel_fill = 0
|
||||
local total_slots = 0
|
||||
for k, v in pairs(train.entity.locomotives) do
|
||||
if v[1] then
|
||||
local inv = v[1].get_fuel_inventory()
|
||||
if inv then
|
||||
local inv_size = #inv
|
||||
total_slots = total_slots + inv_size
|
||||
for i = 1, inv_size do
|
||||
local item = inv[i--[[@as uint]]]
|
||||
local count = item.count
|
||||
if count > 0 then
|
||||
fuel_fill = fuel_fill + count/get_stack_size(map_data, item.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if total_slots == 0 then
|
||||
--if total_slots == 0 it's probably a modded electric train
|
||||
if mod_settings.depot_bypass_threshold < 1 then
|
||||
add_available_train(map_data, train_id, train)
|
||||
end
|
||||
elseif fuel_fill/total_slots > mod_settings.depot_bypass_threshold then
|
||||
add_available_train(map_data, train_id, train)
|
||||
end
|
||||
interface_raise_train_completed_request(train_id)
|
||||
end
|
||||
elseif train.status == STATUS_D then
|
||||
--The train is leaving the depot without a manifest, the player likely intervened
|
||||
local depot = map_data.depots[train.parked_at_depot_id--[[@as uint]]]
|
||||
remove_train(map_data, train_id, train)
|
||||
send_lost_train_alert(train.entity, depot.entity_stop.backer_name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@param map_data MapData
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
local 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 train.manifest then
|
||||
on_failed_delivery(map_data, train_id, train)
|
||||
end
|
||||
remove_train(map_data, train_id, train)
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param pre_train_id uint
|
||||
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.manifest then
|
||||
on_failed_delivery(map_data, pre_train_id, train)
|
||||
end
|
||||
remove_train(map_data, pre_train_id, train)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function on_built(event)
|
||||
local entity = event.entity or event.created_entity
|
||||
@@ -827,11 +586,11 @@ local function on_built(event)
|
||||
elseif entity.name == COMBINATOR_NAME then
|
||||
on_combinator_built(global, entity)
|
||||
elseif entity.type == "inserter" then
|
||||
update_station_from_inserter(global, entity)
|
||||
update_stop_from_inserter(global, entity)
|
||||
elseif entity.type == "pump" then
|
||||
update_station_from_pump(global, entity)
|
||||
update_stop_from_pump(global, entity)
|
||||
elseif entity.type == "straight-rail" then
|
||||
update_station_from_rail(global, entity)
|
||||
update_stop_from_rail(global, entity)
|
||||
end
|
||||
end
|
||||
local function on_broken(event)
|
||||
@@ -843,11 +602,11 @@ local function on_broken(event)
|
||||
elseif entity.name == COMBINATOR_NAME then
|
||||
on_combinator_broken(global, entity)
|
||||
elseif entity.type == "inserter" then
|
||||
update_station_from_inserter(global, entity, entity)
|
||||
update_stop_from_inserter(global, entity, entity)
|
||||
elseif entity.type == "pump" then
|
||||
update_station_from_pump(global, entity, entity)
|
||||
update_stop_from_pump(global, entity, entity)
|
||||
elseif entity.type == "straight-rail" then
|
||||
update_station_from_rail(global, entity, nil)
|
||||
update_stop_from_rail(global, entity, nil)
|
||||
elseif entity.train then
|
||||
local train_id = entity.train.id
|
||||
local train = global.trains[train_id]
|
||||
@@ -861,47 +620,7 @@ local function on_rotate(event)
|
||||
if not entity or not entity.valid then return end
|
||||
|
||||
if entity.type == "inserter" then
|
||||
update_station_from_inserter(global, entity)
|
||||
end
|
||||
end
|
||||
local function on_rename(event)
|
||||
if event.entity.name == "train-stop" then
|
||||
on_station_rename(global, event.entity, event.old_name)
|
||||
end
|
||||
end
|
||||
|
||||
local function on_train_built(event)
|
||||
local train_e = event.train
|
||||
if event.old_train_id_1 then
|
||||
on_train_modified(global, event.old_train_id_1)
|
||||
end
|
||||
if event.old_train_id_2 then
|
||||
on_train_modified(global, event.old_train_id_2)
|
||||
end
|
||||
end
|
||||
local function on_train_changed(event)
|
||||
local train_e = event.train--[[@as LuaTrain]]
|
||||
if not train_e.valid then return end
|
||||
local train_id = train_e.id
|
||||
local train = global.trains[train_id]
|
||||
if train_e.state == defines.train_state.wait_station then
|
||||
local stop = train_e.station
|
||||
if stop and stop.valid and stop.name == "train-stop" then
|
||||
if global.stations[stop.unit_number] then
|
||||
if train then
|
||||
on_train_arrives_buffer(global, stop, train_id, train)
|
||||
end
|
||||
else
|
||||
local depot_id = stop.unit_number--[[@as uint]]
|
||||
if global.depots[depot_id] then
|
||||
on_train_arrives_depot(global, depot_id, train_e)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif event.old_state == defines.train_state.wait_station then
|
||||
if train then
|
||||
on_train_leaves_station(global, mod_settings, train_id, train)
|
||||
end
|
||||
update_stop_from_inserter(global, entity)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -927,13 +646,20 @@ local function on_paste(event)
|
||||
end
|
||||
end
|
||||
|
||||
local function on_rename(event)
|
||||
if event.entity.name == "train-stop" then
|
||||
on_stop_rename(global, event.entity, event.old_name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function on_settings_changed(event)
|
||||
mod_settings.tps = settings.global["cybersyn-ticks-per-second"].value --[[@as double]]
|
||||
mod_settings.update_rate = settings.global["cybersyn-update-rate"].value --[[@as int]]
|
||||
mod_settings.r_threshold = settings.global["cybersyn-request-threshold"].value--[[@as int]]
|
||||
mod_settings.network_flag = settings.global["cybersyn-network-flag"].value--[[@as int]]
|
||||
mod_settings.depot_bypass_threshold = settings.global["cybersyn-depot-bypass-threshold"].value--[[@as double]]
|
||||
mod_settings.fuel_threshold = settings.global["cybersyn-fuel-threshold"].value--[[@as double]]
|
||||
mod_settings.depot_bypass_enabled = settings.global["cybersyn-depot-bypass-enabled"].value--[[@as boolean]]
|
||||
mod_settings.warmup_time = settings.global["cybersyn-warmup-time"].value--[[@as double]]
|
||||
mod_settings.stuck_train_time = settings.global["cybersyn-stuck-train-time"].value--[[@as double]]
|
||||
if event.setting == "cybersyn-ticks-per-second" then
|
||||
@@ -946,6 +672,7 @@ local function on_settings_changed(event)
|
||||
script.on_nth_tick(nil)
|
||||
end
|
||||
end
|
||||
interface_raise_on_mod_settings_changed(event)
|
||||
end
|
||||
|
||||
local function setup_se_compat()
|
||||
@@ -1012,29 +739,45 @@ local function setup_se_compat()
|
||||
train.se_awaiting_rename = nil
|
||||
end
|
||||
|
||||
if not (train.status == STATUS_D_TO_P or train.status == STATUS_P_TO_R) then return end
|
||||
if not (train.status == STATUS_TO_P or train.status == STATUS_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))
|
||||
if train.status == STATUS_TO_P or train.status == STATUS_TO_R 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
|
||||
i = i + 1
|
||||
train_entity.schedule = schedule
|
||||
elseif train.status == STATUS_TO_F then
|
||||
local refueler = map_data.refuelers[train.refueler_id]
|
||||
local f_name = refueler.entity_stop.backer_name
|
||||
local f_surface_i = refueler.entity_stop.surface.index
|
||||
local records = schedule.records
|
||||
local i = schedule.current
|
||||
while i <= #records do
|
||||
if records[i].station == f_name and f_surface_i ~= old_surface_index then
|
||||
table_insert(records, i, create_direct_to_station_order(refueler.entity_stop))
|
||||
i = i + 1
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
train_entity.schedule = schedule
|
||||
end
|
||||
train_entity.schedule = schedule
|
||||
end
|
||||
interface_raise_train_teleported(new_id, old_id)
|
||||
end)
|
||||
@@ -1061,9 +804,10 @@ local function main()
|
||||
mod_settings.update_rate = settings.global["cybersyn-update-rate"].value --[[@as int]]
|
||||
mod_settings.r_threshold = settings.global["cybersyn-request-threshold"].value--[[@as int]]
|
||||
mod_settings.network_flag = settings.global["cybersyn-network-flag"].value--[[@as int]]
|
||||
mod_settings.depot_bypass_threshold = settings.global["cybersyn-depot-bypass-threshold"].value--[[@as double]]
|
||||
mod_settings.fuel_threshold = settings.global["cybersyn-fuel-threshold"].value--[[@as double]]
|
||||
mod_settings.warmup_time = settings.global["cybersyn-warmup-time"].value--[[@as double]]
|
||||
mod_settings.stuck_train_time = settings.global["cybersyn-stuck-train-time"].value--[[@as double]]
|
||||
mod_settings.depot_bypass_enabled = settings.global["cybersyn-depot-bypass-enabled"].value--[[@as boolean]]
|
||||
|
||||
mod_settings.missing_train_alert_enabled = true
|
||||
mod_settings.stuck_train_alert_enabled = true
|
||||
|
||||
@@ -2,122 +2,6 @@ local flib_migration = require("__flib__.migration")
|
||||
|
||||
|
||||
local migrations_table = {
|
||||
["0.2.1"] = function()
|
||||
---@type MapData
|
||||
local map_data = global
|
||||
for id, station in pairs(map_data.stations) do
|
||||
station.p_threshold = nil
|
||||
end
|
||||
end,
|
||||
["0.3.0"] = function()
|
||||
---@type MapData
|
||||
local map_data = global
|
||||
map_data.warmup_station_ids = {}
|
||||
map_data.active_station_ids = map_data.all_station_ids
|
||||
map_data.all_station_ids = nil
|
||||
mod_settings.warmup_time = settings.global["cybersyn-warmup-time"].value--[[@as int]]
|
||||
end,
|
||||
["0.4.0"] = function()
|
||||
---@type MapData
|
||||
local map_data = global
|
||||
map_data.is_player_cursor_blueprint = {}
|
||||
map_data.to_comb_params = {}
|
||||
for id, comb in pairs(map_data.to_comb) do
|
||||
map_data.to_comb_params[id] = get_comb_params(comb)
|
||||
end
|
||||
end,
|
||||
["0.4.1"] = function()
|
||||
---@type MapData
|
||||
local map_data = global
|
||||
map_data.tick_state = STATE_INIT
|
||||
for id, station in pairs(map_data.stations) do
|
||||
station.allows_all_trains = station.allow_all_trains or station.allows_all_trains
|
||||
station.allow_all_trains = nil
|
||||
end
|
||||
end,
|
||||
["0.4.2"] = function()
|
||||
---@type MapData
|
||||
local map_data = global
|
||||
map_data.tick_state = STATE_INIT
|
||||
map_data.available_trains = map_data.trains_available
|
||||
for id, train in pairs(map_data.trains) do
|
||||
local depot = train.depot
|
||||
if depot then
|
||||
train.parked_at_depot_id = depot.entity_comb.unit_number
|
||||
train.network_name = depot.network_name
|
||||
train.network_flag = depot.network_flag
|
||||
train.priority = depot.priority
|
||||
else
|
||||
train.network_name = ""
|
||||
train.network_flag = 0
|
||||
train.priority = 0
|
||||
end
|
||||
end
|
||||
for id, depot in pairs(map_data.depots) do
|
||||
map_data.depots[id] = {
|
||||
entity_comb = depot.entity_comb,
|
||||
entity_stop = depot.entity_stop,
|
||||
available_train_id = depot.available_train,
|
||||
}
|
||||
end
|
||||
end,
|
||||
["0.4.3"] = function()
|
||||
---@type MapData
|
||||
local map_data = global
|
||||
map_data.tick_state = STATE_INIT
|
||||
for id, station in pairs(map_data.stations) do
|
||||
set_station_from_comb_state(station)
|
||||
station.allow_all_trains = nil
|
||||
end
|
||||
for id, train in pairs(map_data.trains) do
|
||||
train.last_manifest_tick = map_data.total_ticks
|
||||
end
|
||||
mod_settings.stuck_train_time = settings.global["cybersyn-stuck-train-time"].value--[[@as int]]
|
||||
end,
|
||||
["0.4.4"] = function()
|
||||
---@type MapData
|
||||
local map_data = global
|
||||
map_data.tick_state = STATE_INIT
|
||||
for id, layout in pairs(map_data.layouts) do
|
||||
local new_layout = {}
|
||||
local i = 1
|
||||
for c in string.gmatch(layout, ".") do
|
||||
if c == "N" then
|
||||
elseif c == "C" then
|
||||
new_layout[i] = 1
|
||||
elseif c == "F" then
|
||||
new_layout[i] = 2
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
map_data.layouts[id] = new_layout
|
||||
end
|
||||
end,
|
||||
["0.5.1"] = function()
|
||||
---@type MapData
|
||||
local map_data = global
|
||||
map_data.tick_state = STATE_INIT
|
||||
map_data.is_player_cursor_blueprint = nil
|
||||
for id, layout in pairs(map_data.layouts) do
|
||||
local new_layout = {}
|
||||
local max_i = 0
|
||||
for i, v in pairs(layout) do
|
||||
new_layout[i] = v
|
||||
if i > max_i then
|
||||
max_i = i
|
||||
end
|
||||
end
|
||||
for i = 1, max_i do
|
||||
if new_layout[i] == nil then
|
||||
new_layout[i] = 0
|
||||
end
|
||||
end
|
||||
map_data.layouts[id] = new_layout
|
||||
end
|
||||
for id, station in pairs(map_data.stations) do
|
||||
reset_station_layout(map_data, station)
|
||||
end
|
||||
end,
|
||||
["1.0.3"] = function()
|
||||
---@type MapData
|
||||
local map_data = global
|
||||
@@ -173,9 +57,9 @@ local migrations_table = {
|
||||
map_data.tick_data = {}
|
||||
for id, station in pairs(map_data.stations) do
|
||||
local params = get_comb_params(station.entity_comb1)
|
||||
if params.operation == OPERATION_PRIMARY_IO_FAILED_REQUEST then
|
||||
if params.operation == MODE_PRIMARY_IO_FAILED_REQUEST then
|
||||
station.display_state = 1
|
||||
elseif params.operation == OPERATION_PRIMARY_IO_ACTIVE then
|
||||
elseif params.operation == MODE_PRIMARY_IO_ACTIVE then
|
||||
station.display_state = 2
|
||||
else
|
||||
station.display_state = 0
|
||||
@@ -184,7 +68,35 @@ local migrations_table = {
|
||||
station.update_display = nil
|
||||
end
|
||||
end,
|
||||
["1.1.0"] = function()
|
||||
---@type MapData
|
||||
local map_data = global
|
||||
map_data.tick_state = STATE_INIT
|
||||
map_data.tick_data = {}
|
||||
map_data.refuelers = {}
|
||||
map_data.to_refuelers = {}
|
||||
for id, station in pairs(map_data.stations) do
|
||||
station.p_count_or_r_threshold_per_item = nil
|
||||
end
|
||||
|
||||
local OLD_STATUS_R_TO_D = 5
|
||||
local NEW_STATUS_TO_D = 5
|
||||
local NEW_STATUS_TO_D_BYPASS = 6
|
||||
for id, train in pairs(map_data.trains) do
|
||||
if train.status == OLD_STATUS_R_TO_D then
|
||||
train.manifest = nil
|
||||
train.p_station_id = nil
|
||||
train.r_station_id = nil
|
||||
if train.is_available then
|
||||
train.status = NEW_STATUS_TO_D_BYPASS
|
||||
else
|
||||
train.status = NEW_STATUS_TO_D
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
--STATUS_R_TO_D = 5
|
||||
|
||||
---@param data ConfigurationChangedData
|
||||
function on_config_changed(data)
|
||||
|
||||
@@ -13,20 +13,353 @@ local on_station_created = nil
|
||||
local on_station_removed = nil
|
||||
local on_depot_created = nil
|
||||
local on_depot_removed = nil
|
||||
local on_refueler_created = nil
|
||||
local on_refueler_removed = nil
|
||||
local on_train_created = nil
|
||||
local on_train_removed = nil
|
||||
local on_train_available = nil
|
||||
local on_train_nonempty_in_depot = nil
|
||||
local on_train_dispatched = nil
|
||||
local on_train_dispatch_failed = nil
|
||||
local on_train_failed_delivery = nil
|
||||
local on_train_completed_provide = nil
|
||||
local on_train_completed_request = nil
|
||||
local on_train_parked_at_depot = nil
|
||||
local on_train_status_changed = nil
|
||||
local on_train_stuck = nil
|
||||
local on_train_teleport_started = nil
|
||||
local on_train_teleported = nil
|
||||
local on_tick_init = nil
|
||||
local on_mod_settings_changed = nil
|
||||
|
||||
local interface = {}
|
||||
------------------------------------------------------------------
|
||||
--[[get event id functions]]
|
||||
------------------------------------------------------------------
|
||||
|
||||
function interface.get_on_combinator_changed()
|
||||
if not on_combinator_changed then on_combinator_changed = script_generate_event_name() end
|
||||
return on_combinator_changed
|
||||
end
|
||||
function interface.get_on_station_created()
|
||||
if not on_station_created then on_station_created = script_generate_event_name() end
|
||||
return on_station_created
|
||||
end
|
||||
function interface.get_on_station_removed()
|
||||
if not on_station_removed then on_station_removed = script_generate_event_name() end
|
||||
return on_station_removed
|
||||
end
|
||||
function interface.get_on_depot_created()
|
||||
if not on_depot_created then on_depot_created = script_generate_event_name() end
|
||||
return on_depot_created
|
||||
end
|
||||
function interface.get_on_depot_removed()
|
||||
if not on_depot_removed then on_depot_removed = script_generate_event_name() end
|
||||
return on_depot_removed
|
||||
end
|
||||
function interface.get_on_refueler_created()
|
||||
if not on_refueler_created then on_refueler_created = script_generate_event_name() end
|
||||
return on_refueler_created
|
||||
end
|
||||
function interface.get_on_refueler_removed()
|
||||
if not on_refueler_removed then on_refueler_removed = script_generate_event_name() end
|
||||
return on_refueler_removed
|
||||
end
|
||||
function interface.get_on_train_created()
|
||||
if not on_train_created then on_train_created = script_generate_event_name() end
|
||||
return on_train_created
|
||||
end
|
||||
function interface.get_on_train_removed()
|
||||
if not on_train_removed then on_train_removed = script_generate_event_name() end
|
||||
return on_train_removed
|
||||
end
|
||||
function interface.get_on_train_available()
|
||||
if not on_train_available then on_train_available = script_generate_event_name() end
|
||||
return on_train_available
|
||||
end
|
||||
function interface.get_on_train_nonempty_in_depot()
|
||||
if not on_train_nonempty_in_depot then on_train_nonempty_in_depot = script_generate_event_name() end
|
||||
return on_train_nonempty_in_depot
|
||||
end
|
||||
function interface.get_on_train_dispatch_failed()
|
||||
if not on_train_dispatch_failed then on_train_dispatch_failed = script_generate_event_name() end
|
||||
return on_train_dispatch_failed
|
||||
end
|
||||
function interface.get_on_train_failed_delivery()
|
||||
if not on_train_failed_delivery then on_train_failed_delivery = script_generate_event_name() end
|
||||
return on_train_failed_delivery
|
||||
end
|
||||
function interface.get_on_train_status_changed()
|
||||
if not on_train_status_changed then on_train_status_changed = script_generate_event_name() end
|
||||
return on_train_status_changed
|
||||
end
|
||||
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_teleport_started()
|
||||
if not on_train_teleport_started then on_train_teleport_started = script_generate_event_name() end
|
||||
return on_train_teleport_started
|
||||
end
|
||||
function interface.get_on_train_teleported()
|
||||
if not on_train_teleported then on_train_teleported = script_generate_event_name() end
|
||||
return on_train_teleported
|
||||
end
|
||||
function interface.get_on_tick_init()
|
||||
if not on_tick_init then on_tick_init = script_generate_event_name() end
|
||||
return on_tick_init
|
||||
end
|
||||
function interface.get_on_mod_settings_changed()
|
||||
if not on_mod_settings_changed then on_mod_settings_changed = script_generate_event_name() end
|
||||
return on_mod_settings_changed
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[helper functions]]
|
||||
------------------------------------------------------------------
|
||||
--NOTE: the policy of cybersyn is to give modders access to as much of the raw data of the mod as possible. Factorio only allows me to return copies of the original data rather than the actual thing, which sucks. The unsafe api has some tools to help you bypass this limitation.
|
||||
|
||||
function interface.get_mod_settings()
|
||||
return mod_settings
|
||||
end
|
||||
---@param key string
|
||||
function interface.read_setting(key)
|
||||
return mod_settings[key]
|
||||
end
|
||||
---@param ... string|int
|
||||
function interface.read_global(...)
|
||||
--this can read anything off of cybersyn's map_data
|
||||
--so interface.read_global("trains", 31415, "manifest") == global.trains[31415].manifest (or nil if train 31415 does not exist)
|
||||
--the second return value is how many parameters could be processed before a nil value was encountered (in the above example it's useful for telling apart global.trains[31415] == nil vs global.trains[31415].manifest == nil)
|
||||
local base = global
|
||||
local depth = 0
|
||||
for i, v in ipairs({...}) do
|
||||
depth = i
|
||||
base = base[v]
|
||||
if not base then break end
|
||||
end
|
||||
return base, depth
|
||||
end
|
||||
---@param id uint
|
||||
function interface.get_station(id)
|
||||
return global.stations[id]
|
||||
end
|
||||
---@param id uint
|
||||
function interface.get_depot(id)
|
||||
return global.depots[id]
|
||||
end
|
||||
---@param id uint
|
||||
function interface.get_refueler(id)
|
||||
return global.refuelers[id]
|
||||
end
|
||||
---@param id uint
|
||||
function interface.get_train(id)
|
||||
return global.trains[id]
|
||||
end
|
||||
---@param train_entity LuaTrain
|
||||
function interface.get_train_id_from_luatrain(train_entity)
|
||||
return train_entity.id
|
||||
end
|
||||
---@param stop LuaEntity
|
||||
function interface.get_id_from_stop(stop)
|
||||
return stop.unit_number
|
||||
end
|
||||
---@param comb LuaEntity
|
||||
function interface.get_id_from_comb(comb)
|
||||
local stop = global.to_stop[comb.unit_number]
|
||||
if stop then
|
||||
return stop.unit_number
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[safe API]]
|
||||
------------------------------------------------------------------
|
||||
--NOTE: These functions can be called whenever however so long as their parameters have the correct types. Their ability to cause harm is extremely minimal.
|
||||
|
||||
---@param key string
|
||||
---@param value any
|
||||
function interface.write_setting(key, value)
|
||||
--be careful that the value you write is of the correct type specified in global.lua
|
||||
--these settings are not saved and have to be set on load and on init
|
||||
mod_settings[key] = value
|
||||
end
|
||||
|
||||
|
||||
---@param comb LuaEntity
|
||||
function interface.combinator_update(comb)
|
||||
combinator_update(global, comb)
|
||||
end
|
||||
|
||||
---@param train_id uint
|
||||
function interface.update_train_layout(train_id)
|
||||
local train = global.trains[train_id]
|
||||
assert(train)
|
||||
local old_layout_id = train.layout_id
|
||||
local count = global.layout_train_count[old_layout_id]
|
||||
if count <= 1 then
|
||||
global.layout_train_count[old_layout_id] = nil
|
||||
global.layouts[old_layout_id] = nil
|
||||
for station_id, station in pairs(global.stations) do
|
||||
station.accepted_layouts[old_layout_id] = nil
|
||||
end
|
||||
else
|
||||
global.layout_train_count[old_layout_id] = count - 1
|
||||
end
|
||||
set_train_layout(global, train)
|
||||
end
|
||||
---@param layout_pattern (0|1|2|3)[]
|
||||
---@param layout (0|1|2)[]
|
||||
function interface.is_layout_accepted(layout_pattern, layout)
|
||||
return is_layout_accepted(layout_pattern, layout)
|
||||
end
|
||||
---@param layout_pattern (0|1|2|3)[]
|
||||
---@param layout (0|1|2)[]
|
||||
function interface.is_refuel_layout_accepted(layout_pattern, layout)
|
||||
return is_refuel_layout_accepted(layout_pattern, layout)
|
||||
end
|
||||
---@param stop_id uint
|
||||
---@param forbidden_entity LuaEntity?
|
||||
---@param force_update boolean?
|
||||
function interface.reset_stop_layout(stop_id, forbidden_entity, force_update)
|
||||
local is_station = true
|
||||
---@type Refueler|Station
|
||||
local stop = global.stations[stop_id]
|
||||
if not stop then
|
||||
is_station = false
|
||||
stop = global.refuelers[stop_id]
|
||||
end
|
||||
assert(stop)
|
||||
if force_update or not stop.allows_all_trains then
|
||||
reset_stop_layout(global, stop, is_station, forbidden_entity)
|
||||
end
|
||||
end
|
||||
---@param rail LuaEntity
|
||||
---@param forbidden_entity LuaEntity?
|
||||
---@param force_update boolean?
|
||||
function interface.update_stop_from_rail(rail, forbidden_entity, force_update)
|
||||
update_stop_from_rail(global, rail, forbidden_entity, force_update)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[unsafe API]]
|
||||
------------------------------------------------------------------
|
||||
--NOTE: The following functions can cause serious longterm damage to someone's world if they are given bad parameters. Please refer to global.lua for type information. Use caution.
|
||||
|
||||
---@param value any
|
||||
---@param ... string|int
|
||||
function interface.write_global(value, ...)
|
||||
--this can write anything into cybersyn's map_data, please be very careful with anything you write, it can cause permanent damage
|
||||
--so interface.read_global(nil, "trains", 31415, "manifest") will cause global.trains[31415].manifest = nil (or return false if train 31415 does not exist)
|
||||
local params = {...}
|
||||
local size = #params
|
||||
local key = params[size]
|
||||
assert(key ~= nil)
|
||||
local base = global
|
||||
for i = 1, size - 1 do
|
||||
base = base[params[i]]
|
||||
if not base then return false end
|
||||
end
|
||||
base[key] = value
|
||||
return true
|
||||
end
|
||||
|
||||
---@param station_id Station
|
||||
---@param manifest Manifest
|
||||
---@param sign -1|1
|
||||
function interface.remove_manifest_from_station_deliveries(station_id, manifest, sign)
|
||||
local station = global.stations[station_id]
|
||||
assert(station)
|
||||
remove_manifest(global, station, manifest, sign)
|
||||
end
|
||||
---@param r_station_id uint
|
||||
---@param p_station_id uint
|
||||
---@param train_id uint
|
||||
function interface.create_manifest(r_station_id, p_station_id, train_id)
|
||||
local train = global.trains[train_id]
|
||||
assert(global.stations[r_station_id] and global.stations[p_station_id] and train and train.is_available)
|
||||
create_manifest(global, r_station_id, p_station_id, train_id)
|
||||
end
|
||||
---@param r_station_id uint
|
||||
---@param p_station_id uint
|
||||
---@param train_id uint
|
||||
---@param manifest Manifest
|
||||
function interface.create_delivery(r_station_id, p_station_id, train_id, manifest)
|
||||
local train = global.trains[train_id]
|
||||
assert(global.stations[r_station_id] and global.stations[p_station_id] and train and train.is_available and manifest)
|
||||
create_delivery(global, r_station_id, p_station_id, train_id, manifest)
|
||||
end
|
||||
---@param train_id uint
|
||||
function interface.fail_delivery(train_id)
|
||||
local train = global.trains[train_id]
|
||||
assert(train)
|
||||
on_failed_delivery(global, train_id, train)
|
||||
end
|
||||
---@param train_id uint
|
||||
function interface.remove_train(train_id)
|
||||
local train = global.trains[train_id]
|
||||
assert(train)
|
||||
remove_train(global, train_id, train)
|
||||
end
|
||||
|
||||
---@param train_id uint
|
||||
function interface.add_available_train(train_id)
|
||||
--This function marks a train as available but not in a depot so it can do depot bypass, be sure the train has no active deliveries before calling this
|
||||
--available trains can be chosen by the dispatcher to be rescheduled and dispatched for a new delivery
|
||||
--when this train parks at a depot add_available_train_to_depot will be called on it automatically
|
||||
local train = global.trains[train_id]
|
||||
assert(train)
|
||||
add_available_train(global, train_id, train)
|
||||
end
|
||||
---@param depot_id uint
|
||||
---@param train_id uint
|
||||
function interface.add_available_train_to_depot(train_id, depot_id)
|
||||
--This function marks a train as available and in a depot, be sure the train has no active deliveries before calling this
|
||||
--available trains can be chosen by the dispatcher to be rescheduled and dispatched for a new delivery
|
||||
local train = global.trains[train_id]
|
||||
local depot = global.depots[depot_id]
|
||||
assert(train and depot)
|
||||
add_available_train_to_depot(global, mod_settings, train_id, train, depot_id, depot)
|
||||
end
|
||||
---@param train_id uint
|
||||
function interface.remove_available_train(train_id)
|
||||
--this function removes a train from the available trains list so it cannot be rescheduled and dispatched. if the train was not already available nothing will happen
|
||||
local train = global.trains[train_id]
|
||||
assert(train)
|
||||
remove_available_train(global, train_id, train)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[train schedule]]
|
||||
------------------------------------------------------------------
|
||||
|
||||
interface.create_loading_order = create_loading_order
|
||||
interface.create_unloading_order = create_unloading_order
|
||||
interface.create_inactivity_order = create_inactivity_order
|
||||
interface.create_direct_to_station_order = create_direct_to_station_order
|
||||
interface.set_depot_schedule = set_depot_schedule
|
||||
interface.lock_train = lock_train
|
||||
interface.rename_manifest_schedule = rename_manifest_schedule
|
||||
interface.se_get_space_elevator_name = se_get_space_elevator_name
|
||||
interface.se_create_elevator_order = se_create_elevator_order
|
||||
interface.set_manifest_schedule = set_manifest_schedule
|
||||
interface.add_refueler_schedule = add_refueler_schedule
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[alerts]]
|
||||
------------------------------------------------------------------
|
||||
|
||||
interface.send_missing_train_alert = send_missing_train_alert
|
||||
interface.send_lost_train_alert = send_lost_train_alert
|
||||
interface.send_unexpected_train_alert = send_unexpected_train_alert
|
||||
interface.send_nonempty_train_in_depot_alert = send_nonempty_train_in_depot_alert
|
||||
interface.send_stuck_train_alert = send_stuck_train_alert
|
||||
|
||||
|
||||
remote.add_interface("cybersyn", interface)
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[internal event calls]]
|
||||
------------------------------------------------------------------
|
||||
|
||||
---@param entity LuaEntity
|
||||
---@param old_parameters ArithmeticCombinatorParameters
|
||||
@@ -77,6 +410,25 @@ function interface_raise_depot_removed(old_depot_id, old_depot)
|
||||
end
|
||||
end
|
||||
|
||||
---@param refueler_id uint
|
||||
function interface_raise_refueler_created(refueler_id)
|
||||
if on_refueler_created then
|
||||
raise_event(on_refueler_created, {
|
||||
refueler_id = refueler_id,
|
||||
})
|
||||
end
|
||||
end
|
||||
---@param old_refueler_id uint
|
||||
---@param old_refueler Refueler
|
||||
function interface_raise_refueler_removed(old_refueler_id, old_refueler)
|
||||
if on_refueler_removed then
|
||||
raise_event(on_refueler_removed, {
|
||||
old_refueler_id = old_refueler_id, --this id is now invalid
|
||||
old_refueler = old_refueler, --this is the data that used to be stored at the old id
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
---@param train_id uint
|
||||
---@param depot_id uint
|
||||
function interface_raise_train_created(train_id, depot_id)
|
||||
@@ -118,14 +470,6 @@ function interface_raise_train_nonempty_in_depot(depot_id, train_entity, train_i
|
||||
end
|
||||
end
|
||||
|
||||
---@param train_id uint
|
||||
function interface_raise_train_dispatched(train_id)
|
||||
if on_train_dispatched then
|
||||
raise_event(on_train_dispatched, {
|
||||
train_id = train_id,
|
||||
})
|
||||
end
|
||||
end
|
||||
---@param train_id uint
|
||||
function interface_raise_train_dispatch_failed(train_id)
|
||||
--this event is rare, it can only occur when a train is bypassing the depot and can't find a path to the provide station, that train is marked as unavailable but not dispatched
|
||||
@@ -154,28 +498,14 @@ function interface_raise_train_failed_delivery(train_id, was_p_in_progress, p_st
|
||||
end
|
||||
end
|
||||
---@param train_id uint
|
||||
function interface_raise_train_completed_provide(train_id)
|
||||
if on_train_completed_provide then
|
||||
raise_event(on_train_completed_provide, {
|
||||
---@param old_status uint
|
||||
---@param new_status uint
|
||||
function interface_raise_train_status_changed(train_id, old_status, new_status)
|
||||
if on_train_status_changed then
|
||||
raise_event(on_train_status_changed, {
|
||||
train_id = train_id,
|
||||
})
|
||||
end
|
||||
end
|
||||
---@param train_id uint
|
||||
function interface_raise_train_completed_request(train_id)
|
||||
if on_train_completed_request then
|
||||
raise_event(on_train_completed_request, {
|
||||
train_id = train_id,
|
||||
})
|
||||
end
|
||||
end
|
||||
---@param train_id uint
|
||||
---@param depot_id uint
|
||||
function interface_raise_train_parked_at_depot(train_id, depot_id)
|
||||
if on_train_parked_at_depot then
|
||||
raise_event(on_train_parked_at_depot, {
|
||||
train_id = train_id,
|
||||
depot_id = depot_id,
|
||||
old_status = old_status,
|
||||
new_status = new_status,
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -191,7 +521,7 @@ end
|
||||
function interface_raise_train_teleport_started(old_train_id)
|
||||
if on_train_teleport_started then
|
||||
raise_event(on_train_teleport_started, {
|
||||
old_train_id = old_train_id,--this id is currently valid but will become valid just before on_train_teleported is raised
|
||||
old_train_id = old_train_id,--this id is currently valid but will become invalid just before on_train_teleported is raised
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -212,261 +542,8 @@ function interface_raise_tick_init()
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local interface = {}
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[get event id functions]]
|
||||
------------------------------------------------------------------
|
||||
|
||||
function interface.get_on_combinator_changed()
|
||||
if not on_combinator_changed then on_combinator_changed = script_generate_event_name() end
|
||||
return on_combinator_changed
|
||||
end
|
||||
function interface.get_on_station_created()
|
||||
if not on_station_created then on_station_created = script_generate_event_name() end
|
||||
return on_station_created
|
||||
end
|
||||
function interface.get_on_station_removed()
|
||||
if not on_station_removed then on_station_removed = script_generate_event_name() end
|
||||
return on_station_removed
|
||||
end
|
||||
function interface.get_on_depot_created()
|
||||
if not on_depot_created then on_depot_created = script_generate_event_name() end
|
||||
return on_depot_created
|
||||
end
|
||||
function interface.get_on_depot_removed()
|
||||
if not on_depot_removed then on_depot_removed = script_generate_event_name() end
|
||||
return on_depot_removed
|
||||
end
|
||||
function interface.get_on_train_created()
|
||||
if not on_train_created then on_train_created = script_generate_event_name() end
|
||||
return on_train_created
|
||||
end
|
||||
function interface.get_on_train_removed()
|
||||
if not on_train_removed then on_train_removed = script_generate_event_name() end
|
||||
return on_train_removed
|
||||
end
|
||||
function interface.get_on_train_available()
|
||||
if not on_train_available then on_train_available = script_generate_event_name() end
|
||||
return on_train_available
|
||||
end
|
||||
function interface.get_on_train_nonempty_in_depot()
|
||||
if not on_train_nonempty_in_depot then on_train_nonempty_in_depot = script_generate_event_name() end
|
||||
return on_train_nonempty_in_depot
|
||||
end
|
||||
function interface.get_on_train_dispatched()
|
||||
if not on_train_dispatched then on_train_dispatched = script_generate_event_name() end
|
||||
return on_train_dispatched
|
||||
end
|
||||
function interface.get_on_train_dispatch_failed()
|
||||
if not on_train_dispatch_failed then on_train_dispatch_failed = script_generate_event_name() end
|
||||
return on_train_dispatch_failed
|
||||
end
|
||||
function interface.get_on_train_failed_delivery()
|
||||
if not on_train_failed_delivery then on_train_failed_delivery = script_generate_event_name() end
|
||||
return on_train_failed_delivery
|
||||
end
|
||||
function interface.get_on_train_completed_provide()
|
||||
if not on_train_completed_provide then on_train_completed_provide = script_generate_event_name() end
|
||||
return on_train_completed_provide
|
||||
end
|
||||
function interface.get_on_train_completed_request()
|
||||
if not on_train_completed_request then on_train_completed_request = script_generate_event_name() end
|
||||
return on_train_completed_request
|
||||
end
|
||||
function interface.get_on_train_parked_at_depot()
|
||||
if not on_train_parked_at_depot then on_train_parked_at_depot = script_generate_event_name() end
|
||||
return on_train_parked_at_depot
|
||||
end
|
||||
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_teleport_started()
|
||||
if not on_train_teleport_started then on_train_teleport_started = script_generate_event_name() end
|
||||
return on_train_teleport_started
|
||||
end
|
||||
function interface.get_on_train_teleported()
|
||||
if not on_train_teleported then on_train_teleported = script_generate_event_name() end
|
||||
return on_train_teleported
|
||||
end
|
||||
function interface.get_on_tick_init()
|
||||
if not on_tick_init then on_tick_init = script_generate_event_name() end
|
||||
return on_tick_init
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[safe API]]
|
||||
------------------------------------------------------------------
|
||||
--NOTE: These functions can be called whenever however so long as their parameters have the correct types. Their ability to cause harm is extremely minimal.
|
||||
|
||||
---@param comb LuaEntity
|
||||
function interface.combinator_update(comb)
|
||||
combinator_update(global, comb)
|
||||
end
|
||||
|
||||
---@param train_id uint
|
||||
function interface.update_train_layout(train_id)
|
||||
local train = global.trains[train_id]
|
||||
assert(train)
|
||||
local old_layout_id = train.layout_id
|
||||
local count = global.layout_train_count[old_layout_id]
|
||||
if count <= 1 then
|
||||
global.layout_train_count[old_layout_id] = nil
|
||||
global.layouts[old_layout_id] = nil
|
||||
for station_id, station in pairs(global.stations) do
|
||||
station.accepted_layouts[old_layout_id] = nil
|
||||
end
|
||||
else
|
||||
global.layout_train_count[old_layout_id] = count - 1
|
||||
end
|
||||
set_train_layout(global, train)
|
||||
end
|
||||
---@param layout_pattern (0|1|2|3)[]
|
||||
---@param layout (0|1|2)[]
|
||||
function interface.is_layout_accepted(layout_pattern, layout)
|
||||
return is_layout_accepted(layout_pattern, layout)
|
||||
end
|
||||
---@param station_id uint
|
||||
---@param forbidden_entity LuaEntity?
|
||||
---@param force_update boolean?
|
||||
function interface.reset_station_layout(station_id, forbidden_entity, force_update)
|
||||
local station = global.stations[station_id]
|
||||
assert(station)
|
||||
if force_update or not station.allows_all_trains then
|
||||
reset_station_layout(global, station, forbidden_entity)
|
||||
function interface_raise_on_mod_settings_changed(e)
|
||||
if on_mod_settings_changed then
|
||||
raise_event(on_mod_settings_changed, e)
|
||||
end
|
||||
end
|
||||
---@param rail LuaEntity
|
||||
---@param forbidden_entity LuaEntity?
|
||||
---@param force_update boolean?
|
||||
function interface.update_station_from_rail(rail, forbidden_entity, force_update)
|
||||
update_station_from_rail(global, rail, forbidden_entity, force_update)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[unsafe API]]
|
||||
------------------------------------------------------------------
|
||||
--NOTE: The following functions can cause serious longterm damage to someone's world if they are given bad parameters. Use caution.
|
||||
|
||||
---@param station_id Station
|
||||
---@param manifest Manifest
|
||||
---@param sign -1|1
|
||||
function interface.remove_manifest_from_station_deliveries(station_id, manifest, sign)
|
||||
local station = global.stations[station_id]
|
||||
assert(station)
|
||||
remove_manifest(global, station, manifest, sign)
|
||||
end
|
||||
---@param r_station_id uint
|
||||
---@param p_station_id uint
|
||||
---@param train_id uint
|
||||
---@param primary_item_name string?
|
||||
function interface.create_new_delivery_between_stations(r_station_id, p_station_id, train_id, primary_item_name)
|
||||
local train = global.trains[train_id]
|
||||
assert(global.stations[r_station_id] and global.stations[p_station_id] and train and train.is_available)
|
||||
send_train_between(global, r_station_id, p_station_id, train_id, primary_item_name)
|
||||
end
|
||||
---@param train_id uint
|
||||
function interface.fail_delivery(train_id)
|
||||
local train = global.trains[train_id]
|
||||
assert(train)
|
||||
on_failed_delivery(global, train_id, train)
|
||||
end
|
||||
---@param train_id uint
|
||||
function interface.remove_train(train_id)
|
||||
local train = global.trains[train_id]
|
||||
assert(train)
|
||||
remove_train(global, train_id, train)
|
||||
end
|
||||
|
||||
---@param train_id uint
|
||||
function interface.add_available_train(train_id)
|
||||
local train = global.trains[train_id]
|
||||
assert(train)
|
||||
add_available_train(global, train_id, train)
|
||||
end
|
||||
---@param depot_id uint
|
||||
---@param train_id uint
|
||||
function interface.add_available_train_to_depot(train_id, depot_id)
|
||||
local train = global.trains[train_id]
|
||||
local depot = global.depots[depot_id]
|
||||
assert(train and depot)
|
||||
add_available_train_to_depot(global, mod_settings, train_id, train, depot_id, depot)
|
||||
end
|
||||
---@param train_id uint
|
||||
function interface.remove_available_train(train_id)
|
||||
local train = global.trains[train_id]
|
||||
assert(train)
|
||||
remove_available_train(global, train_id, train)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[train schedule]]
|
||||
------------------------------------------------------------------
|
||||
|
||||
interface.create_loading_order = create_loading_order
|
||||
interface.create_unloading_order = create_unloading_order
|
||||
interface.create_inactivity_order = create_inactivity_order
|
||||
interface.create_direct_to_station_order = create_direct_to_station_order
|
||||
interface.set_depot_schedule = set_depot_schedule
|
||||
interface.lock_train = lock_train
|
||||
interface.rename_manifest_schedule = rename_manifest_schedule
|
||||
interface.se_get_space_elevator_name = se_get_space_elevator_name
|
||||
interface.se_create_elevator_order = se_create_elevator_order
|
||||
interface.set_manifest_schedule = set_manifest_schedule
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[alerts]]
|
||||
------------------------------------------------------------------
|
||||
|
||||
interface.send_missing_train_alert = send_missing_train_alert
|
||||
interface.send_lost_train_alert = send_lost_train_alert
|
||||
interface.send_unexpected_train_alert = send_unexpected_train_alert
|
||||
interface.send_nonempty_train_in_depot_alert = send_nonempty_train_in_depot_alert
|
||||
interface.send_stuck_train_alert = send_stuck_train_alert
|
||||
|
||||
------------------------------------------------------------------
|
||||
--[[helper functions]]
|
||||
------------------------------------------------------------------
|
||||
--NOTE: the policy of cybersyn is to give modders access to the raw data of the mod, please either treat all tables returned from the modding interface as "read only", or if you do modify them take responsibility that your modification does not result in an error occuring in cybersyn later on.
|
||||
--NOTE: the follow functions aren't strictly necessary; they are provided more as a guide how the mod api works rather than as practical functions.
|
||||
|
||||
function interface.get_map_data()
|
||||
return global
|
||||
end
|
||||
function interface.get_mod_settings()
|
||||
return mod_settings
|
||||
end
|
||||
---@param id uint
|
||||
function interface.get_station(id)
|
||||
return global.stations[id]
|
||||
end
|
||||
---@param id uint
|
||||
function interface.get_depot(id)
|
||||
return global.depots[id]
|
||||
end
|
||||
---@param id uint
|
||||
function interface.get_train(id)
|
||||
return global.trains[id]
|
||||
end
|
||||
---@param train_entity LuaTrain
|
||||
function interface.get_train_id_from_luatrain(train_entity)
|
||||
return train_entity.id
|
||||
end
|
||||
---@param stop LuaEntity
|
||||
function interface.get_station_or_depot_id_from_stop(stop)
|
||||
return stop.unit_number
|
||||
end
|
||||
---@param comb LuaEntity
|
||||
function interface.get_station_or_depot_id_from_comb(comb)
|
||||
local stop = global.to_stop[comb.unit_number]
|
||||
if stop then
|
||||
return stop.unit_number
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
remote.add_interface("cybersyn", interface)
|
||||
|
||||
@@ -0,0 +1,447 @@
|
||||
--By Mami
|
||||
local min = math.min
|
||||
local INF = math.huge
|
||||
|
||||
---@param map_data MapData
|
||||
---@param station Station
|
||||
---@param manifest Manifest
|
||||
---@param sign int?
|
||||
local function set_comb1(map_data, station, manifest, sign)
|
||||
local comb = station.entity_comb1
|
||||
if comb.valid then
|
||||
if manifest then
|
||||
local signals = {}
|
||||
for i, item in ipairs(manifest) do
|
||||
signals[i] = {index = i, signal = {type = item.type, name = item.name}, count = sign*item.count}
|
||||
end
|
||||
set_combinator_output(map_data, comb, signals)
|
||||
else
|
||||
set_combinator_output(map_data, comb, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
function on_failed_delivery(map_data, train_id, train)
|
||||
--NOTE: must either change this train's status or remove it after this call
|
||||
local p_station_id = train.p_station_id--[[@as uint]]
|
||||
local r_station_id = train.r_station_id--[[@as uint]]
|
||||
local manifest = train.manifest--[[@as Manifest]]
|
||||
local is_p_in_progress = train.status == STATUS_TO_P or train.status == STATUS_P
|
||||
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)
|
||||
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)
|
||||
end
|
||||
end
|
||||
train.r_station_id = nil
|
||||
train.p_station_id = nil
|
||||
train.manifest = nil
|
||||
interface_raise_train_failed_delivery(train_id, is_p_in_progress, p_station_id, is_r_in_progress, r_station_id, manifest)
|
||||
end
|
||||
|
||||
|
||||
|
||||
---@param map_data MapData
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
function add_available_train(map_data, train_id, train)
|
||||
local network_name = train.network_name
|
||||
if network_name then
|
||||
local network = map_data.available_trains[network_name]
|
||||
if not network then
|
||||
network = {}
|
||||
map_data.available_trains[network_name] = network
|
||||
end
|
||||
network[train_id] = true
|
||||
train.is_available = true
|
||||
interface_raise_train_available(train_id)
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param mod_settings CybersynModSettings
|
||||
---@param depot_id uint
|
||||
---@param depot Depot
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
function add_available_train_to_depot(map_data, mod_settings, train_id, train, depot_id, depot)
|
||||
local comb = depot.entity_comb
|
||||
local network_name = get_comb_network_name(comb)
|
||||
if network_name then
|
||||
local network = map_data.available_trains[network_name]
|
||||
if not network then
|
||||
network = {}
|
||||
map_data.available_trains[network_name] = network
|
||||
end
|
||||
network[train_id] = true
|
||||
train.is_available = true
|
||||
end
|
||||
depot.available_train_id = train_id
|
||||
train.status = STATUS_D
|
||||
train.parked_at_depot_id = depot_id
|
||||
train.depot_name = depot.entity_stop.backer_name
|
||||
train.se_depot_surface_i = depot.entity_stop.surface.index
|
||||
train.network_name = network_name
|
||||
train.network_flag = mod_settings.network_flag
|
||||
train.priority = 0
|
||||
if network_name then
|
||||
local signals = comb.get_merged_signals(defines.circuit_connector_id.combinator_input)
|
||||
if signals then
|
||||
for k, v in pairs(signals) do
|
||||
local item_name = v.signal.name
|
||||
local item_count = v.count
|
||||
if item_name then
|
||||
if item_name == SIGNAL_PRIORITY then
|
||||
train.priority = item_count
|
||||
end
|
||||
if item_name == network_name then
|
||||
train.network_flag = item_count
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
interface_raise_train_available(train_id)
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
function remove_available_train(map_data, train_id, train)
|
||||
---@type uint
|
||||
if train.is_available and train.network_name then
|
||||
local network = map_data.available_trains[train.network_name--[[@as string]]]
|
||||
if network then
|
||||
network[train_id] = nil
|
||||
if next(network) == nil then
|
||||
map_data.available_trains[train.network_name] = nil
|
||||
end
|
||||
end
|
||||
train.is_available = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---@param map_data MapData
|
||||
---@param depot_id uint
|
||||
---@param train_entity LuaTrain
|
||||
local function on_train_arrives_depot(map_data, depot_id, train_entity)
|
||||
local contents = train_entity.get_contents()
|
||||
local fluid_contents = train_entity.get_fluid_contents()
|
||||
local is_train_empty = next(contents) == nil and next(fluid_contents) == nil
|
||||
local train_id = train_entity.id
|
||||
local train = map_data.trains[train_id]
|
||||
if train then
|
||||
if train.status == STATUS_TO_D then
|
||||
elseif train.status == STATUS_TO_D_BYPASS or train.status == STATUS_D then
|
||||
--shouldn't be possible to get train.status == STATUS_D
|
||||
remove_available_train(map_data, train_id, train)
|
||||
elseif mod_settings.react_to_train_early_to_depot then
|
||||
if train.manifest then
|
||||
on_failed_delivery(map_data, train_id, train)
|
||||
end
|
||||
send_unexpected_train_alert(train.entity)
|
||||
else
|
||||
return
|
||||
end
|
||||
if is_train_empty then
|
||||
local old_status = train.status
|
||||
add_available_train_to_depot(map_data, mod_settings, train_id, train, depot_id, map_data.depots[depot_id])
|
||||
set_depot_schedule(train_entity, train.depot_name)
|
||||
interface_raise_train_status_changed(train_id, old_status, STATUS_D)
|
||||
else
|
||||
--train still has cargo
|
||||
if mod_settings.react_to_nonempty_train_in_depot then
|
||||
lock_train(train_entity)
|
||||
remove_train(map_data, train_id, train)
|
||||
send_nonempty_train_in_depot_alert(train_entity)
|
||||
end
|
||||
interface_raise_train_nonempty_in_depot(depot_id, train_entity, train_id)
|
||||
end
|
||||
elseif is_train_empty then
|
||||
--NOTE: only place where new Train
|
||||
train = {
|
||||
entity = train_entity,
|
||||
--layout_id = set_train_layout,
|
||||
--item_slot_capacity = set_train_layout,
|
||||
--fluid_capacity = set_train_layout,
|
||||
--status = add_available_train_to_depot,
|
||||
p_station_id = 0,
|
||||
r_station_id = 0,
|
||||
manifest = nil,
|
||||
last_manifest_tick = map_data.total_ticks,
|
||||
has_filtered_wagon = nil,
|
||||
--is_available = add_available_train_to_depot,
|
||||
--parked_at_depot_id = add_available_train_to_depot,
|
||||
--depot_name = add_available_train_to_depot,
|
||||
--network_name = add_available_train_to_depot,
|
||||
--network_flag = add_available_train_to_depot,
|
||||
--priority = add_available_train_to_depot,
|
||||
}
|
||||
set_train_layout(map_data, train)
|
||||
map_data.trains[train_id] = train
|
||||
add_available_train_to_depot(map_data, mod_settings, train_id, train, depot_id, map_data.depots[depot_id])
|
||||
|
||||
set_depot_schedule(train_entity, train.depot_name)
|
||||
interface_raise_train_created(train_id, depot_id)
|
||||
else
|
||||
if mod_settings.react_to_nonempty_train_in_depot then
|
||||
lock_train(train_entity)
|
||||
send_nonempty_train_in_depot_alert(train_entity)
|
||||
end
|
||||
interface_raise_train_nonempty_in_depot(depot_id, train_entity)
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param station_id uint
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
local function on_train_arrives_station(map_data, station_id, train_id, train)
|
||||
if train.manifest then
|
||||
---@type uint
|
||||
if train.status == STATUS_TO_P then
|
||||
if train.p_station_id == station_id then
|
||||
train.status = STATUS_P
|
||||
local station = map_data.stations[station_id]
|
||||
set_comb1(map_data, station, train.manifest, 1)
|
||||
set_p_wagon_combs(map_data, station, train)
|
||||
interface_raise_train_status_changed(train_id, STATUS_TO_P, STATUS_P)
|
||||
end
|
||||
elseif train.status == STATUS_TO_R then
|
||||
if train.r_station_id == station_id then
|
||||
train.status = STATUS_R
|
||||
local station = map_data.stations[station_id]
|
||||
set_comb1(map_data, station, train.manifest, -1)
|
||||
set_r_wagon_combs(map_data, station, train)
|
||||
interface_raise_train_status_changed(train_id, STATUS_TO_R, STATUS_R)
|
||||
end
|
||||
elseif train.status == STATUS_P and train.p_station_id == station_id then
|
||||
--this is player intervention that is considered valid
|
||||
elseif (train.status == STATUS_R or train.status == STATUS_TO_D or train.status == STATUS_TO_D_BYPASS) and train.r_station_id == station_id then
|
||||
--this is player intervention that is considered valid
|
||||
elseif mod_settings.react_to_train_at_incorrect_station then
|
||||
on_failed_delivery(map_data, train_id, train)
|
||||
remove_train(map_data, train_id, train)
|
||||
lock_train(train.entity)
|
||||
send_lost_train_alert(train.entity, train.depot_name)
|
||||
end
|
||||
elseif mod_settings.react_to_train_at_incorrect_station then
|
||||
--train is lost somehow, probably from player intervention
|
||||
remove_train(map_data, train_id, train)
|
||||
send_lost_train_alert(train.entity, train.depot_name)
|
||||
end
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param refueler_id uint
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
local function on_train_arrives_refueler(map_data, refueler_id, 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)
|
||||
end
|
||||
end
|
||||
|
||||
---@param map_data MapData
|
||||
---@param mod_settings CybersynModSettings
|
||||
---@param train_id uint
|
||||
---@param train Train
|
||||
local function on_train_leaves_stop(map_data, mod_settings, train_id, train)
|
||||
if train.status == STATUS_P then
|
||||
train.status = STATUS_TO_R
|
||||
local station = map_data.stations[train.p_station_id]
|
||||
remove_manifest(map_data, station, train.manifest, 1)
|
||||
set_comb1(map_data, station, nil)
|
||||
unset_wagon_combs(map_data, station)
|
||||
if train.has_filtered_wagon then
|
||||
train.has_filtered_wagon = nil
|
||||
for carriage_i, carriage in ipairs(train.entity.cargo_wagons) do
|
||||
local inv = carriage.get_inventory(defines.inventory.cargo_wagon)
|
||||
if inv and inv.is_filtered() then
|
||||
---@type uint
|
||||
for i = 1, #inv do
|
||||
inv.set_filter(i, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
interface_raise_train_status_changed(train_id, STATUS_P, STATUS_TO_R)
|
||||
elseif train.status == STATUS_R then
|
||||
local station = map_data.stations[train.r_station_id]
|
||||
remove_manifest(map_data, station, train.manifest, -1)
|
||||
set_comb1(map_data, station, nil)
|
||||
unset_wagon_combs(map_data, station)
|
||||
--complete delivery
|
||||
train.p_station_id = nil
|
||||
train.r_station_id = nil
|
||||
train.manifest = nil
|
||||
--add to available trains for depot bypass
|
||||
local fuel_fill = INF
|
||||
for _, v in pairs(train.entity.locomotives) do
|
||||
for _, loco in pairs(v) do
|
||||
local inv = loco.get_fuel_inventory()
|
||||
if inv then
|
||||
local inv_size = #inv
|
||||
if inv_size > 0 then
|
||||
local fuel_total = 0
|
||||
---@type uint
|
||||
for i = 1, inv_size do
|
||||
local item = inv[i]
|
||||
if item.valid_for_read then
|
||||
fuel_total = fuel_total + item.count/get_stack_size(map_data, item.name)
|
||||
end
|
||||
end
|
||||
fuel_fill = min(fuel_fill, fuel_total/inv_size)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if fuel_fill > mod_settings.fuel_threshold then
|
||||
--if fuel_fill == INF, it's probably a modded electric train
|
||||
if mod_settings.depot_bypass_enabled then
|
||||
train.status = STATUS_TO_D_BYPASS
|
||||
add_available_train(map_data, train_id, train)
|
||||
interface_raise_train_status_changed(train_id, STATUS_R, STATUS_TO_D_BYPASS)
|
||||
return
|
||||
end
|
||||
else
|
||||
local refuelers = map_data.to_refuelers[train.network_name]
|
||||
if refuelers then
|
||||
local best_refueler_id = nil
|
||||
local best_dist = INF
|
||||
local best_prior = -INF
|
||||
for id, _ in pairs(refuelers) do
|
||||
local refueler = map_data.refuelers[id]
|
||||
set_refueler_from_comb(mod_settings, refueler)
|
||||
if bit32.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
|
||||
end
|
||||
end
|
||||
end
|
||||
if best_refueler_id then
|
||||
train.status = STATUS_TO_F
|
||||
train.refueler_id = best_refueler_id
|
||||
local refueler = map_data.refuelers[best_refueler_id]
|
||||
refueler.trains_total = refueler.trains_total + 1
|
||||
add_refueler_schedule(train.entity, refueler.entity_stop, train.depot_name)
|
||||
interface_raise_train_status_changed(train_id, STATUS_R, STATUS_TO_F)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
--the train has not qualified for depot bypass nor refueling
|
||||
train.status = STATUS_TO_D
|
||||
interface_raise_train_status_changed(train_id, STATUS_R, STATUS_TO_D)
|
||||
elseif train.status == STATUS_F then
|
||||
local refueler = map_data.refuelers[train.refueler_id]
|
||||
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 mod_settings.depot_bypass_enabled then
|
||||
train.status = STATUS_TO_D_BYPASS
|
||||
add_available_train(map_data, train_id, train)
|
||||
else
|
||||
train.status = STATUS_TO_D
|
||||
end
|
||||
interface_raise_train_status_changed(train_id, STATUS_F, train.status)
|
||||
elseif train.status == STATUS_D then
|
||||
--The train is leaving the depot without a manifest, the player likely intervened
|
||||
local depot = map_data.depots[train.parked_at_depot_id--[[@as uint]]]
|
||||
remove_train(map_data, train_id, train)
|
||||
send_lost_train_alert(train.entity, depot.entity_stop.backer_name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@param map_data MapData
|
||||
---@param train_id uint
|
||||
---@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 train.manifest then
|
||||
on_failed_delivery(map_data, train_id, train)
|
||||
end
|
||||
remove_train(map_data, train_id, train)
|
||||
end
|
||||
end
|
||||
---@param map_data MapData
|
||||
---@param pre_train_id uint
|
||||
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.manifest then
|
||||
on_failed_delivery(map_data, pre_train_id, train)
|
||||
end
|
||||
remove_train(map_data, pre_train_id, train)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function on_train_built(event)
|
||||
local train_e = event.train
|
||||
if event.old_train_id_1 then
|
||||
on_train_modified(global, event.old_train_id_1)
|
||||
end
|
||||
if event.old_train_id_2 then
|
||||
on_train_modified(global, event.old_train_id_2)
|
||||
end
|
||||
end
|
||||
function on_train_changed(event)
|
||||
local train_e = event.train--[[@as LuaTrain]]
|
||||
if not train_e.valid then return end
|
||||
local train_id = train_e.id
|
||||
if train_e.state == defines.train_state.wait_station then
|
||||
local stop = train_e.station
|
||||
if stop and stop.valid and stop.name == "train-stop" then
|
||||
local id = stop.unit_number--[[@as uint]]
|
||||
if global.stations[id] then
|
||||
local train = global.trains[train_id]
|
||||
if train then
|
||||
on_train_arrives_station(global, id, train_id, train)
|
||||
end
|
||||
elseif global.depots[id] then
|
||||
on_train_arrives_depot(global, id, train_e)
|
||||
elseif global.refuelers[id] then
|
||||
local train = global.trains[train_id]
|
||||
if train then
|
||||
on_train_arrives_refueler(global, id, train_id, train)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif event.old_state == defines.train_state.wait_station then
|
||||
local train = global.trains[train_id]
|
||||
if train then
|
||||
on_train_leaves_stop(global, mod_settings, train_id, train)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -47,17 +47,24 @@ data:extend({
|
||||
},
|
||||
{
|
||||
type = "double-setting",
|
||||
name = "cybersyn-depot-bypass-threshold",
|
||||
name = "cybersyn-fuel-threshold",
|
||||
order = "ae",
|
||||
setting_type = "runtime-global",
|
||||
default_value = .5,
|
||||
minimum_value = 0,
|
||||
maximum_value = 1,
|
||||
},
|
||||
{
|
||||
type = "bool-setting",
|
||||
name = "cybersyn-depot-bypass-enabled",
|
||||
order = "af",
|
||||
setting_type = "runtime-global",
|
||||
default_value = true,
|
||||
},
|
||||
{
|
||||
type = "double-setting",
|
||||
name = "cybersyn-warmup-time",
|
||||
order = "af",
|
||||
order = "ag",
|
||||
setting_type = "runtime-global",
|
||||
default_value = 20,
|
||||
minimum_value = 0,
|
||||
@@ -66,7 +73,7 @@ data:extend({
|
||||
{
|
||||
type = "double-setting",
|
||||
name = "cybersyn-stuck-train-time",
|
||||
order = "ag",
|
||||
order = "ah",
|
||||
setting_type = "runtime-global",
|
||||
default_value = 600,
|
||||
minimum_value = 0,
|
||||
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 343 KiB |
|
After Width: | Height: | Size: 325 KiB |