344 lines
14 KiB
Lua
344 lines
14 KiB
Lua
local const = require("scripts/constants")
|
|
local utils = require("scripts/utils")
|
|
local draw = require("scripts/rendering")
|
|
local get_belt_type = utils.get_belt_type
|
|
local empty_check = utils.empty_check
|
|
local check_entity = utils.check_entity
|
|
local lane_cycle = const.lane_cycle
|
|
local side_cycle = const.side_cycle
|
|
local straight = const.straight
|
|
local underground = const.underground
|
|
local dash = const.dash
|
|
local splitter = const.splitter
|
|
local loader = const.loader
|
|
local loader_1x1 = const.loader_1x1
|
|
local linked_belt = const.linked_belt
|
|
|
|
local function is_clockwise(entity, output)
|
|
return (output.direction - entity.direction) % 8 == 2
|
|
end
|
|
|
|
local function get_splitter_sides(entity, belt)
|
|
local direction = entity.direction
|
|
local position = entity.position
|
|
local belt_position = belt.position
|
|
local axis = direction % 4 == 0 and "x" or "y"
|
|
if position[axis] == belt_position[axis] then return side_cycle.both end
|
|
return (position[axis] > belt_position[axis]) ~= (direction >= 4) and side_cycle.left or side_cycle.right
|
|
end
|
|
|
|
local function get_filter_side(data, entity)
|
|
if not data.filter then return end
|
|
local splitter_filter = entity.splitter_filter
|
|
if not splitter_filter then return end
|
|
local output_priority = entity.splitter_output_priority
|
|
if output_priority == "none" then return end
|
|
return (output_priority == "left") == (data.filter == splitter_filter.name) and "left" or "right"
|
|
end
|
|
|
|
local function get_input_paths(check, lanes)
|
|
for lane, paths in pairs(check) do
|
|
if paths[1] then
|
|
lanes[lane] = true
|
|
end
|
|
end
|
|
end
|
|
|
|
local function get_input_lanes(data, entity, input)
|
|
local check = data.checked[input.unit_number]
|
|
local lanes = {}
|
|
if get_belt_type(input) == "splitter" then
|
|
for _, side_check in pairs(check) do
|
|
get_input_paths(side_check, lanes)
|
|
end
|
|
else
|
|
get_input_paths(check, lanes)
|
|
end
|
|
return lanes
|
|
end
|
|
|
|
local default_output = {"output", "output"}
|
|
local function get_output_lanes(data, entity, lanes, output)
|
|
if not output or entity.direction == output.direction then return lanes, default_output end
|
|
if not data.ghost and output.type == "entity-ghost" then return lanes, default_output end
|
|
local clockwise = is_clockwise(entity, output)
|
|
local next_lanes = {}
|
|
local offsets = {}
|
|
if get_belt_type(output) == "underground-belt" then
|
|
for lane in pairs(lanes) do
|
|
local type = output.belt_to_ground_type == "input"
|
|
if (clockwise == type) == (lane == 1) then
|
|
next_lanes[clockwise and 2 or 1] = true
|
|
offsets[lane] = "sideload"
|
|
else
|
|
offsets[lane] = "output"
|
|
end
|
|
end
|
|
else
|
|
if #output.belt_neighbours.inputs ~= 1 then
|
|
for lane in pairs(lanes) do
|
|
next_lanes[clockwise and 2 or 1] = true
|
|
offsets[lane] = "sideload"
|
|
end
|
|
else
|
|
return lanes, default_output
|
|
end
|
|
end
|
|
return next_lanes, offsets
|
|
end
|
|
|
|
local function get_prev_lanes(entity, lanes, input)
|
|
if entity.direction == input.direction then return lanes end
|
|
local clockwise = is_clockwise(input, entity)
|
|
for lane in pairs(lanes) do
|
|
if clockwise == (lane == 2) then
|
|
if get_belt_type(entity) == "underground-belt" then
|
|
local type = entity.belt_to_ground_type == "input"
|
|
return lane_cycle[clockwise == type and 2 or 3]
|
|
else
|
|
return lane_cycle[1]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function add_to_queue(data, entity, lanes, path, old_entity)
|
|
if not entity then return end
|
|
local belt_type = entity.type
|
|
if belt_type == "entity-ghost" then
|
|
if data.ghost then
|
|
belt_type = entity.ghost_type
|
|
else return end
|
|
end
|
|
local is_splitter = belt_type == "splitter"
|
|
local sides
|
|
if is_splitter then
|
|
local const_sides = get_splitter_sides(entity, old_entity)
|
|
sides = {}
|
|
for side in pairs(const_sides) do
|
|
sides[side] = true
|
|
end
|
|
if path == 2 then
|
|
local filter_side = get_filter_side(data, entity)
|
|
if filter_side then
|
|
for side in pairs(const_sides) do
|
|
if filter_side ~= side then
|
|
sides[side] = nil
|
|
end
|
|
end
|
|
if not next(sides) then return end
|
|
end
|
|
end
|
|
end
|
|
local unit_number = entity.unit_number
|
|
local checked = data.checked
|
|
local new_lanes = {}
|
|
for lane in pairs(lanes) do
|
|
local check
|
|
if checked[unit_number] then
|
|
if is_splitter then
|
|
for side in pairs(sides) do
|
|
check = checked[unit_number][side][lane][path]
|
|
end
|
|
else
|
|
check = checked[unit_number][lane][path]
|
|
end
|
|
else
|
|
checked[unit_number] = empty_check(belt_type)
|
|
end
|
|
if not check then
|
|
new_lanes[lane] = true
|
|
check_entity(data, unit_number, lane, path, sides)
|
|
end
|
|
end
|
|
if next(new_lanes) then
|
|
local next_entities = data.next_entities
|
|
local next_len = data.next_len + 1
|
|
data.next_len = next_len
|
|
next_entities[next_len] = {entity = entity, lanes = new_lanes, path = path}
|
|
end
|
|
end
|
|
|
|
local highlight_entity = {}
|
|
|
|
highlight_entity["transport-belt"] = function(data, entity, lanes, path)
|
|
local direction = entity.direction
|
|
local belt_neighbours = entity.belt_neighbours
|
|
local inputs = belt_neighbours.inputs
|
|
local output = belt_neighbours.outputs[1]
|
|
local is_curved = (#inputs == 1) and (direction ~= inputs[1].direction)
|
|
local next_lanes, lane_offsets = get_output_lanes(data, entity, lanes, output)
|
|
for lane in pairs(lanes) do
|
|
local offsets = straight[lane][direction]
|
|
local lane_offset = lane_offsets[lane]
|
|
if not is_curved then
|
|
draw.line(data, entity, offsets.input, offsets[lane_offset])
|
|
else
|
|
draw.arc(data, entity, lane, is_clockwise(inputs[1], entity))
|
|
if lane_offset == "sideload" then
|
|
draw.line(data, entity, offsets.output, offsets[lane_offset])
|
|
end
|
|
end
|
|
end
|
|
if path == 1 then
|
|
add_to_queue(data, output, next_lanes, 1, entity)
|
|
else
|
|
for _, input in pairs(inputs) do
|
|
local prev_lanes = is_curved and lanes or get_prev_lanes(entity, lanes, input)
|
|
if prev_lanes then add_to_queue(data, input, prev_lanes, 2, entity) end
|
|
end
|
|
end
|
|
end
|
|
|
|
highlight_entity["underground-belt"] = function(data, entity, lanes, path)
|
|
local direction = entity.direction
|
|
local belt_neighbours = entity.belt_neighbours
|
|
local output = belt_neighbours.outputs[1]
|
|
local type = entity.belt_to_ground_type
|
|
local is_input = type == "input"
|
|
local next_lanes, lane_offsets = get_output_lanes(data, entity, lanes, output)
|
|
for lane in pairs(lanes) do
|
|
local lane_offset = is_input and "input" or lane_offsets[lane]
|
|
draw.line(data, entity, underground[lane][direction][type], straight[lane][direction][lane_offset])
|
|
end
|
|
local forward = path == 1
|
|
if forward then
|
|
add_to_queue(data, output, next_lanes, path, entity)
|
|
else
|
|
for _, input in pairs(belt_neighbours.inputs) do
|
|
local prev_lanes = get_prev_lanes(entity, lanes, input)
|
|
if prev_lanes then add_to_queue(data, input, prev_lanes, path, entity) end
|
|
end
|
|
end
|
|
local neighbour = entity.neighbours
|
|
if forward == is_input and neighbour then
|
|
local check = data.checked[entity.unit_number]
|
|
local neighbour_check = data.checked[neighbour.unit_number]
|
|
for lane in pairs(lanes) do
|
|
if not (neighbour_check and neighbour_check[lane].dash) then
|
|
local offsets = dash[lane][direction]
|
|
draw.dash(data, is_input and entity or neighbour, offsets.input, offsets.output)
|
|
end
|
|
check[lane].dash = true
|
|
end
|
|
add_to_queue(data, neighbour, lanes, path, entity)
|
|
end
|
|
end
|
|
|
|
highlight_entity["splitter"] = function(data, entity, lanes, path)
|
|
local direction = entity.direction
|
|
local belt_neighbours = entity.belt_neighbours
|
|
local forward = path == 1
|
|
local belts = {}
|
|
for _, belt in pairs(belt_neighbours[forward and "outputs" or "inputs"]) do
|
|
for side in pairs(get_splitter_sides(entity, belt)) do
|
|
if forward or get_belt_type(belt) ~= "splitter" or get_filter_side(data, belt) ~= side then
|
|
belts[side] = belt
|
|
end
|
|
end
|
|
end
|
|
local queued
|
|
local filter_side = get_filter_side(data, entity)
|
|
for side in pairs(forward and side_cycle[filter_side] or side_cycle.both) do
|
|
local next_lanes, lane_offsets = get_output_lanes(data, entity, lanes, belts[side])
|
|
for lane in pairs(lanes) do
|
|
local offsets = splitter[lane][direction]
|
|
local side_offsets = offsets[side]
|
|
local lane_offset = forward and lane_offsets[lane] or "input"
|
|
draw.line(data, entity, side_offsets.middle, side_offsets[lane_offset])
|
|
draw.line(data, entity, offsets.left.line, offsets.right.line)
|
|
end
|
|
if queued ~= belts[side] then
|
|
add_to_queue(data, belts[side], next_lanes, path, entity)
|
|
queued = belts[side]
|
|
end
|
|
end
|
|
for _, belt in pairs(belt_neighbours[forward and "inputs" or "outputs"]) do
|
|
local belt_check = data.checked[belt.unit_number]
|
|
if belt_check then
|
|
local checked_lanes = forward and get_input_lanes(data, entity, belt) or lanes
|
|
local _, lane_offsets = get_output_lanes(data, entity, lanes, belt)
|
|
local sides = not forward and side_cycle[filter_side] or get_splitter_sides(entity, belt)
|
|
for side in pairs(sides) do
|
|
for lane in pairs(checked_lanes) do
|
|
local belt_path
|
|
if get_belt_type(belt) == "splitter" then
|
|
belt_path = belt_check.left[lane][path] or belt_check.right[lane][path]
|
|
else
|
|
belt_path = belt_check[lane][path]
|
|
end
|
|
if belt_path then
|
|
local side_offsets = splitter[lane][direction][side]
|
|
local lane_offset = forward and "input" or lane_offsets[lane]
|
|
draw.line(data, entity, side_offsets.middle, side_offsets[lane_offset])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
highlight_entity["linked-belt"] = function(data, entity, lanes, path)
|
|
local direction = entity.direction
|
|
local belt_neighbours = entity.belt_neighbours
|
|
local output = belt_neighbours.outputs[1]
|
|
local linked_belt_neighbour = entity.linked_belt_neighbour
|
|
local is_input = entity.linked_belt_type == "input"
|
|
local forward = path == 1
|
|
local next_lanes, lane_offsets = get_output_lanes(data, entity, lanes, output)
|
|
for lane in pairs(lanes) do
|
|
local offsets = linked_belt[lane][direction]
|
|
local middle = offsets.middle
|
|
local lane_offset = is_input and "input" or lane_offsets[lane]
|
|
draw.line(data, entity, middle, offsets[lane_offset])
|
|
draw.circle(data, entity, middle)
|
|
end
|
|
add_to_queue(data, forward and output or belt_neighbours.inputs[1], next_lanes, path, entity)
|
|
if is_input == forward then
|
|
add_to_queue(data, linked_belt_neighbour, lanes, path, entity)
|
|
end
|
|
end
|
|
|
|
---@return fun(data: table, entity: LuaEntity, lanes: table, path: 1|2)
|
|
local function highlight_loader(loader_const)
|
|
return function(data, entity, lanes, path)
|
|
local direction = entity.direction
|
|
local belt_neighbours = entity.belt_neighbours
|
|
local output = belt_neighbours.outputs[1]
|
|
local loader_type = entity.loader_type
|
|
local next_lanes, lane_offsets = get_output_lanes(data, entity, lanes, output)
|
|
for lane in pairs(lanes) do
|
|
local offsets = loader_const[lane][direction]
|
|
local lane_offset = lane_offsets[lane]
|
|
draw.line(data, entity, offsets.input, offsets[lane_offset])
|
|
draw.rectangle(data, entity, loader_const.rectangle[lane][direction][loader_type])
|
|
end
|
|
local forward = path == 1
|
|
local new_entity = forward and output or belt_neighbours.inputs[1]
|
|
add_to_queue(data, new_entity, next_lanes, path, entity)
|
|
if entity.type == "entity-ghost" then return end -- TODO: ACTUALLY FIX
|
|
if data.container_passthrough and forward == (loader_type == "input") then
|
|
local container = entity.loader_container
|
|
if container and (container.type == "container" or container.type == "logistic-container" or container.type == "infinity-container") then
|
|
local box = container.prototype.collision_box
|
|
local lt, rb = box.left_top, box.right_bottom
|
|
local pos = container.position
|
|
local loaders = container.surface.find_entities_filtered{
|
|
area = {{pos.x + lt.x - 1, pos.y + lt.y - 1}, {pos.x + rb.x + 1, pos.y + rb.y + 1}},
|
|
type = {"loader", "loader-1x1"},
|
|
}
|
|
for _, loader in pairs(loaders) do
|
|
local loader_container = loader.loader_container
|
|
if loader ~= entity and loader_container and loader_container == container and loader_type ~= loader.loader_type then
|
|
add_to_queue(data, loader, lane_cycle[1], path, entity)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
highlight_entity["loader"] = highlight_loader(loader)
|
|
highlight_entity["loader-1x1"] = highlight_loader(loader_1x1)
|
|
|
|
return highlight_entity |