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)
## 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.
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)
![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.
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.
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
Date: 2022-1-7
Bugfixes:
@@ -12,7 +21,7 @@ Date: 2022-1-5
Features:
- Improved placeholder cybernetic combinator art
- 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:
- Sped up the rate at which copy-paste by blueprint will be noticed
Bugfixes:

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
--By Mami
local ceil = math.ceil
local table_insert = table.insert
local table_remove = table.remove
---@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})
for stop in rnext_consume, stops do
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]]
goto continue
end
@@ -138,10 +139,25 @@ local function on_station_built(map_data, stop, comb1, comb2)
item_p_counts = {},
item_thresholds = nil,
display_state = 0,
is_warming_up = true,
}
local id = stop.unit_number--[[@as uint]]
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_cycles[id] = 0
if not map_data.queue_station_update then
map_data.queue_station_update = {}
end

View File

@@ -267,6 +267,32 @@ local migrations_table = {
train.use_any_depot = true
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

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.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)
local fuel_fill = 1
if mod_settings.fuel_threshold < 1 then
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
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 fuel_fill == 1, it's probably a modded electric train
if not train.disable_bypass then
train.status = STATUS_TO_D_BYPASS
add_available_train(map_data, train_id, train)

View File

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