added entities

This commit is contained in:
Monica Moniot
2022-10-16 01:44:59 -04:00
parent fc050f39c1
commit 822c9b6a7e
17 changed files with 450 additions and 106 deletions

19
mtc/scripts/constants.lua Normal file
View File

@@ -0,0 +1,19 @@
--By Mami
SIGNAL_PRIORITY = "cybersyn-priority"
REQUEST_THRESHOLD = "cybersyn-request-threshold"
PROVIDE_THRESHOLD = "cybersyn-provide-threshold"
STATION_IN_NAME = "cybersyn-station-in"
STATION_OUT_NAME = "cybersyn-station-out"
BUFFER_STATION_NAME = "cybersyn-station"
DEPOT_STATION_NAME = "cybersyn-depot"
DELTA = 1/2048
STATUS_D = 0
STATUS_D_TO_P = 1
STATUS_P = 2
STATUS_P_TO_R = 3
STATUS_R = 4
STATUS_R_TO_D = 5

View File

@@ -1,4 +1,4 @@
--By Monica Moniot
--By Mami
local get_distance = require("__flib__.misc").get_distance
local math = math
local INF = math.huge
@@ -22,7 +22,8 @@ local function icpairs(a, start_i)
end
end
local function create_loading_order(stop, manifest)
local create_loading_order_condition = {type = "inactivity", compare_type = "and", ticks = 120}
function create_loading_order(stop, manifest)
local condition = {}
for _, item in ipairs(manifest) do
local cond_type
@@ -32,23 +33,24 @@ local function create_loading_order(stop, manifest)
cond_type = "item_count"
end
condition[#condition + 1] = {
condition[1] = {
type = cond_type,
compare_type = "and",
condition = {comparator = "", first_signal = {type = item.type, name = item.name}, constant = item.count}
}
condition[2] = create_loading_order_condition
end
return {station = stop.backer_name, wait_conditions = condition}
end
local create_unloading_order_condition = {type = "empty", compare_type = "and"}
local function create_unloading_order(stop, manifest)
function create_unloading_order(stop)
return {station = stop.backer_name, wait_conditions = create_unloading_order_condition}
end
local create_inactivity_order_condition = {type = "inactivity", compare_type = "and", ticks = 3}
local function create_inactivity_order(stop)
return {station = stop.backer_name, wait_conditions = create_inactivity_order_condition}
local create_inactivity_order_condition = create_loading_order_condition
function create_inactivity_order(depot_name)
return {station = depot_name, wait_conditions = create_inactivity_order_condition}
end
local create_direct_to_station_order_condition = {{type = "time", compare_type = "and", ticks = 0}}
@@ -58,18 +60,23 @@ end
local function get_signals(stations, station_id)
return {}
local function get_signals(station)
local signals = station.entity_in.get_merged_signals()
return signals
end
local function get_stop_dist(stop0, stop1)
return get_distance(stop0.position, stop1.position)
end
local function get_valid_train(stations, r_station_id, p_station_id, available_trains, item_type)
local function station_accepts_layout(station, layout_id)
return true
end
local function get_valid_train(map_data, r_station_id, p_station_id, item_type)
--NOTE: this code is the critical section for run-time optimization
local r_station = stations[r_station_id]
local p_station = stations[p_station_id]
local r_station = map_data.stations[r_station_id]
local p_station = map_data.stations[p_station_id]
local p_to_r_dist = get_stop_dist(p_station.entity, r_station.entity)
if p_to_r_dist == INF then
@@ -81,14 +88,15 @@ 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 train_id, _ in pairs(available_trains) do
for train_id, _ in pairs(map_data.trains_available) do
local train = map_data.trains[train_id]
--check cargo capabilities
--check layout validity for both stations
if
((is_fluid and train.fluid_capacity > 0) or (not is_fluid and train.item_slot_capacity > 0))
and r_station.accepted_layouts[train.layout_id] and p_station.accepted_layouts[train.layout_id]
and train.entity.station
((is_fluid and train.fluid_capacity > 0) or (not is_fluid and train.item_slot_capacity > 0))
and station_accepts_layout(r_station, train.layout_id)
and station_accepts_layout(p_station, train.layout_id)
and train.entity.station
then
valid_train_exists = true
--check if exists valid path
@@ -110,14 +118,14 @@ 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, available_trains, primary_item_name, economy)
local r_station = stations[r_station_id]
local p_station = stations[p_station_id]
local function send_train_between(map_data, r_station_id, p_station_id, train, primary_item_name, economy)
local r_station = map_data.stations[r_station_id]
local p_station = map_data.stations[p_station_id]
local requests = {}
local manifest = {}
local r_signals = get_signals(r_station_id)
local r_signals = get_signals(r_station)
for k, v in pairs(r_signals) do
local item_name = v.signal.name
local item_count = v.count
@@ -130,7 +138,7 @@ local function send_train_between(stations, r_station_id, p_station_id, train, a
end
end
local p_signals = get_signals(r_station_id)
local p_signals = get_signals(r_station)
for k, v in pairs(p_signals) do
local item_name = v.signal.name
local item_count = v.count
@@ -193,8 +201,8 @@ local function send_train_between(stations, r_station_id, p_station_id, train, a
for _, 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] + item.count
p_station.deliveries[item.name] = p_station.deliveries[item.name] - item.count
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
local r_stations = economy.r_stations_all[item.name]
local p_stations = economy.p_stations_all[item.name]
@@ -212,22 +220,20 @@ local function send_train_between(stations, r_station_id, p_station_id, train, a
end
end
available_trains[train.entity.id] = nil
map_data.trains_available[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)
records[#records + 1] = create_direct_to_station_order(p_station.entity)
records[#records + 1] = create_loading_order(p_station.entity, manifest)
records[#records + 1] = create_direct_to_station_order(p_station.entity)
records[#records + 1] = create_unloading_order(p_station.entity, manifest)
local records = {
create_inactivity_order(train.depot_name),
create_direct_to_station_order(p_station.entity),
create_loading_order(p_station.entity, manifest),
create_direct_to_station_order(r_station.entity),
create_unloading_order(r_station.entity),
}
local schedule = {current = 1, records = records}
train.entity.schedule = schedule
@@ -235,7 +241,9 @@ local function send_train_between(stations, r_station_id, p_station_id, train, a
end
function tick(stations, available_trains, ticks_total)
function tick(map_data, mod_settings)
local ticks_total = map_data.ticks_total
local stations = map_data.stations
local economy = {
r_stations_all = {},
p_stations_all = {},
@@ -248,10 +256,10 @@ function tick(stations, available_trains, ticks_total)
for station_id, station in pairs(stations) do
if station.deliveries_total < station.train_limit then
station.r_threshold = 0
station.p_threshold = 0
station.r_threshold = mod_settings.r_threshold
station.p_threshold = mod_settings.p_threshold
station.priority = 0
local signals = get_signals(station_id)
local signals = get_signals(station)
for k, v in pairs(signals) do
local item_name = v.signal.name
local item_count = v.count
@@ -316,7 +324,7 @@ function tick(stations, available_trains, ticks_total)
local highest_prior = -INF
local could_have_been_serviced = false
for j, p_station_id in ipairs(p_stations) do
local train, d = get_valid_train(stations, r_station_id, p_station_id, available_trains)
local train, d = get_valid_train(map_data, r_station_id, p_station_id)
local prior = stations[p_station_id].priority
if prior > highest_prior or (prior == highest_prior and d < best_dist) then
if train then
@@ -330,7 +338,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, available_trains, item_name, economy)
send_train_between(map_data, r_station_id, p_stations[best], best_train, item_name, economy)
elseif could_have_been_serviced then
failed_because_missing_trains_total = failed_because_missing_trains_total + 1
end
@@ -350,7 +358,7 @@ function tick(stations, available_trains, ticks_total)
local r_station = stations[r_station_id]
local prior = r_station.priority
if prior > highest_prior or (prior == highest_prior and r_station.last_delivery_tick < lowest_tick) then
local train, d = get_valid_train(stations, r_station_id, p_station_id, available_trains)
local train, d = get_valid_train(map_data, r_station_id, p_station_id)
if train then
best = i
best_train = train
@@ -362,7 +370,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, available_trains, item_name, economy)
send_train_between(map_data, r_stations[best], p_station_id, best_train, item_name, economy)
elseif could_have_been_serviced then
failed_because_missing_trains_total = failed_because_missing_trains_total + 1
end

View File

@@ -1,4 +1,4 @@
--By Monica Moniot
--By Mami
--[[
global: {
@@ -21,13 +21,15 @@ Station: {
deliveries: {
[item_name]: int
}
train_layout: [char]
--train_layout: [char]
accepted_layouts: {
[layout_id]: bool
}
}
Train: {
entity: LuaEntity
entity_in: LuaEntity
entity_out: LuaEntity
layout_id: int
item_slot_capacity: int
fluid_capacity: int
@@ -44,6 +46,11 @@ Train: {
Layout: string
]]
--TODO: only init once
mod_settings = {}
mod_settings.tps = settings.global["cybersyn-ticks-per-second"]
mod_settings.r_threshold = settings.global["cybersyn-requester-threshold"]
mod_settings.p_threshold = settings.global["cybersyn-provider-threshold"]
global.total_ticks = 0
global.stations = {}
global.trains = {}
@@ -51,10 +58,3 @@ global.trains_available = {}
global.layouts = {}
global.layout_train_count = {}
global.layout_top_id = 1
STATUS_D = 0
STATUS_D_TO_P = 1
STATUS_P = 2
STATUS_P_TO_R = 3
STATUS_R = 4
STATUS_R_TO_D = 5

View File

@@ -1,8 +1,9 @@
--By Monica Moniot
--By Mami
local function on_failed_delivery(map_data, train)
--NOTE: must change train status to STATUS_D or remove it from tracked trains after this call
local is_p_delivery_made = train.status ~= STATUS_D_TO_P and train.status ~= STATUS_P
if not is_p_delivery_made then
local station = map_data.stations[train.p_station_id]
@@ -13,6 +14,10 @@ local function on_failed_delivery(map_data, train)
end
end
station.deliveries_total = station.deliveries_total - 1
if train.status == STATUS_P then
--change circuit outputs
station.entity_out.get_control_behavior().parameters = nil
end
end
local is_r_delivery_made = train.status == STATUS_R_TO_D
if not is_r_delivery_made then
@@ -24,12 +29,14 @@ local function on_failed_delivery(map_data, train)
end
end
station.deliveries_total = station.deliveries_total - 1
if train.status == STATUS_R then
--change circuit outputs
station.entity_out.get_control_behavior().parameters = nil
end
end
--TODO: change circuit outputs
train.r_station_id = 0
train.p_station_id = 0
train.manifest = nil
--NOTE: must change train status to STATUS_D or remove it from tracked trains after call
end
local function remove_train(map_data, train, train_id)
@@ -49,22 +56,104 @@ local function remove_train(map_data, train, train_id)
end
local function on_station_built(map_data, stop)
--TODO: update station stats
local pos_x = stop.position.x
local pos_y = stop.position.y
local in_pos
local out_pos
local direction
local search_area
if stop.direction == 0 then
direction = 0
in_pos = {pos_x, pos_y - 1}
out_pos = {pos_x - 1, pos_y - 1}
search_area = {
{pos_x + DELTA - 1, pos_y + DELTA - 1},
{pos_x - DELTA + 1, pos_y - DELTA}
}
elseif stop.direction == 2 then
direction = 2
in_pos = {pos_x, pos_y}
out_pos = {pos_x, pos_y - 1}
search_area = {
{pos_x + DELTA, pos_y + DELTA - 1},
{pos_x - DELTA + 1, pos_y - DELTA + 1}
}
elseif stop.direction == 4 then
direction = 4
in_pos = {pos_x - 1, pos_y}
out_pos = {pos_x, pos_y}
search_area = {
{pos_x + DELTA - 1, pos_y + DELTA},
{pos_x - DELTA + 1, pos_y - DELTA + 1}
}
elseif stop.direction == 6 then
direction = 6
in_pos = {pos_x - 1, pos_y - 1}
out_pos = {pos_x - 1, pos_y}
search_area = {
{pos_x + DELTA - 1, pos_y + DELTA - 1},
{pos_x - DELTA, pos_y - DELTA + 1}
}
else
assert(false, "cybersyn: invalid direction of train stop")
end
local entity_in = nil
local entity_out = nil
local entities = stop.surface.find_entities(search_area)
for _, cur_entity in pairs (entities) do
if cur_entity.valid then
if cur_entity.name == "entity-ghost" then
if cur_entity.ghost_name == STATION_IN_NAME then
_, entity_in = cur_entity.revive()
elseif cur_entity.ghost_name == STATION_OUT_NAME then
_, entity_out = cur_entity.revive()
end
elseif cur_entity.name == STATION_IN_NAME then
entity_in = cur_entity
elseif cur_entity.name == STATION_OUT_NAME then
entity_out = cur_entity
end
end
end
if entity_in == nil then -- create new
entity_in = stop.surface.create_entity({
name = STATION_IN_NAME,
position = in_pos,
force = stop.force
})
end
entity_in.operable = false
entity_in.minable = false
entity_in.destructible = false
if entity_out == nil then -- create new
entity_out = stop.surface.create_entity({
name = STATION_OUT_NAME,
position = out_pos,
direction = direction,
force = stop.force
})
end
entity_out.operable = false
entity_out.minable = false
entity_out.destructible = false
local station = {
entity = stop,
entity_in = entity_in,
entity_out = entity_out,
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
}
accepted_layouts = {}
}
map_data.stations[stop.unit_number] = station
end
local function on_station_broken(map_data, stop)
@@ -92,6 +181,33 @@ local function on_station_broken(map_data, stop)
map_data.stations[station_id] = nil
end
local function on_station_rename(map_data, stop)
--search for trains coming to the renamed station
local station_id = stop.unit_number
local station = map_data.stations[station_id]
for train_id, train in pairs(map_data.trains) do
if station.deliveries_total <= 0 then
break
end
local is_p = train.r_station_id == station_id
local is_r = train.p_station_id == station_id
if is_p or is_r then
local is_p_delivery_made = train.status ~= STATUS_D_TO_P and train.status ~= STATUS_P
local is_r_delivery_made = train.status == STATUS_R_TO_D
if (is_r and not is_r_delivery_made) or (is_p and not is_p_delivery_made) then
--train is attempting delivery to a stop that was renamed
--TODO: test to make sure this code actually works
local record = train.entity.schedule.records
if is_p then
record[3] = create_loading_order(station.entity, train.manifest)
else
record[5] = create_unloading_order(station.entity)
end
end
end
end
end
local function find_and_add_all_stations(map_data)
for _, surface in pairs(game.surfaces) do
@@ -141,35 +257,35 @@ local function update_train_layout(map_data, train)
map_data.layouts[layout_id] = layout
map_data.layout_train_count[layout_id] = 1
for station_id, station in pairs(map_data.stations) do
if #layout >= #station.train_layout then
local is_approved = true
for i, v in ipairs(station.train_layout) do
local c = string.sub(layout, i, i)
if v == "C" then
if c ~= "C" and c ~= "?" then
is_approved = false
break
end
elseif v == "F" then
if c ~= "F" then
is_approved = false
break
end
end
end
for i = #station.train_layout, #layout do
local c = string.sub(layout, i, i)
if c ~= "?" then
is_approved = false
break
end
end
if is_approved then
station.accepted_layouts[layout_id] = true
end
end
end
--for station_id, station in pairs(map_data.stations) do
-- if #layout >= #station.train_layout then
-- local is_approved = true
-- for i, v in ipairs(station.train_layout) do
-- local c = string.sub(layout, i, i)
-- if v == "C" then
-- if c ~= "C" and c ~= "?" then
-- is_approved = false
-- break
-- end
-- elseif v == "F" then
-- if c ~= "F" then
-- is_approved = false
-- break
-- end
-- end
-- end
-- for i = #station.train_layout, #layout do
-- local c = string.sub(layout, i, i)
-- if c ~= "?" then
-- is_approved = false
-- break
-- end
-- end
-- if is_approved then
-- station.accepted_layouts[layout_id] = true
-- end
-- end
--end
else
map_data.layout_train_count[layout_id] = map_data.layout_train_count[layout_id] + 1
end
@@ -229,12 +345,24 @@ local function on_train_arrives_buffer(map_data, station_id, train)
if train.status == STATUS_D_TO_P then
if train.p_station_id == station_id then
train.status = STATUS_P
--TODO: change circuit outputs
--change circuit outputs
local station = map_data.stations[station_id]
local signals = {}
for i, item in ipairs(train.manifest) do
signals[i] = {index = i, signal = {type = item.type, name = item.name}, count = item.count}
end
station.entity_out.get_control_behavior().parameters = signals
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
--change circuit outputs
local station = map_data.stations[station_id]
local signals = {}
for i, item in ipairs(train.manifest) do
signals[i] = {index = i, signal = {type = item.type, name = item.name}, count = -1}
end
station.entity_out.get_control_behavior().parameters = signals
end
else
on_failed_delivery(map_data, train)
@@ -258,7 +386,8 @@ local function on_train_leaves_station(map_data, train)
end
end
station.deliveries_total = station.deliveries_total - 1
--TODO: change circuit outputs
--change circuit outputs
station.entity_out.get_control_behavior().parameters = nil
elseif train.status == STATUS_R then
train.status = STATUS_R_TO_D
local station = map_data.stations[train.r_station_id]
@@ -269,7 +398,8 @@ local function on_train_leaves_station(map_data, train)
end
end
station.deliveries_total = station.deliveries_total - 1
--TODO: change circuit outputs
--change circuit outputs
station.entity_out.get_control_behavior().parameters = nil
end
end
end
@@ -301,8 +431,10 @@ local function on_train_modified(map_data, pre_train_id, train_entity)
end
local function on_tick(event)
tick(global.stations, global.trains_available, global.total_ticks)
tick(global, mod_settings)
global.total_ticks = global.total_ticks + 1
end
@@ -313,6 +445,9 @@ local function on_built(event)
on_station_built(global, entity)
elseif entity.type == "inserter" then
elseif entity.type == "pump" then
if entity.pump_rail_target then
end
end
end
local function on_broken(event)
@@ -371,6 +506,12 @@ local function on_surface_removed(event)
end
end
local function on_rename(event)
if event.entity.name == BUFFER_STATION_NAME then
on_station_rename(global, event.entity)
end
end
local filter_built = {
{filter = "type", type = "train-stop"},
{filter = "type", type = "inserter"},
@@ -383,6 +524,7 @@ local filter_broken = {
{filter = "rolling-stock"},
}
local function register_events()
--NOTE: I have no idea if this correctly registers all events once in all situations
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)
@@ -394,11 +536,14 @@ local function register_events()
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)
local nth_tick = math.ceil(60/mod_settings.tps);
script.on_nth_tick(nil)
script.on_nth_tick(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)
script.on_event(defines.events.on_entity_renamed, on_rename)
end
script.on_load(function()