mirror of
https://github.com/Xevion/project-cybersyn.git
synced 2025-12-10 06:08:11 -06:00
Merge pull request #31 from mamoniot/experimental
This commit is contained in:
11
README.md
11
README.md
@@ -6,18 +6,17 @@ Behold one of the most feature-rich and performant train logistics network mods
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
|
||||

|
||||

|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cybersyn",
|
||||
"version": "1.2.9",
|
||||
"version": "1.3.0",
|
||||
"title": "Project Cybersyn",
|
||||
"author": "Mami",
|
||||
"factorio_version": "1.1",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
--},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user