diff --git a/cybersyn/changelog.txt b/cybersyn/changelog.txt index 4156c75..9586626 100644 --- a/cybersyn/changelog.txt +++ b/cybersyn/changelog.txt @@ -5,6 +5,7 @@ Date: 2023-3-28 - Added opt-in WIP trains, inventory, and station manager gui (highly experimental, use at your own risk) Changes: - Improved the recipe derivation logic for the cybernetic combinator, in all modpacks it should now consistently be about as difficult to craft as an arthmetic combinator. Vanilla recipe is unchanged, but several overhaul mods will receive new recipes. + - The automatic allow list now consistently looks 3 tiles past the first curve rail it finds along a station for inserters or pumps. Previously it would conditionally look only 1 tile past. This should lead to more intuitive allow list behaviour for stations with trains that park slightly on curved rails. Bugfixes: - Provider override thresholds now correctly override the required train capacity as well; fix contributed by shopt - Fixed a rare crash relating to an uninitialized network mask on a new station diff --git a/cybersyn/scripts/layout.lua b/cybersyn/scripts/layout.lua index ee2ceb1..46b82b1 100644 --- a/cybersyn/scripts/layout.lua +++ b/cybersyn/scripts/layout.lua @@ -6,6 +6,10 @@ local ceil = math.ceil local min = math.min local max = math.max local bit_extract = bit32.extract +local defines_front = defines.rail_direction.front +local defines_back = defines.rail_direction.back +local defines_straight = defines.rail_connection_direction.straight +local search_type = {"straight-rail", "curved-rail"} ---@param layout_pattern (0|1|2|3)[] @@ -417,7 +421,7 @@ function unset_wagon_combs(map_data, stop) end end - +local type_filter = {"inserter", "pump", "arithmetic-combinator", "loader-1x1"} ---@param map_data MapData ---@param stop Station|Refueler ---@param is_station_or_refueler boolean @@ -432,10 +436,10 @@ function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_ent return end local rail_direction_from_stop - if stop.entity_stop.connected_rail_direction == defines.rail_direction.front then - rail_direction_from_stop = defines.rail_direction.back + if stop.entity_stop.connected_rail_direction == defines_front then + rail_direction_from_stop = defines_back else - rail_direction_from_stop = defines.rail_direction.front + rail_direction_from_stop = defines_front end local stop_direction = stop.entity_stop.direction local surface = stop.entity_stop.surface @@ -446,38 +450,67 @@ function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_ent local area_delta local is_ver if stop_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} + search_area = {{middle_x - reach, middle_y}, {middle_x + reach, middle_y + 6}} + area_delta = {0, 7} is_ver = true elseif stop_direction == defines.direction.east then - search_area = {left_top = {y = middle_y - reach, x = middle_x - 6}, right_bottom = {y = middle_y + reach, x = middle_x}} - area_delta = {x = -7, y = 0} + search_area = {{middle_x - 6, middle_y - reach}, {middle_x, middle_y + reach}} + area_delta = {-7, 0} is_ver = false elseif stop_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} + search_area = {{middle_x - reach, middle_y - 6}, {middle_x + reach, middle_y}} + area_delta = {0, -7} is_ver = true elseif stop_direction == defines.direction.west 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} + search_area = {{middle_x, middle_y - reach}, {middle_x + 6, middle_y + reach}} + area_delta = {7, 0} is_ver = false else assert(false, "cybersyn: invalid stop direction") end - local length = 2 + local length = 1 + ---@type LuaEntity? local pre_rail = stop_rail local layout_pattern = {0} - local type_filter = {"inserter", "pump", "arithmetic-combinator", "loader-1x1"} local wagon_number = 0 for i = 1, 112 do - local rail, rail_direction, rail_connection_direction = pre_rail.get_connected_rail({rail_direction = rail_direction_from_stop, rail_connection_direction = defines.rail_connection_direction.straight}) - if not rail or not rail.valid then - is_break = true - break + if pre_rail then + local rail, rail_direction, rail_connection_direction = pre_rail.get_connected_rail({rail_direction = rail_direction_from_stop, rail_connection_direction = defines_straight}) + if not rail or rail_connection_direction ~= defines_straight then + -- There is a curved rail or break in the tracks at this point + -- We are assuming it's a curved rail, maybe that's a bad assumption + -- We stop searching to expand the allow list after we see a curved rail + -- We are allowing up to 3 tiles of extra allow list usage on a curved rail + length = length + 3 + pre_rail = nil + else + pre_rail = rail + length = length + 2 + end end - pre_rail = rail - length = length + 2 - if length%7 <= 1 then + if length >= 6 or not pre_rail then + if not pre_rail then + if length <= 0 then + -- No point searching nothing + -- Once we hit a curve and process the 3 extra tiles we break here + -- This is the only breakpoint in this for loop + break + end + -- Minimize the search_area to include only the straight section of track and the 3 tiles of the curved rail + local missing_rail_length = 6 - length + if missing_rail_length > 0 then + if stop_direction == defines.direction.north then + search_area[2][2] = search_area[2][2] - missing_rail_length + elseif stop_direction == defines.direction.east then + search_area[1][1] = search_area[1][1] + missing_rail_length + elseif stop_direction == defines.direction.south then + search_area[1][2] = search_area[1][2] + missing_rail_length + else + search_area[2][1] = search_area[2][1] - missing_rail_length + end + end + end + length = length - 7 wagon_number = wagon_number + 1 local supports_cargo = false local supports_fluid = false @@ -486,7 +519,7 @@ function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_ent type = type_filter, }) for _, entity in pairs(entities) do - if entity.valid and entity ~= forbidden_entity then + if entity ~= forbidden_entity then if entity.type == "inserter" then if not supports_cargo then local pos = entity.pickup_position @@ -566,10 +599,6 @@ function reset_stop_layout(map_data, stop, is_station_or_refueler, forbidden_ent end search_area = area.move(search_area, area_delta) end - if rail_connection_direction ~= defines.rail_connection_direction.straight then - is_break = true - break - end end stop.layout_pattern = layout_pattern if is_station_or_refueler then @@ -593,47 +622,55 @@ function update_stop_if_auto(map_data, stop, is_station_or_refueler, forbidden_e end end +---@param map_data MapData +---@param entity LuaEntity +---@param forbidden_entity LuaEntity? +---@param force boolean? +local function resolve_update_stop_from_rail(map_data, entity, forbidden_entity, force) + local id = entity.unit_number--[[@as uint]] + local is_station = true + ---@type Station|Refueler + local stop = map_data.stations[id] + if not stop then + stop = map_data.refuelers[id] + is_station = false + end + if stop and stop.entity_stop.valid then + if force then + reset_stop_layout(map_data, stop, is_station, forbidden_entity) + elseif not stop.allows_all_trains then + reset_stop_layout(map_data, stop, is_station, forbidden_entity) + end + end +end ---@param map_data MapData ---@param rail LuaEntity ---@param forbidden_entity LuaEntity? ---@param force boolean? function update_stop_from_rail(map_data, rail, forbidden_entity, force) --NOTE: is this a correct way to figure out the direction? + ---@type LuaEntity? + local rail_front = rail + ---@type LuaEntity? + local rail_back = rail ---@type defines.rail_direction - local rail_direction = defines.rail_direction.back - local entity = rail.get_rail_segment_entity(rail_direction, false) - if not entity then - rail_direction = defines.rail_direction.front - entity = rail.get_rail_segment_entity(rail_direction, false) - end for i = 1, 112 do - if not entity or not entity.valid then - return - end - if entity.name == "train-stop" then - local id = entity.unit_number--[[@as uint]] - local is_station = true - ---@type Station|Refueler - local stop = map_data.stations[id] - if not stop then - stop = map_data.refuelers[id] - is_station = false + if rail_back then + local entity = rail_back.get_rail_segment_entity(defines_back, false) + if entity and entity.name == "train-stop" then + resolve_update_stop_from_rail(map_data, entity, forbidden_entity, force) + return end - if stop and stop.entity_stop.valid then - if force then - reset_stop_layout(map_data, stop, is_station, forbidden_entity) - elseif not stop.allows_all_trains then - reset_stop_layout(map_data, stop, is_station, forbidden_entity) - end + rail_back = rail_back.get_connected_rail({rail_direction = defines_back, rail_connection_direction = defines_straight}) + end + if rail_front then + local entity = rail_front.get_rail_segment_entity(defines_front, false) + if entity and entity.name == "train-stop" then + resolve_update_stop_from_rail(map_data, entity, forbidden_entity, force) + return end - return + rail_front = rail_front.get_connected_rail({rail_direction = defines_front, rail_connection_direction = defines_straight}) end - - rail = rail.get_connected_rail({rail_direction = rail_direction, rail_connection_direction = defines.rail_connection_direction.straight})--[[@as LuaEntity]] - if not rail or not rail.valid then - return - end - entity = rail.get_rail_segment_entity(rail_direction, false) end end @@ -650,20 +687,46 @@ end ---@param forbidden_entity LuaEntity? function update_stop_from_inserter(map_data, inserter, forbidden_entity) local surface = inserter.surface + local pos0 = inserter.position + local pos1 = inserter.pickup_position + local pos2 = inserter.drop_position + local has_found = false - --NOTE: we don't use find_entity solely for miniloader compat local rails = surface.find_entities_filtered({ - type = "straight-rail", - position = inserter.pickup_position, - radius = 1, + type = search_type, + position = pos1, + }) + if rails[1] then + update_stop_from_rail(map_data, rails[1], forbidden_entity) + has_found = true + end + rails = surface.find_entities_filtered({ + type = search_type, + position = pos2, + }) + if rails[1] then + update_stop_from_rail(map_data, rails[1], forbidden_entity) + has_found = true + end + if has_found then + return + end + -- We need to check secondary positions because of weird modded inserters. + -- Mostly because of miniloaders not aligning with the hitbox of a rail by default. + pos1.x = pos1.x + 0.2*(pos1.x - pos0.x) + pos1.y = pos1.y + 0.2*(pos1.y - pos0.y) + pos2.x = pos2.x + 0.2*(pos2.x - pos0.x) + pos2.y = pos2.y + 0.2*(pos2.y - pos0.y) + rails = surface.find_entities_filtered({ + type = search_type, + position = pos1, }) if rails[1] then update_stop_from_rail(map_data, rails[1], forbidden_entity) end rails = surface.find_entities_filtered({ - type = "straight-rail", - position = inserter.drop_position, - radius = 1, + type = search_type, + position = pos2, }) if rails[1] then update_stop_from_rail(map_data, rails[1], forbidden_entity) @@ -681,86 +744,29 @@ function update_stop_from_loader(map_data, loader, forbidden_entity) if loader_type == "input" then --loading train if direction == defines.direction.east then position.x = position.x + 1 -- input and facing east -> move on X axis 1 to the right - local rails = surface.find_entities_filtered({ - type = "straight-rail", - position = position, - radius = 1, - }) - if rails[1] then - update_stop_from_rail(map_data, rails[1], forbidden_entity) - end elseif direction == defines.direction.south then position.y = position.y + 1 -- input and facing south -> move on Y axis down 1 unit - local rails = surface.find_entities_filtered({ - type = "straight-rail", - position = position, - radius = 1, - }) - if rails[1] then - update_stop_from_rail(map_data, rails[1], forbidden_entity) - end elseif direction == defines.direction.west then position.x = position.x - 1 -- input and facing west -> move on X axis 1 to the left - local rails = surface.find_entities_filtered({ - type = "straight-rail", - position = position, - radius = 1, - }) - if rails[1] then - update_stop_from_rail(map_data, rails[1], forbidden_entity) - end elseif direction == defines.direction.north then position.y = position.y - 1 -- input and facing south -> move on Y axis up 1 unit - local rails = surface.find_entities_filtered({ - type = "straight-rail", - position = position, - radius = 1, - }) - if rails[1] then - update_stop_from_rail(map_data, rails[1], forbidden_entity) - end end elseif loader_type == "output" then --unloading train if direction == defines.direction.east then position.x = position.x - 1 -- output and facing east -> move on X axis 1 to the left - local rails = surface.find_entities_filtered({ - type = "straight-rail", - position = position, - radius = 1, - }) - if rails[1] then - update_stop_from_rail(map_data, rails[1], forbidden_entity) - end elseif direction == defines.direction.south then position.y = position.y - 1 -- output and facing south -> move on Y axis up 1 unit - local rails = surface.find_entities_filtered({ - type = "straight-rail", - position = position, - radius = 1, - }) - if rails[1] then - update_stop_from_rail(map_data, rails[1], forbidden_entity) - end elseif direction == defines.direction.west then position.x = position.x + 1 -- output and facing west -> move on X axis 1 to the right - local rails = surface.find_entities_filtered({ - type = "straight-rail", - position = position, - radius = 1, - }) - if rails[1] then - update_stop_from_rail(map_data, rails[1], forbidden_entity) - end elseif direction == defines.direction.north then position.y = position.y + 1 -- output and facing south -> move on Y axis down 1 unit - local rails = surface.find_entities_filtered({ - type = "straight-rail", - position = position, - radius = 1, - }) - if rails[1] then - update_stop_from_rail(map_data, rails[1], forbidden_entity) - end end end -end \ No newline at end of file + local rails = surface.find_entities_filtered({ + type = search_type, + position = position, + }) + if rails[1] then + update_stop_from_rail(map_data, rails[1], forbidden_entity) + end +end diff --git a/cybersyn/scripts/main.lua b/cybersyn/scripts/main.lua index f1cc163..e276892 100644 --- a/cybersyn/scripts/main.lua +++ b/cybersyn/scripts/main.lua @@ -624,7 +624,7 @@ local function on_built(event) update_stop_from_loader(global, entity) elseif entity.type == "pump" then update_stop_from_pump(global, entity) - elseif entity.type == "straight-rail" then + elseif entity.type == "straight-rail" or entity.type == "curved-rail" then update_stop_from_rail(global, entity) end end @@ -642,7 +642,7 @@ local function on_broken(event) update_stop_from_loader(global, entity, entity) elseif entity.type == "pump" then update_stop_from_pump(global, entity, entity) - elseif entity.type == "straight-rail" then + elseif entity.type == "straight-rail" or entity.type == "curved-rail" then update_stop_from_rail(global, entity, nil) elseif entity.train then local train_id = entity.train.id @@ -876,6 +876,7 @@ local filter_built = { {filter = "type", type = "inserter"}, {filter = "type", type = "pump"}, {filter = "type", type = "straight-rail"}, + {filter = "type", type = "curved-rail"}, {filter = "type", type = "loader-1x1"}, } local filter_broken = { @@ -884,6 +885,7 @@ local filter_broken = { {filter = "type", type = "inserter"}, {filter = "type", type = "pump"}, {filter = "type", type = "straight-rail"}, + {filter = "type", type = "curved-rail"}, {filter = "type", type = "loader-1x1"}, {filter = "rolling-stock"}, } diff --git a/cybersyn/scripts/migrations.lua b/cybersyn/scripts/migrations.lua index e6292de..5498059 100644 --- a/cybersyn/scripts/migrations.lua +++ b/cybersyn/scripts/migrations.lua @@ -321,13 +321,14 @@ local migrations_table = { ---@param data ConfigurationChangedData function on_config_changed(data) - for i, v in pairs(global.manager.players) do - manager_gui.reset_player(i, v) - end global.tick_state = STATE_INIT global.tick_data = {} flib_migration.on_config_changed(data, migrations_table) + for i, v in pairs(global.manager.players) do + manager_gui.reset_player(i, v) + end + IS_SE_PRESENT = remote.interfaces["space-exploration"] ~= nil if IS_SE_PRESENT and not global.se_tele_old_id then global.se_tele_old_id = {}