Merge pull request #31 from mamoniot/experimental

This commit is contained in:
Monica Moniot
2023-01-09 11:16:38 -05:00
committed by GitHub
9 changed files with 112 additions and 44 deletions

View File

@@ -6,18 +6,17 @@ Behold one of the most feature-rich and performant train logistics network mods
![Image](https://raw.githubusercontent.com/mamoniot/project-cybersyn/main/previews/outpost-resupply-station.png) ![Image](https://raw.githubusercontent.com/mamoniot/project-cybersyn/main/previews/outpost-resupply-station.png)
## Quick Start Guide
Copy the contents of [Project Cybersyn Official Example Blueprints](https://raw.githubusercontent.com/mamoniot/project-cybersyn/main/cybersyn_blueprints.txt) and paste them into the import string text box to see examples of how to create a functional network. I highly recommend taking a look at these; the blueprint book showcases both the basics of the mod and highly advanced designs you can create. ## [Project Cybersyn Official Example Blueprints](https://raw.githubusercontent.com/mamoniot/project-cybersyn/main/cybersyn_blueprints.txt)
Copy the contents of https://raw.githubusercontent.com/mamoniot/project-cybersyn/main/cybersyn_blueprints.txt and paste them into the import string text box to see examples of how to create a functional network. I highly recommend taking a look at these; the blueprint book showcases both the basics of the mod and highly advanced designs you can create.
## 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. 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 "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. 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 "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.
![Image](https://raw.githubusercontent.com/mamoniot/project-cybersyn/main/previews/basic-provider.png) 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. Then add the signal called "Request threshold" to the constant combinator. Set its signal strength to be at most the cargo capacity of the trains in your system. 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. Be sure that the requester station has the space to at minimum unload 2 fully loaded trains.
![Image](https://raw.githubusercontent.com/mamoniot/project-cybersyn/main/previews/basic-requester.png)
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. Be sure that the requester station has the space to at minimum unload 2 fully loaded trains.
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. There is one issue with this kind of network though; trains won't always deliver full loads of cargo, meaning trains will make deliveries more frequently than is necessary. To fix this issue you will need to start using "request thresholds". To get a full picture of how request thresholds work, either import the official example blueprints from above, or read the **Request thresholds** section below. 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. There is one issue with this kind of network though; trains won't always deliver full loads of cargo, meaning trains will make deliveries more frequently than is necessary. To fix this issue you will need to start using "request thresholds". To get a full picture of how request thresholds work, either import the official example blueprints from above, or read the **Request thresholds** section below.

View File

@@ -1,4 +1,13 @@
--------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------
Version: 1.2.10
Date: 2022-1-9
Changes:
- Improved performance when fuel threshold is set to 1
Bugfixes:
- Fixed a bug where it was possible for a single station to be updated twice per dispatch cycle, which could cause a crash
- Fixed a crash where trains would sometimes think a destoyed depot still exists
- Removed unfinished mod setting with the broken translation key
---------------------------------------------------------------------------------------------------
Version: 1.2.9 Version: 1.2.9
Date: 2022-1-7 Date: 2022-1-7
Bugfixes: Bugfixes:
@@ -12,7 +21,7 @@ Date: 2022-1-5
Features: Features:
- Improved placeholder cybernetic combinator art - Improved placeholder cybernetic combinator art
- Added a wagon control setting to bar unfiltered slots in adjacent cargo wagons - Added a wagon control setting to bar unfiltered slots in adjacent cargo wagons
- Added a setting and keybind for toggling on or off the central planner - Added a setting for toggling on or off the central planner
Changes: Changes:
- Sped up the rate at which copy-paste by blueprint will be noticed - Sped up the rate at which copy-paste by blueprint will be noticed
Bugfixes: Bugfixes:

View File

@@ -1,6 +1,6 @@
{ {
"name": "cybersyn", "name": "cybersyn",
"version": "1.2.9", "version": "1.3.0",
"title": "Project Cybersyn", "title": "Project Cybersyn",
"author": "Mami", "author": "Mami",
"factorio_version": "1.1", "factorio_version": "1.1",

View File

@@ -523,7 +523,7 @@ local function tick_poll_station(map_data, mod_settings)
end end
station_id = map_data.active_station_ids[tick_data.i] station_id = map_data.active_station_ids[tick_data.i]
station = map_data.stations[station_id] station = map_data.stations[station_id]
if station then if station and not station.is_warming_up then
if station.network_name then if station.network_name then
break break
end end
@@ -725,22 +725,35 @@ function tick_init(map_data, mod_settings)
map_data.economy.all_r_stations = {} map_data.economy.all_r_stations = {}
map_data.economy.all_names = {} map_data.economy.all_names = {}
for i, id in pairs(map_data.warmup_station_ids) do local i = 1
while i <= #map_data.warmup_station_ids do
local id = map_data.warmup_station_ids[i]
local station = map_data.stations[id] local station = map_data.stations[id]
if station then if station then
if station.last_delivery_tick + mod_settings.warmup_time*mod_settings.tps < map_data.total_ticks then local cycles = map_data.warmup_station_cycles[id]
map_data.active_station_ids[#map_data.active_station_ids + 1] = id --force a station to wait at least 1 cycle so we can be sure active_station_ids was flushed of duplicates
map_data.warmup_station_ids[i] = nil if cycles > 0 then
if station.entity_comb1.valid then if station.last_delivery_tick + mod_settings.warmup_time*mod_settings.tps < map_data.total_ticks then
combinator_update(map_data, station.entity_comb1) station.is_warming_up = nil
else map_data.active_station_ids[#map_data.active_station_ids + 1] = id
on_station_broken(map_data, id, station) map_data.warmup_station_ids[i] = nil
map_data.warmup_station_cycles[id] = nil
if station.entity_comb1.valid then
combinator_update(map_data, station.entity_comb1)
else
on_station_broken(map_data, id, station)
end
end end
else
map_data.warmup_station_cycles[id] = cycles + 1
end end
i = i + 1
else else
map_data.warmup_station_ids[i] = nil table_remove(map_data.warmup_station_ids, i)
map_data.warmup_station_cycles[id] = nil
end end
end end
if map_data.queue_station_update then if map_data.queue_station_update then
for id, _ in pairs(map_data.queue_station_update) do for id, _ in pairs(map_data.queue_station_update) do
local station = map_data.stations[id] local station = map_data.stations[id]
@@ -787,7 +800,7 @@ function tick(map_data, mod_settings)
end end
elseif map_data.tick_state == STATE_DISPATCH then elseif map_data.tick_state == STATE_DISPATCH then
for i = 1, mod_settings.update_rate do for i = 1, mod_settings.update_rate do
tick_dispatch(map_data, mod_settings) if tick_dispatch(map_data, mod_settings) then break end
end end
end end
else else

View File

@@ -9,6 +9,7 @@
---@field public stations {[uint]: Station} ---@field public stations {[uint]: Station}
---@field public active_station_ids uint[] ---@field public active_station_ids uint[]
---@field public warmup_station_ids uint[] ---@field public warmup_station_ids uint[]
---@field public warmup_station_cycles {[uint]: int}
---@field public queue_station_update {[uint]: true?}? ---@field public queue_station_update {[uint]: true?}?
---@field public depots {[uint]: Depot} ---@field public depots {[uint]: Depot}
---@field public refuelers {[uint]: Refueler} ---@field public refuelers {[uint]: Refueler}
@@ -49,6 +50,7 @@
---@field public item_p_counts {[string]: int} --transient ---@field public item_p_counts {[string]: int} --transient
---@field public item_thresholds {[string]: int}? --transient ---@field public item_thresholds {[string]: int}? --transient
---@field public display_state int ---@field public display_state int
---@field public is_warming_up true?
---@class Depot ---@class Depot
---@field public entity_stop LuaEntity ---@field public entity_stop LuaEntity
@@ -146,6 +148,7 @@ function init_global()
global.stations = {} global.stations = {}
global.active_station_ids = {} global.active_station_ids = {}
global.warmup_station_ids = {} global.warmup_station_ids = {}
global.warmup_station_cycles = {}
global.depots = {} global.depots = {}
global.trains = {} global.trains = {}
global.available_trains = {} global.available_trains = {}

View File

@@ -1,6 +1,7 @@
--By Mami --By Mami
local ceil = math.ceil local ceil = math.ceil
local table_insert = table.insert local table_insert = table.insert
local table_remove = table.remove
---@param map_data MapData ---@param map_data MapData
@@ -30,7 +31,7 @@ function on_depot_broken(map_data, depot_id, depot)
local stops = e.force.get_train_stops({name = depot.entity_stop.backer_name, surface = e.surface}) local stops = e.force.get_train_stops({name = depot.entity_stop.backer_name, surface = e.surface})
for stop in rnext_consume, stops do for stop in rnext_consume, stops do
local new_depot_id = stop.unit_number local new_depot_id = stop.unit_number
if map_data.depots[new_depot_id] then if new_depot_id ~= depot_id and map_data.depots[new_depot_id] then
train.depot_id = new_depot_id--[[@as uint]] train.depot_id = new_depot_id--[[@as uint]]
goto continue goto continue
end end
@@ -138,10 +139,25 @@ local function on_station_built(map_data, stop, comb1, comb2)
item_p_counts = {}, item_p_counts = {},
item_thresholds = nil, item_thresholds = nil,
display_state = 0, display_state = 0,
is_warming_up = true,
} }
local id = stop.unit_number--[[@as uint]] local id = stop.unit_number--[[@as uint]]
map_data.stations[id] = station map_data.stations[id] = station
--prevent the same station from warming up multiple times
if map_data.warmup_station_cycles[id] then
--enforce FIFO
for i, v in ipairs(map_data.warmup_station_ids) do
if v == id then
table_remove(map_data.warmup_station_ids, i)
break
end
end
end
map_data.warmup_station_ids[#map_data.warmup_station_ids + 1] = id map_data.warmup_station_ids[#map_data.warmup_station_ids + 1] = id
map_data.warmup_station_cycles[id] = 0
if not map_data.queue_station_update then if not map_data.queue_station_update then
map_data.queue_station_update = {} map_data.queue_station_update = {}
end end

View File

@@ -267,6 +267,32 @@ local migrations_table = {
train.use_any_depot = true train.use_any_depot = true
end end
end, end,
["1.2.10"] = function()
---@type MapData
local map_data = global
map_data.warmup_station_cycles = {}
local is_registered = {}
for i = #map_data.warmup_station_ids, 1, -1 do
local id = map_data.warmup_station_ids[i]
if is_registered[id] then
table.remove(map_data.warmup_station_ids, i)
else
is_registered[id] = true
map_data.warmup_station_cycles[id] = 0
end
end
for i = #map_data.active_station_ids, 1, -1 do
local id = map_data.active_station_ids[i]
if is_registered[id] then
table.remove(map_data.active_station_ids, i)
else
is_registered[id] = true
end
end
end
} }
--STATUS_R_TO_D = 5 --STATUS_R_TO_D = 5

View File

@@ -278,28 +278,30 @@ local function on_train_leaves_stop(map_data, mod_settings, train_id, train)
train.r_station_id = nil train.r_station_id = nil
train.manifest = nil train.manifest = nil
--add to available trains for depot bypass --add to available trains for depot bypass
local fuel_fill = INF local fuel_fill = 1
for _, v in pairs(train.entity.locomotives) do if mod_settings.fuel_threshold < 1 then
for _, loco in pairs(v) do for _, v in pairs(train.entity.locomotives) do
local inv = loco.get_fuel_inventory() for _, loco in pairs(v) do
if inv then local inv = loco.get_fuel_inventory()
local inv_size = #inv if inv then
if inv_size > 0 then local inv_size = #inv
local fuel_total = 0 if inv_size > 0 then
---@type uint local fuel_total = 0
for i = 1, inv_size do ---@type uint
local item = inv[i] for i = 1, inv_size do
if item.valid_for_read then local item = inv[i]
fuel_total = fuel_total + item.count/get_stack_size(map_data, item.name) if item.valid_for_read then
fuel_total = fuel_total + item.count/get_stack_size(map_data, item.name)
end
end end
fuel_fill = min(fuel_fill, fuel_total/inv_size)
end end
fuel_fill = min(fuel_fill, fuel_total/inv_size)
end end
end end
end end
end end
if fuel_fill > mod_settings.fuel_threshold then if fuel_fill > mod_settings.fuel_threshold then
--if fuel_fill == INF, it's probably a modded electric train --if fuel_fill == 1, it's probably a modded electric train
if not train.disable_bypass then if not train.disable_bypass then
train.status = STATUS_TO_D_BYPASS train.status = STATUS_TO_D_BYPASS
add_available_train(map_data, train_id, train) add_available_train(map_data, train_id, train)

View File

@@ -102,13 +102,13 @@ data:extend({
setting_type = "runtime-global", setting_type = "runtime-global",
default_value = false, default_value = false,
}, },
{ --{
type = "int-setting", -- type = "int-setting",
name = "cybersyn-history-length", -- name = "cybersyn-history-length",
setting_type = "runtime-global", -- setting_type = "runtime-global",
minimum_value = 10, -- minimum_value = 10,
maximum_value = 1000, -- maximum_value = 1000,
default_value = 50, -- default_value = 50,
order = "ea", -- order = "ea",
}, --},
}) })