diff --git a/cybersyn/graphics/icons/locked_slots.png b/cybersyn/graphics/icons/locked-slots.png similarity index 100% rename from cybersyn/graphics/icons/locked_slots.png rename to cybersyn/graphics/icons/locked-slots.png diff --git a/cybersyn/graphics/icons/lost-train.png b/cybersyn/graphics/icons/lost-train.png new file mode 100644 index 0000000..3f42332 Binary files /dev/null and b/cybersyn/graphics/icons/lost-train.png differ diff --git a/cybersyn/graphics/icons/missing-train.png b/cybersyn/graphics/icons/missing-train.png new file mode 100644 index 0000000..3f42332 Binary files /dev/null and b/cybersyn/graphics/icons/missing-train.png differ diff --git a/cybersyn/graphics/icons/nonempty-train.png b/cybersyn/graphics/icons/nonempty-train.png new file mode 100644 index 0000000..3f42332 Binary files /dev/null and b/cybersyn/graphics/icons/nonempty-train.png differ diff --git a/cybersyn/prototypes/signal.lua b/cybersyn/prototypes/signal.lua index cbc8fff..6e80e5b 100644 --- a/cybersyn/prototypes/signal.lua +++ b/cybersyn/prototypes/signal.lua @@ -32,7 +32,7 @@ r_threshold_signal = { locked_slots_signal = { type = "virtual-signal", name = LOCKED_SLOTS, - icon = "__cybersyn__/graphics/icons/locked_slots.png", + icon = "__cybersyn__/graphics/icons/locked-slots.png", icon_size = 64, subgroup = "cybersyn-signal", order = "a-d" diff --git a/cybersyn/scripts/constants.lua b/cybersyn/scripts/constants.lua index df8b31b..6b0e4a9 100644 --- a/cybersyn/scripts/constants.lua +++ b/cybersyn/scripts/constants.lua @@ -30,13 +30,12 @@ TRAIN_LAYOUT_NA = "N" TRAIN_LAYOUT_CARGO = "C" TRAIN_LAYOUT_FLUID = "F" --TRAIN_LAYOUT_ARTILLERY = "A" - STATION_LAYOUT_NA = "N" -STATION_LAYOUT_CARGO = "C" -STATION_LAYOUT_FLUID = "F" -STATION_LAYOUT_BOTH = "." +STATION_LAYOUT_ALL = "." +STATION_LAYOUT_NOT_FLUID = "[NC]" +STATION_LAYOUT_NOT_CARGO = "[NF]" LONGEST_INSERTER_REACH = 2 -TRAIN_CLASS_ALL = "all" -TRAIN_CLASS_AUTO = "auto" +TRAIN_CLASS_ALL = {name = "all", type = "virtual"} +TRAIN_CLASS_AUTO = {name = "auto", type = "virtual"} diff --git a/cybersyn/scripts/controller.lua b/cybersyn/scripts/controller.lua index 20c6303..592874c 100644 --- a/cybersyn/scripts/controller.lua +++ b/cybersyn/scripts/controller.lua @@ -38,7 +38,6 @@ 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}} ---@param stop LuaEntity local function create_direct_to_station_order(stop) return {rail = stop.connected_rail, rail_direction = stop.connected_rail_direction} @@ -377,7 +376,7 @@ function tick(map_data, mod_settings) local item_count = v.count local effective_item_count = item_count + (station.deliveries[item_name] or 0) local r_threshold, p_threshold = get_thresholds(map_data, station, v.signal) - + if item_name then if -effective_item_count >= r_threshold then if r_stations_all[item_name] == nil then diff --git a/cybersyn/scripts/global.lua b/cybersyn/scripts/global.lua index d7429e2..449030a 100644 --- a/cybersyn/scripts/global.lua +++ b/cybersyn/scripts/global.lua @@ -22,9 +22,9 @@ ---@field public entity_stop LuaEntity ---@field public entity_comb1 LuaEntity ---@field public entity_comb2 LuaEntity? ----@field public wagon_combs {[int]: LuaEntity}?--allowed to be invalid entities +---@field public wagon_combs {[int]: LuaEntity}?--NOTE: allowed to be invalid entities or combinators with the wrong operation, these must be checked and lazy deleted when found ---@field public deliveries {[string]: int} ----@field public train_class string +---@field public train_class SignalID? ---@field public accepted_layouts TrainClass ---@field public layout_pattern string? @@ -57,6 +57,7 @@ mod_settings.p_threshold = settings.global["cybersyn-provide-threshold"].value global.total_ticks = 0 global.to_output = {} +global.to_stop = {} global.stations = {} global.depots = {} global.trains = {} diff --git a/cybersyn/scripts/layout.lua b/cybersyn/scripts/layout.lua index b3d7a2a..ecc5cc5 100644 --- a/cybersyn/scripts/layout.lua +++ b/cybersyn/scripts/layout.lua @@ -75,8 +75,16 @@ end ---@param map_data MapData ---@param station Station -local function reset_station_layout(map_data, station) +---@param forbidden_entity LuaEntity? +local function reset_station_layout(map_data, station, forbidden_entity) + --NOTE: station must be in auto mode local station_rail = station.entity_stop.connected_rail + if station_rail == nil then + --cannot accept deliveries + station.layout_pattern = "X" + station.accepted_layouts = {} + return + end local rail_direction_from_station if station.entity_stop.connected_rail_direction == defines.rail_direction.front then rail_direction_from_station = defines.rail_direction.back @@ -87,26 +95,32 @@ local function reset_station_layout(map_data, station) local surface = station.entity_stop.surface local middle_x = station_rail.position.x local middle_y = station_rail.position.y - local reach = LONGEST_INSERTER_REACH + 1 - DELTA + local reach = LONGEST_INSERTER_REACH + 1 local search_area local area_delta local direction_filter + local is_ver + --local center_line if station_direction == defines.direction.north then - search_area = {left_top = {x = middle_x - reach, y = middle_y}, right_bottom = {x = middle_x + reach, y = middle_y - 6}} - area_delta = {x = 0, y = -7} - direction_filter = {defines.direction.east, defines.direction.west} - elseif station_direction == defines.direction.east then - search_area = {left_top = {y = middle_y - reach, x = middle_x}, right_bottom = {y = middle_y + reach, x = middle_x - 6}} - area_delta = {y = 0, x = -7} - direction_filter = {defines.direction.north, defines.direction.south} - elseif station_direction == defines.direction.south then - search_area = {left_top = {x = middle_x - reach, y = middle_y + 6}, right_bottom = {x = middle_x + reach, y = middle_y}} + search_area = {left_top = {x = middle_x - reach, y = middle_y}, right_bottom = {x = middle_x + reach, y = middle_y + 6}} area_delta = {x = 0, y = 7} direction_filter = {defines.direction.east, defines.direction.west} + is_ver = true + elseif station_direction == defines.direction.east then + search_area = {left_top = {y = middle_y - reach, x = middle_x}, right_bottom = {y = middle_y + reach, x = middle_x - 6}} + area_delta = {x = -7, y = 0} + direction_filter = {defines.direction.north, defines.direction.south} + is_ver = false + elseif station_direction == defines.direction.south then + search_area = {left_top = {x = middle_x - reach, y = middle_y - 6}, right_bottom = {x = middle_x + reach, y = middle_y}} + area_delta = {x = 0, y = -7} + direction_filter = {defines.direction.east, defines.direction.west} + is_ver = true elseif station_direction == defines.direction.west then search_area = {left_top = {y = middle_y - reach, x = middle_x + 6}, right_bottom = {y = middle_y + reach, x = middle_x}} - area_delta = {y = 0, x = 7} + area_delta = {x = 7, y = 0} direction_filter = {defines.direction.north, defines.direction.south} + is_ver = false else assert(false, "cybersyn: invalid station direction") end @@ -114,14 +128,17 @@ local function reset_station_layout(map_data, station) local pre_rail = station_rail local layout_pattern = "^" local layout_min_size = 10000 - local type_filter = {"inserter", "pump"} + local type_filter = {"inserter", "pump", "arithmetic-combinator"} + local wagon_number = 0 for i = 1, 100 do local rail, rail_direction, rail_connection_direction = pre_rail.get_connected_rail({rail_direction = rail_direction_from_station, rail_connection_direction = defines.rail_connection_direction.straight}) - if rail_connection_direction ~= defines.rail_connection_direction.straight or not rail.valid then + if not rail or rail_connection_direction ~= defines.rail_connection_direction.straight or not rail.valid then break end + pre_rail = rail length = length + 2 if length%7 <= 1 then + wagon_number = wagon_number + 1 local supports_cargo = false local supports_fluid = false local entities = surface.find_entities_filtered({ @@ -130,26 +147,64 @@ local function reset_station_layout(map_data, station) direction = direction_filter, }) for _, entity in pairs(entities) do - if entity.type == "inserter" then - --local pickup_pos = entity.prototype.inserter_pickup_position + entity.position - --local drop_pos = entity.prototype.inserter_drop_position + entity.position - --TODO: add further checks - supports_cargo = true - elseif entity.type == "pump" then - if entity.pump_rail_target then - supports_fluid = true + if entity.valid and entity ~= forbidden_entity then + if entity.type == "inserter" then + if not supports_cargo then + local pos = entity.pickup_position + local is_there + if is_ver then + is_there = middle_x - 1 <= pos.x and pos.x <= middle_x + 1 + else + is_there = middle_y - 1 <= pos.y and pos.y <= middle_y + 1 + end + if is_there then + supports_cargo = true + else + pos = entity.drop_position + if is_ver then + is_there = middle_x - 1 <= pos.x and pos.x <= middle_x + 1 + else + is_there = middle_y - 1 <= pos.y and pos.y <= middle_y + 1 + end + if is_there then + supports_cargo = true + end + end + end + elseif entity.type == "pump" then + if not supports_fluid and entity.pump_rail_target then + supports_fluid = true + end + elseif entity.name == COMBINATOR_NAME then + local control = entity.get_or_create_control_behavior().parameters + if control.operation == OPERATION_WAGON_MANIFEST then + local pos = entity.position + local is_there + if is_ver then + is_there = middle_x - 2.1 <= pos.x and pos.x <= middle_x + 2.1 + else + is_there = middle_y - 2.1 <= pos.y and pos.y <= middle_y + 2.1 + end + if is_there then + if not station.wagon_combs then + station.wagon_combs = {} + end + station.wagon_combs[wagon_number] = entity + end + end end end end if supports_cargo then if supports_fluid then - layout_pattern = layout_pattern..STATION_LAYOUT_BOTH + layout_pattern = layout_pattern..STATION_LAYOUT_ALL else - layout_pattern = layout_pattern..STATION_LAYOUT_CARGO + --TODO: needs to allow misc wagons as well + layout_pattern = layout_pattern..STATION_LAYOUT_NOT_FLUID end elseif supports_fluid then - layout_pattern = layout_pattern..STATION_LAYOUT_FLUID + layout_pattern = layout_pattern..STATION_LAYOUT_NOT_CARGO else layout_pattern = layout_pattern..STATION_LAYOUT_NA end @@ -175,17 +230,17 @@ end ---@param map_data MapData ---@param station Station ----@param train_class_name string -function set_station_train_class(map_data, station, train_class_name) - if train_class_name == TRAIN_CLASS_AUTO then - if station.train_class ~= TRAIN_CLASS_AUTO then +---@param train_class SignalID +function set_station_train_class(map_data, station, train_class) + if train_class.name == TRAIN_CLASS_AUTO.name then + if station.train_class.name ~= TRAIN_CLASS_AUTO.name then station.train_class = TRAIN_CLASS_AUTO station.accepted_layouts = {} end - reset_station_layout(map_data, station) + reset_station_layout(map_data, station, nil) else - station.train_class = train_class_name - station.accepted_layouts = map_data.train_classes[train_class_name] + station.train_class = train_class + station.accepted_layouts = map_data.train_classes[train_class.name] assert(station.accepted_layouts ~= nil) station.layout_pattern = nil end @@ -193,26 +248,39 @@ end ---@param map_data MapData ---@param station Station -function update_station_if_auto(map_data, station) - if station.train_class == TRAIN_CLASS_AUTO then - reset_station_layout(map_data, station) +---@param forbidden_entity LuaEntity? +function update_station_if_auto(map_data, station, forbidden_entity) + if station.train_class.name == TRAIN_CLASS_AUTO.name then + reset_station_layout(map_data, station, forbidden_entity) end end ---@param map_data MapData ---@param rail LuaEntity -function update_station_from_rail(map_data, rail) - --TODO: search further? - local entity = rail.get_rail_segment_entity(nil, false) - if entity.name == BUFFER_STATION_NAME then - update_station_if_auto(map_data, map_data.stations[entity.unit_number]) +---@param forbidden_entity LuaEntity +function update_station_from_rail(map_data, rail, forbidden_entity) + --TODO: search further or better? + local entity = rail.get_rail_segment_entity(defines.rail_direction.back, false) + if entity and entity.valid and entity.name == "train-stop" then + local station = map_data.stations[entity.unit_number] + if station then + update_station_if_auto(map_data, station, forbidden_entity) + end + else + entity = rail.get_rail_segment_entity(defines.rail_direction.front, false) + if entity and entity.valid and entity.name == "train-stop" then + local station = map_data.stations[entity.unit_number] + if station then + update_station_if_auto(map_data, station, forbidden_entity) + end + end end end ---@param map_data MapData ---@param pump LuaEntity function update_station_from_pump(map_data, pump) if pump.pump_rail_target then - update_station_from_rail(map_data, pump.pump_rail_target) + update_station_from_rail(map_data, pump.pump_rail_target, pump) end end ---@param map_data MapData @@ -220,16 +288,13 @@ end function update_station_from_inserter(map_data, inserter) --TODO: check if correct local surface = inserter.surface - local pos = inserter.position - local pickup_pos = inserter.prototype.inserter_pickup_position - local drop_pos = inserter.prototype.inserter_drop_position - local rail = surface.find_entity("straight-rail", {pos.x + pickup_pos.x, pos.y + pickup_pos.y}) + local rail = surface.find_entity("straight-rail", inserter.pickup_position) if rail then - update_station_from_rail(map_data, rail) + update_station_from_rail(map_data, rail, inserter) end - rail = surface.find_entity("straight-rail", {pos.x + drop_pos.x, pos.y + drop_pos.y}) + rail = surface.find_entity("straight-rail", inserter.drop_position) if rail then - update_station_from_rail(map_data, rail) + update_station_from_rail(map_data, rail, inserter) end end diff --git a/cybersyn/scripts/main.lua b/cybersyn/scripts/main.lua index 7e717be..e311246 100644 --- a/cybersyn/scripts/main.lua +++ b/cybersyn/scripts/main.lua @@ -48,7 +48,7 @@ local function on_station_built(map_data, stop, comb1, comb2) } map_data.stations[stop.unit_number] = station - update_station_if_auto(map_data, station) + update_station_if_auto(map_data, station, nil) end ---@param map_data MapData ---@param station_id uint @@ -84,8 +84,8 @@ local function search_for_station_combinator(map_data, stop, comb_operation, com local pos_y = stop.position.y --TODO: fix search area local search_area = { - {pos_x + DELTA - 1, pos_y + DELTA - 1}, - {pos_x - DELTA + 1, pos_y - DELTA + 1} + {pos_x - 2, pos_y - 2}, + {pos_x + 2, pos_y + 2} } local entities = stop.surface.find_entities(search_area) for _, entity in pairs(entities) do @@ -108,13 +108,21 @@ local function on_combinator_built(map_data, comb) local pos_y = comb.position.y --TODO: fix search area - local search_area = { - {pos_x + DELTA - 1, pos_y + DELTA - 1}, - {pos_x - DELTA + 1, pos_y - DELTA + 1} - } + local search_area + if comb.direction == defines.direction.north or comb.direction == defines.direction.south then + search_area = { + {pos_x - 1.5, pos_y - 2}, + {pos_x + 1.5, pos_y + 2} + } + else + search_area = { + {pos_x - 2, pos_y - 1.5}, + {pos_x + 2, pos_y + 1.5} + } + end local stop = nil local rail = nil - local entities = stop.surface.find_entities(search_area) + local entities = comb.surface.find_entities(search_area) for _, cur_entity in pairs(entities) do if cur_entity.valid then if cur_entity.name == "train-stop" then @@ -131,15 +139,15 @@ local function on_combinator_built(map_data, comb) position = comb.position, force = comb.force }) - assert(out) + assert(out, "cybersyn: could not spawn combinator controller") comb.connect_neighbour({ target_entity = out, - source_wire_id = defines.circuit_connector_id.combinator_output, + source_circuit_id = defines.circuit_connector_id.combinator_output, wire = defines.wire_type.green, }) comb.connect_neighbour({ target_entity = out, - source_wire_id = defines.circuit_connector_id.combinator_output, + source_circuit_id = defines.circuit_connector_id.combinator_output, wire = defines.wire_type.red, }) @@ -149,7 +157,7 @@ local function on_combinator_built(map_data, comb) local control = comb.get_or_create_control_behavior().parameters if control.operation == OPERATION_WAGON_MANIFEST then if rail then - update_station_from_rail(map_data, rail) + update_station_from_rail(map_data, rail, nil) end elseif control.operation == OPERATION_DEPOT then if stop then @@ -182,49 +190,32 @@ local function on_combinator_built(map_data, comb) --no station or depot --add station - local comb2 = search_for_station_combinator(map_data, stop, OPERATION_SECONDARY_IO, nil) + local comb2 = search_for_station_combinator(map_data, stop, OPERATION_SECONDARY_IO, comb) - station = { - entity_stop = stop, - entity_comb1 = comb, - entity_comb2 = comb2, - wagon_combs = nil, - deliveries_total = 0, - last_delivery_tick = 0, - priority = 0, - r_threshold = 0, - p_threshold = 0, - locked_slots = 0, - deliveries = {}, - train_class = TRAIN_CLASS_AUTO, - accepted_layouts = {}, - layout_pattern = nil, - } - map_data.stations[stop.unit_number] = station - - update_station_if_auto(map_data, station) + on_station_built(map_data, stop, comb, comb2) end end end ---@param map_data MapData ---@param comb LuaEntity local function on_combinator_broken(map_data, comb) + --NOTE: we do not check for wagon manifest combinators and update their stations, it is assumed they will be lazy deleted later local out = map_data.to_output[comb.unit_number] local stop = map_data.to_stop[comb.unit_number] if stop and stop.valid then local station = map_data.stations[stop.unit_number] if station then - if station.comb1 == comb then + if station.entity_comb1 == comb then local comb1 = search_for_station_combinator(map_data, stop, OPERATION_PRIMARY_IO, comb) if comb1 then - station.comb1 = comb1 + station.entity_comb1 = comb1 else on_station_broken(map_data, stop.unit_number, station) map_data.depots[stop.unit_number] = search_for_station_combinator(map_data, stop, OPERATION_DEPOT, nil) end - elseif station.comb2 == comb then - station.comb2 = search_for_station_combinator(map_data, stop, OPERATION_SECONDARY_IO, comb) + elseif station.entity_comb2 == comb then + station.entity_comb2 = search_for_station_combinator(map_data, stop, OPERATION_SECONDARY_IO, comb) end else local depot_comb = map_data.depots[stop.unit_number] @@ -244,7 +235,7 @@ end ---@param map_data MapData ---@param comb LuaEntity local function on_combinator_updated(map_data, comb) - --NOTE: this is the lazy way to implement updates and is not robust + --NOTE: this is the lazy way to implement updates and puts strong restrictions on data validity on on_combinator_broken on_combinator_broken(map_data, comb) on_combinator_built(map_data, comb) end @@ -257,8 +248,8 @@ local function on_stop_built(map_data, stop) --TODO: fix search area local search_area = { - {pos_x + DELTA - 1, pos_y + DELTA - 1}, - {pos_x - DELTA + 1, pos_y - DELTA + 1} + {pos_x - 2, pos_y - 2}, + {pos_x + 2, pos_y + 2} } local comb2 = nil local comb1 = nil @@ -291,8 +282,8 @@ local function on_stop_broken(map_data, stop) --TODO: fix search area local search_area = { - {pos_x + DELTA - 1, pos_y + DELTA - 1}, - {pos_x - DELTA + 1, pos_y - DELTA + 1} + {pos_x - 2, pos_y - 2}, + {pos_x + 2, pos_y + 2} } local entities = stop.surface.find_entities(search_area) for _, entity in pairs(entities) do @@ -509,7 +500,7 @@ local function on_built(event) elseif entity.type == "pump" then update_station_from_pump(global, entity) elseif entity.type == "straight-rail" then - update_station_from_rail(global, entity) + update_station_from_rail(global, entity, nil) end end local function on_broken(event) @@ -530,7 +521,7 @@ local function on_broken(event) elseif entity.type == "pump" then update_station_from_pump(global, entity) elseif entity.type == "straight-rail" then - update_station_from_rail(global, entity) + update_station_from_rail(global, entity, nil) end end local function on_rename(event)