mirror of
https://github.com/Xevion/project-cybersyn.git
synced 2025-12-10 06:08:11 -06:00
added events
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
|
||||
|
||||
--require("scripts.controller")
|
||||
--require("scripts.main")
|
||||
require("scripts.global")
|
||||
require("scripts.controller")
|
||||
require("scripts.main")
|
||||
|
||||
@@ -22,36 +22,6 @@ local function icpairs(a, start_i)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
station: {
|
||||
deliveries_total: int
|
||||
train_limit: int
|
||||
priority: int
|
||||
last_delivery_tick: int
|
||||
r_threshold: int >= 0
|
||||
p_threshold: int >= 0
|
||||
entity: FactorioStop
|
||||
train_layout: [ [ {
|
||||
[car_type]: true|nil
|
||||
} ] ]
|
||||
accepted_layouts: {
|
||||
[layout_id]: true|nil
|
||||
}
|
||||
}
|
||||
train: {
|
||||
layout_id: int
|
||||
depot_id: int
|
||||
depot_name: string
|
||||
item_slot_capacity: int
|
||||
fluid_capacity: int
|
||||
}
|
||||
available_trains: [{
|
||||
layout_id: int
|
||||
capacity: int
|
||||
all: [train]
|
||||
}]
|
||||
]]
|
||||
|
||||
local function create_loading_order(stop, manifest)
|
||||
local condition = {}
|
||||
for _, item in ipairs(manifest) do
|
||||
@@ -111,7 +81,8 @@ local function get_valid_train(stations, r_station_id, p_station_id, available_t
|
||||
local valid_train_exists = false
|
||||
|
||||
local is_fluid = item_type == "fluid"
|
||||
for k, train in pairs(available_trains.all) do
|
||||
for train_id, _ in pairs(available_trains) do
|
||||
local train = map_data.trains[train_id]
|
||||
--check cargo capabilities
|
||||
--check layout validity for both stations
|
||||
if
|
||||
@@ -139,7 +110,7 @@ local function get_valid_train(stations, r_station_id, p_station_id, available_t
|
||||
end
|
||||
end
|
||||
|
||||
local function send_train_between(stations, r_station_id, p_station_id, train, primary_item_name, economy)
|
||||
local function send_train_between(stations, r_station_id, p_station_id, train, available_trains, primary_item_name, economy)
|
||||
local r_station = stations[r_station_id]
|
||||
local p_station = stations[p_station_id]
|
||||
|
||||
@@ -152,7 +123,7 @@ local function send_train_between(stations, r_station_id, p_station_id, train, p
|
||||
local item_count = v.count
|
||||
local item_type = v.signal.type
|
||||
if item_name and item_type and item_type ~= "virtual" then
|
||||
local effective_item_count = item_count + r_station.delivery_amount[item_name]
|
||||
local effective_item_count = item_count + r_station.deliveries[item_name]
|
||||
if -effective_item_count >= r_station.r_threshold then
|
||||
requests[item_name] = -effective_item_count
|
||||
end
|
||||
@@ -165,7 +136,7 @@ local function send_train_between(stations, r_station_id, p_station_id, train, p
|
||||
local item_count = v.count
|
||||
local item_type = v.signal.type
|
||||
if item_name and item_type and item_type ~= "virtual" then
|
||||
local effective_item_count = item_count + p_station.delivery_amount[item_name]
|
||||
local effective_item_count = item_count + p_station.deliveries[item_name]
|
||||
if effective_item_count >= p_station.p_threshold then
|
||||
local r = requests[item_name]
|
||||
if r then
|
||||
@@ -222,8 +193,8 @@ local function send_train_between(stations, r_station_id, p_station_id, train, p
|
||||
for _, item in ipairs(manifest) do
|
||||
assert(item.count > 0, "main.lua error, transfer amount was not positive")
|
||||
|
||||
r_station.delivery_amount[item.name] = r_station.delivery_amount[item.name] + item.count
|
||||
p_station.delivery_amount[item.name] = p_station.delivery_amount[item.name] - item.count
|
||||
r_station.deliveries[item.name] = r_station.deliveries[item.name] + item.count
|
||||
p_station.deliveries[item.name] = p_station.deliveries[item.name] - item.count
|
||||
|
||||
local r_stations = economy.r_stations_all[item.name]
|
||||
local p_stations = economy.p_stations_all[item.name]
|
||||
@@ -241,6 +212,12 @@ local function send_train_between(stations, r_station_id, p_station_id, train, p
|
||||
end
|
||||
end
|
||||
|
||||
available_trains[train.entity.id] = nil
|
||||
train.status = STATUS_D_TO_P
|
||||
train.p_station_id = p_station_id
|
||||
train.r_station_id = r_station_id
|
||||
train.manifest = manifest
|
||||
|
||||
do
|
||||
local records = {}
|
||||
records[#records + 1] = create_inactivity_order(train.depot_name)
|
||||
@@ -297,7 +274,7 @@ function tick(stations, available_trains, ticks_total)
|
||||
for k, v in pairs(signals) do
|
||||
local item_name = v.signal.name
|
||||
local item_count = v.count
|
||||
local effective_item_count = item_count + station.delivery_amount[item_name]
|
||||
local effective_item_count = item_count + station.deliveries[item_name]
|
||||
|
||||
if -effective_item_count >= station.r_threshold then
|
||||
if r_stations_all[item_name] == nil then
|
||||
@@ -353,7 +330,7 @@ function tick(stations, available_trains, ticks_total)
|
||||
end
|
||||
end
|
||||
if best > 0 then
|
||||
send_train_between(stations, r_station_id, p_stations[best], best_train, item_name, economy)
|
||||
send_train_between(stations, r_station_id, p_stations[best], best_train, available_trains, item_name, economy)
|
||||
elseif could_have_been_serviced then
|
||||
failed_because_missing_trains_total = failed_because_missing_trains_total + 1
|
||||
end
|
||||
@@ -385,7 +362,7 @@ function tick(stations, available_trains, ticks_total)
|
||||
end
|
||||
end
|
||||
if best > 0 then
|
||||
send_train_between(stations, r_stations[best], p_station_id, best_train, item_name, economy)
|
||||
send_train_between(stations, r_stations[best], p_station_id, best_train, available_trains, item_name, economy)
|
||||
elseif could_have_been_serviced then
|
||||
failed_because_missing_trains_total = failed_because_missing_trains_total + 1
|
||||
end
|
||||
|
||||
56
mtc/scripts/global.lua
Normal file
56
mtc/scripts/global.lua
Normal file
@@ -0,0 +1,56 @@
|
||||
--By Monica Moniot
|
||||
|
||||
--[[
|
||||
global: {
|
||||
total_ticks: int
|
||||
stations: {[stop_id]: Station}
|
||||
trains: {[train_id]: Train}
|
||||
trains_available: {[train_id]: bool}
|
||||
}
|
||||
Station: {
|
||||
deliveries_total: int
|
||||
train_limit: int
|
||||
priority: int
|
||||
last_delivery_tick: int
|
||||
r_threshold: int >= 0
|
||||
p_threshold: int >= 0
|
||||
entity: LuaEntity
|
||||
deliveries: {
|
||||
[item_name]: int
|
||||
}
|
||||
train_layout: [ [ {
|
||||
[car_type]: bool
|
||||
} ] ]
|
||||
accepted_layouts: {
|
||||
[layout_id]: bool
|
||||
}
|
||||
}
|
||||
Train: {
|
||||
entity: LuaEntity
|
||||
layout_id: int
|
||||
item_slot_capacity: int
|
||||
fluid_capacity: int
|
||||
depot_id: int
|
||||
depot_name: string
|
||||
status: int
|
||||
p_station_id: stop_id
|
||||
r_station_id: stop_id
|
||||
manifest: [{
|
||||
name: string
|
||||
type: string
|
||||
count: int
|
||||
}]
|
||||
}
|
||||
]]
|
||||
|
||||
global.total_ticks = 0
|
||||
global.stations = {}
|
||||
global.trains = {}
|
||||
global.trains_available = {}
|
||||
|
||||
STATUS_D = 0
|
||||
STATUS_D_TO_P = 1
|
||||
STATUS_P = 2
|
||||
STATUS_P_TO_R = 3
|
||||
STATUS_R = 4
|
||||
STATUS_R_TO_D = 5
|
||||
@@ -1,163 +1,219 @@
|
||||
local function get_item_amount(station, item_id)
|
||||
return 0
|
||||
end
|
||||
|
||||
local function get_valid_train(stations, r_station_i, p_station_i, available_trains)
|
||||
return {}
|
||||
end
|
||||
|
||||
local function get_distance(stations, r_station_i, p_station_i)
|
||||
return 0
|
||||
end
|
||||
|
||||
local function send_train_between(stations, r_station_i, p_station_i, train)
|
||||
local r_station = stations[r_station_i]
|
||||
local p_station = stations[p_station_i]
|
||||
r_station.last_p_station_i = p_station_i
|
||||
p_station.last_r_station_i = r_station_i
|
||||
|
||||
r_station.deliveries_total = r_station.deliveries_total + 1
|
||||
p_station.deliveries_total = p_station.deliveries_total + 1
|
||||
|
||||
local r_amount = get_item_amount(r_station, item_id) + r_station.delivery_amount[item_id]
|
||||
local p_amount = get_item_amount(p_station, item_id) + p_station.delivery_amount[item_id]
|
||||
local transfer_amount = math.min(train.capacity, -r_amount, p_amount)
|
||||
assert(transfer_amount > 0, "main.lua error, transfer amount was not positive")
|
||||
|
||||
r_station.delivery_amount[item_id] = r_station.delivery_amount[item_id] + transfer_amount
|
||||
p_station.delivery_amount[item_id] = p_station.delivery_amount[item_id] - transfer_amount
|
||||
end
|
||||
|
||||
--[[
|
||||
station: {
|
||||
deliveries_total: int
|
||||
train_limit: int
|
||||
requester_limit: int > 0
|
||||
provider_limit: int > 0
|
||||
priority: int
|
||||
last_delivery_tick: int
|
||||
train_layout: [ [ {
|
||||
[car_type]: true|nil
|
||||
} ] ]
|
||||
accepted_layouts: {
|
||||
[layout_id]: true|nil
|
||||
--By Monica Moniot
|
||||
local function on_station_built(map_data, stop)
|
||||
local station = {
|
||||
deliveries_total = 0,
|
||||
train_limit = 100,
|
||||
priority = 0,
|
||||
last_delivery_tick = 0,
|
||||
r_threshold = 0,
|
||||
p_threshold = 0,
|
||||
entity = stop,
|
||||
--train_layout: [ [ {
|
||||
-- [car_type]: true|nil
|
||||
--} ] ]
|
||||
accepted_layouts = {
|
||||
--[layout_id]: true|nil
|
||||
}
|
||||
}
|
||||
available_trains: [{
|
||||
layout_id: int
|
||||
capacity: int
|
||||
}]
|
||||
]]
|
||||
map_data.stations[stop.unit_number] = station
|
||||
end
|
||||
local function on_station_broken(map_data, stop)
|
||||
end
|
||||
|
||||
|
||||
local function icpairs(a, start_i)
|
||||
start_i = start_i%#a + 1
|
||||
local i = start_i - 1
|
||||
local flag = true
|
||||
return function()
|
||||
i = i%#a + 1
|
||||
if i ~= start_i or flag then
|
||||
flag = false
|
||||
local v = a[i]
|
||||
if v then
|
||||
return i, v
|
||||
local function find_and_add_all_stations(map_data)
|
||||
for _, surface in pairs(game.surfaces) do
|
||||
local stops = surface.find_entities_filtered({type="train-stop"})
|
||||
if stops then
|
||||
for k, stop in pairs(stops) do
|
||||
if stop.name == BUFFER_STATION_NAME then
|
||||
local station = map_data.stations[stop.unit_number]
|
||||
if not station then
|
||||
on_station_built(map_data, stop)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function tick(stations, all_items, available_trains, ticks_total)
|
||||
if #all_items == 0 then
|
||||
return
|
||||
end
|
||||
local failed_because_missing_trains_total = 0
|
||||
--psuedo-randomize what item (and what station) to check first so if trains available is low they choose orders psuedo-randomly
|
||||
for _, item_id in icpairs(all_items, ticks_total) do
|
||||
local r_stations = {}
|
||||
local p_stations = {}
|
||||
|
||||
for station_i, station in pairs(stations) do
|
||||
if station.deliveries_total < station.train_limit then
|
||||
local item_amount = get_item_amount(station, item_id) + station.delivery_amount[item_id]
|
||||
|
||||
if -item_amount >= station.requester_limit then
|
||||
table.insert(r_stations, station_i)
|
||||
elseif item_amount >= station.provider_limit then
|
||||
table.insert(p_stations, station_i)
|
||||
end
|
||||
end
|
||||
local function on_failed_delivery(map_data, train)
|
||||
if train.status == STATUS_D or train.status == STATUS_D_TO_P or train.status == STATUS_P then
|
||||
local station = map_data.stations[train.p_station_id]
|
||||
for i, item in ipairs(train.manifest) do
|
||||
station.deliveries[item.name] = station.deliveries[item.name] + item.count
|
||||
end
|
||||
end
|
||||
if train.status ~= STATUS_R_TO_D then
|
||||
local station = map_data.stations[train.r_station_id]
|
||||
for i, item in ipairs(train.manifest) do
|
||||
station.deliveries[item.name] = station.deliveries[item.name] - item.count
|
||||
end
|
||||
end
|
||||
--TODO: change circuit outputs
|
||||
train.r_station_id = 0
|
||||
train.p_station_id = 0
|
||||
train.manifest = nil
|
||||
--NOTE: must change train status after call or remove it from tracked trains
|
||||
end
|
||||
|
||||
--we do not dispatch more than one train per station per tick
|
||||
|
||||
if #r_stations > 0 and #p_stations > 0 then
|
||||
if #r_stations <= #p_stations then
|
||||
--backpressure, prioritize locality
|
||||
for i, r_station_i in icpairs(r_stations, ticks_total) do
|
||||
|
||||
local best = 0
|
||||
local best_train = nil
|
||||
local best_dist = math.huge
|
||||
local highest_prior = -math.huge
|
||||
local could_have_been_serviced = false
|
||||
for j, p_station_i in ipairs(p_stations) do
|
||||
local d = get_distance(stations, r_station_i, p_station_i)
|
||||
local prior = stations[p_station_i].priority
|
||||
if prior > highest_prior or (prior == highest_prior and d < best_dist) then
|
||||
local train, is_possible = get_valid_train(stations, r_station_i, p_station_i, available_trains)
|
||||
if train then
|
||||
best = j
|
||||
best_dist = d
|
||||
best_train = train
|
||||
highest_prior = prior
|
||||
elseif is_possible then
|
||||
could_have_been_serviced = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if best > 0 then
|
||||
send_train_between(stations, r_station_i, p_stations[best], best_train)
|
||||
table.remove(p_stations, best)
|
||||
elseif could_have_been_serviced then
|
||||
failed_because_missing_trains_total = failed_because_missing_trains_total + 1
|
||||
end
|
||||
end
|
||||
local function on_train_arrives_depot(map_data, train_entity)
|
||||
local train = map_data.trains[train_entity.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
|
||||
else
|
||||
--prioritize round robin
|
||||
for j, p_station_i in icpairs(p_stations, ticks_total) do
|
||||
|
||||
local best = 0
|
||||
local best_train = nil
|
||||
local lowest_tick = math.huge
|
||||
local highest_prior = -math.huge
|
||||
local could_have_been_serviced = false
|
||||
for i, r_station_i in ipairs(r_stations) do
|
||||
local r_station = stations[r_station_i]
|
||||
local prior = r_station.priority
|
||||
if prior > highest_prior or (prior == highest_prior and r_station.last_delivery_tick < lowest_tick) then
|
||||
local train, is_possible = get_valid_train(stations, r_station_i, p_station_i, available_trains)
|
||||
if train then
|
||||
best = i
|
||||
best_train = train
|
||||
lowest_tick = r_station.last_delivery_tick
|
||||
highest_prior = prior
|
||||
elseif is_possible then
|
||||
could_have_been_serviced = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if best > 0 then
|
||||
send_train_between(stations, r_stations[best], p_station_i, best_train)
|
||||
table.remove(r_stations, best)
|
||||
elseif could_have_been_serviced then
|
||||
failed_because_missing_trains_total = failed_because_missing_trains_total + 1
|
||||
end
|
||||
end
|
||||
on_failed_delivery(map_data, train)
|
||||
end
|
||||
end
|
||||
train.depot_id = train_entity.station.unit_number
|
||||
train.depot_name = train_entity.station.backer_name
|
||||
train.status = STATUS_D
|
||||
map_data.trains_available[train_entity.id] = true
|
||||
else
|
||||
map_data.trains[train_entity.id] = {
|
||||
depot_id = train_entity.station.unit_number,
|
||||
depot_name = train_entity.station.backer_name,
|
||||
status = STATUS_D,
|
||||
entity = train_entity,
|
||||
layout_id = 0,
|
||||
item_slot_capacity = 0,
|
||||
fluid_capacity = 0,
|
||||
p_station = 0,
|
||||
r_station = 0,
|
||||
manifest = nil,
|
||||
}
|
||||
end
|
||||
map_data.trains_available[train_entity.id] = true
|
||||
end
|
||||
|
||||
local function on_train_arrives_buffer(map_data, station_id, train)
|
||||
if train.manifest then
|
||||
if train.status == STATUS_D_TO_P then
|
||||
if train.p_station_id == station_id then
|
||||
train.status = STATUS_P
|
||||
--TODO: change circuit outputs
|
||||
end
|
||||
elseif train.status == STATUS_P_TO_R then
|
||||
if train.r_station_id == station_id then
|
||||
train.status = STATUS_R
|
||||
--TODO: change circuit outputs
|
||||
end
|
||||
else
|
||||
on_failed_delivery(map_data, train)
|
||||
map_data.trains[train.entity.id] = nil
|
||||
end
|
||||
else
|
||||
--train is lost somehow, probably from player intervention
|
||||
map_data.trains[train.entity.id] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function on_train_leaves_buffer(map_data, 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]
|
||||
for i, item in ipairs(train.manifest) do
|
||||
station.deliveries[item.name] = station.deliveries[item.name] + item.count
|
||||
end
|
||||
--TODO: change circuit outputs
|
||||
elseif train.status == STATUS_R then
|
||||
train.status = STATUS_R_TO_D
|
||||
local station = map_data.stations[train.r_station_id]
|
||||
for i, item in ipairs(train.manifest) do
|
||||
station.deliveries[item.name] = station.deliveries[item.name] - item.count
|
||||
end
|
||||
--TODO: change circuit outputs
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function on_train_broken(map_data, train)
|
||||
if train.manifest then
|
||||
on_failed_delivery(map_data, train)
|
||||
map_data.trains[train.entity.id] = nil
|
||||
end
|
||||
end
|
||||
|
||||
tick()
|
||||
|
||||
local function on_tick(event)
|
||||
tick(global.stations, global.trains_available, global.total_ticks)
|
||||
global.total_ticks = global.total_ticks + 1
|
||||
end
|
||||
local function on_built(event)
|
||||
local entity = event.entity or event.created_entity or event.destination
|
||||
if not entity or not entity.valid or entity.name ~= BUFFER_STATION_NAME then return end
|
||||
|
||||
on_station_built(global, entity)
|
||||
end
|
||||
local function on_broken(event)
|
||||
local entity = event.entity
|
||||
if not entity or not entity.valid then return end
|
||||
|
||||
if entity.train then
|
||||
local train = global.trains[entity.id]
|
||||
if train then
|
||||
on_train_broken(global, entity.train)
|
||||
end
|
||||
elseif entity.name == BUFFER_STATION_NAME then
|
||||
on_station_broken(entity.unit_number)
|
||||
end
|
||||
end
|
||||
|
||||
local function on_train_changed(event)
|
||||
local train_e = event.train
|
||||
local train = global.trains[train_e.id]
|
||||
if train_e.state == defines.train_state.wait_station and train_e.station ~= nil then
|
||||
if train_e.station.name == DEPOT_STATION_NAME then
|
||||
on_train_arrives_depot(global, train_e)
|
||||
elseif train_e.station.name == BUFFER_STATION_NAME then
|
||||
if train then
|
||||
on_train_arrives_buffer(global, train_e.station.unit_number, train)
|
||||
end
|
||||
end
|
||||
elseif event.old_state == defines.train_state.wait_station then
|
||||
if train and train.is_at_buffer then
|
||||
on_train_leaves_buffer(global, train)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local filter_built = {{filter = "type", type = "train-stop"}}
|
||||
local filter_broken = {{filter = "type", type = "train-stop"}, {filter = "rolling-stock"}}
|
||||
local function register_events()
|
||||
|
||||
script.on_event(defines.events.on_built_entity, on_built, filter_built)
|
||||
script.on_event(defines.events.on_robot_built_entity, on_built, filter_built)
|
||||
script.on_event({defines.events.script_raised_built, defines.events.script_raised_revive, defines.events.on_entity_cloned}, on_built)
|
||||
|
||||
script.on_event(defines.events.on_pre_player_mined_item, on_broken, filter_broken)
|
||||
script.on_event(defines.events.on_robot_pre_mined, on_broken, filter_broken)
|
||||
script.on_event(defines.events.on_entity_died, on_broken, filter_broken)
|
||||
script.on_event(defines.events.script_raised_destroy, on_broken)
|
||||
|
||||
script.on_event({defines.events.on_pre_surface_deleted, defines.events.on_pre_surface_cleared}, on_surface_removed)
|
||||
|
||||
-- script.on_nth_tick(nil)
|
||||
script.on_nth_tick(controller_nth_tick, on_tick)
|
||||
|
||||
script.on_event(defines.events.on_train_created, on_train_built)
|
||||
script.on_event(defines.events.on_train_changed_state, on_train_changed)
|
||||
end
|
||||
|
||||
script.on_load(function()
|
||||
register_events()
|
||||
end)
|
||||
|
||||
script.on_init(function()
|
||||
register_events()
|
||||
end)
|
||||
|
||||
script.on_configuration_changed(function(data)
|
||||
register_events()
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user