781 lines
31 KiB
Lua

math2d = require "math2d"
local Search = {}
local default_surface_data = { consumers = {}, producers = {}, storage = {}, logistics = {}, modules = {}, requesters = {}, ground_items = {}, entities = {}, signals = {}, map_tags = {} }
local function extend(t1, t2)
local t1_len = #t1
local t2_len = #t2
for i=1, t2_len do
t1[t1_len + i] = t2[i]
end
end
local function signal_eq(sig1, sig2)
return sig1 and sig2 and sig1.type == sig2.type and sig1.name == sig2.name
end
-- Mod-specific overrides for "Entity" search
local mod_placeholder_entities = {
['ff-ferrous-nodule'] = {'ff-seamount'}, -- Freight Forwarding
['ff-cupric-nodule'] = {'ff-seamount'},
['ff-cobalt-crust'] = {'ff-seamount'},
['ff-hot-titansteel-plate'] = -- Freight Forwarding
{'ff-lava-pool', 'ff-lava-pool-small'},
['se-core-fragment-omni'] = {'se-core-fragment-omni', 'se-core-fragment-omni-sealed'}, -- space-exploration
['se-core-fragment-iron-ore'] = {'se-core-fragment-iron-ore', 'se-core-fragment-iron-ore-sealed'},
['se-core-fragment-copper-ore'] = {'se-core-fragment-copper-ore', 'se-core-fragment-copper-ore-sealed'},
['se-core-fragment-coal'] = {'se-core-fragment-coal', 'se-core-fragment-coal-sealed'},
['se-core-fragment-stone'] = {'se-core-fragment-stone', 'se-core-fragment-stone-sealed'},
['se-core-fragment-uranium-ore'] = {'se-core-fragment-uranium-ore', 'se-core-fragment-uranium-ore-sealed'},
['se-core-fragment-crude-oil'] = {'se-core-fragment-crude-oil', 'se-core-fragment-crude-oil-sealed'},
['se-core-fragment-se-beryllium-ore'] = {'se-core-fragment-beryllium-ore', 'se-core-fragment-beryllium-ore-sealed'},
['se-core-fragment-se-cryonite'] = {'se-core-fragment-se-cryonite', 'se-core-fragment-se-cryonite-sealed'},
['se-core-fragment-se-holmium-ore'] = {'se-core-fragment-se-holmium-ore', 'se-core-fragment-se-holmium-ore-sealed'},
['se-core-fragment-se-iridium-ore'] = {'se-core-fragment-se-iridium-ore', 'se-core-fragment-se-iridium-ore-sealed'},
['se-core-fragment-se-vulcanite'] = {'se-core-fragment-se-vulcanite', 'se-core-fragment-se-vulcanite-sealed'},
['se-core-fragment-se-vitemelange'] = {'se-core-fragment-se-vitemelange', 'se-core-fragment-se-vitemelange-sealed'},
}
local list_to_map = util.list_to_map
local ingredient_entities = list_to_map{ "assembling-machine", "furnace", "mining-drill", "boiler", "burner-generator", "generator", "reactor", "inserter", "lab", "car", "spider-vehicle", "locomotive" }
local item_ammo_ingredient_entities = list_to_map{ "artillery-turret", "artillery-wagon", "ammo-turret" } -- spider-vehicle, character
local fluid_ammo_ingredient_entities = list_to_map { "fluid-turret" }
local product_entities = list_to_map{ "assembling-machine", "furnace", "offshore-pump", "mining-drill" } -- TODO add rocket-silo
local item_storage_entities = list_to_map{ "container", "logistic-container", "linked-container", "roboport", "character", "car", "artillery-wagon", "cargo-wagon", "spider-vehicle" }
local neutral_item_storage_entities = list_to_map{ "character-corpse" } -- force = "neutral"
local fluid_storage_entities = list_to_map{ "storage-tank", "fluid-wagon" }
local modules_entities = list_to_map{ "assembling-machine", "furnace", "rocket-silo", "mining-drill", "lab", "beacon" }
local request_entities = list_to_map{ "logistic-container", "character", "spider-vehicle", "item-request-proxy" }
local item_logistic_entities = list_to_map{ "transport-belt", "splitter", "underground-belt", "loader", "loader-1x1", "inserter", "logistic-robot", "construction-robot" }
local fluid_logistic_entities = list_to_map{ "pipe", "pipe-to-ground", "pump" }
local ground_entities = list_to_map{ "item-entity" } -- force = "neutral"
local signal_entities = list_to_map{ "roboport", "train-stop", "arithmetic-combinator", "decider-combinator", "constant-combinator", "accumulator", "rail-signal", "rail-chain-signal", "wall", "container", "logistic-container", "inserter", "storage-tank" }
local function add_entity_type(type_list, to_add_list)
for name, _ in pairs(to_add_list) do
type_list[name] = true
end
end
local function map_to_list(map)
local i = 1
local list = {}
for name, _ in pairs(map) do
list[i] = name
i = i + 1
end
return list
end
local function generate_distance_data(surface_data, player_position)
local distance = math2d.position.distance
for _, entity_groups in pairs(surface_data) do
for _, groups in pairs(entity_groups) do
for _, group in pairs(groups) do
group.distance = distance(group.avg_position, player_position)
end
table.sort(groups, function (k1, k2) return k1.distance < k2.distance end)
end
end
end
local function to_chunk_position(map_position)
return { math.floor(map_position.x / 32), math.floor(map_position.y / 32) }
end
local function remove_uncharted_groups(surface_data, surface, force)
for _, entity_groups in pairs(surface_data) do
for _, groups in pairs(entity_groups) do
for i, group in pairs(groups) do
if not force.is_chunk_charted(surface, to_chunk_position(group.avg_position)) then
table.remove(groups, i)
end
end
end
end
end
local function is_wire_connected(entity, entity_type)
if entity_type == "arithmetic-combinator" or entity_type == "decider-combinator" then
return entity.get_circuit_network(defines.wire_type.red, defines.circuit_connector_id.combinator_output) or entity.get_circuit_network(defines.wire_type.green, defines.circuit_connector_id.combinator_output)
else
return entity.get_circuit_network(defines.wire_type.red) or entity.get_circuit_network(defines.wire_type.green)
end
end
function Search.process_found_entities(entities, state, surface_data, target_item)
-- Not used for Entity and Tag search modes
local target_name = target_item.name
local target_type = target_item.type
local target_is_item = target_type == "item"
local target_is_fluid = target_type == "fluid"
local target_is_virtual = target_type == "virtual"
for _, entity in pairs(entities) do
local entity_type = entity.type
-- Signals
if state.signals then
if signal_entities[entity_type] then
local control_behavior = entity.get_control_behavior()
if control_behavior and is_wire_connected(entity, entity_type) then
-- Does everything except mining drill, as API doesn't support that
if entity_type == "constant-combinator" then
-- If prototype's `item_slot_count = 0` then .parameters will be nil
for _, parameter in pairs(control_behavior.parameters or {}) do
if signal_eq(parameter.signal, target_item) then
SearchResults.add_entity_signal(entity, surface_data.signals, parameter.count)
end
end
elseif entity_type == "arithmetic-combinator" or entity_type == "decider-combinator" then
local signal_count = control_behavior.get_signal_last_tick(target_item)
if signal_count ~= nil then
SearchResults.add_entity_signal(entity, surface_data.signals, signal_count)
end
elseif entity_type == "roboport" then
for _, signal in pairs({ control_behavior.available_logistic_output_signal, control_behavior.total_logistic_output_signal, control_behavior.available_construction_output_signal, control_behavior.total_construction_output_signal }) do
if signal_eq(signal, target_item) then
SearchResults.add_entity(entity, surface_data.signals)
break
end
end
if target_is_item and control_behavior.read_logistics then
local logistic_network = entity.logistic_network
if logistic_network then
local signal_count = logistic_network.get_item_count(target_name)
if signal_count > 0 then
SearchResults.add_entity_signal(entity, surface_data.signals, signal_count)
end
end
end
elseif entity_type == "train-stop" then
if signal_eq(control_behavior.stopped_train_signal, target_item) or signal_eq(control_behavior.trains_count_signal, target_item) then
SearchResults.add_entity(entity, surface_data.signals)
elseif control_behavior.read_from_train then
local train = entity.get_stopped_train()
if train then
if target_is_item then
local signal_count = train.get_item_count(target_name)
if signal_count > 0 then
SearchResults.add_entity_signal(entity, surface_data.signals, signal_count)
end
elseif target_is_fluid then
local signal_count = train.get_fluid_count(target_name)
if signal_count > 0 then
SearchResults.add_entity_signal(entity, surface_data.signals, signal_count)
end
end
end
end
elseif entity_type == "accumulator" or entity_type == "wall" then
if signal_eq(control_behavior.output_signal, target_item) then
SearchResults.add_entity(entity, surface_data.signals)
end
elseif entity_type == "rail-signal" then
for _, signal in pairs({ control_behavior.red_signal, control_behavior.orange_signal, control_behavior.green_signal }) do
if signal_eq(signal, target_item) then
SearchResults.add_entity(entity, surface_data.signals)
break
end
end
elseif entity_type == "rail-chain-signal" then
for _, signal in pairs({ control_behavior.red_signal, control_behavior.orange_signal, control_behavior.green_signal, control_behavior.blue_signal }) do
if signal_eq(signal, target_item) then
SearchResults.add_entity(entity, surface_data.signals)
break
end
end
elseif entity_type == "container" and target_is_item then
local signal_count = entity.get_item_count(target_name)
if signal_count > 0 then
SearchResults.add_entity_signal(entity, surface_data.signals, signal_count)
end
elseif entity_type == "logistic-container" and target_is_item then
if control_behavior.circuit_mode_of_operation == defines.control_behavior.logistic_container.circuit_mode_of_operation.send_contents then
local signal_count = entity.get_item_count(target_name)
if signal_count > 0 then
SearchResults.add_entity_signal(entity, surface_data.signals, signal_count)
end
end
elseif entity_type == "inserter" and target_is_item then
-- Doesn't check inserter if in pulse mode
if control_behavior.circuit_read_hand_contents and control_behavior.circuit_hand_read_mode == defines.control_behavior.inserter.hand_read_mode.hold then
local held_stack = entity.held_stack
if held_stack and held_stack.valid_for_read and held_stack.name == target_name then
SearchResults.add_entity_signal(entity, surface_data.signals, held_stack.count)
end
end
elseif entity_type == "storage-tank" and target_is_fluid then
local signal_count = entity.get_fluid_count(target_name)
if signal_count > 0 then
SearchResults.add_entity_signal(entity, surface_data.signals, signal_count)
end
end
end
end
end
if target_is_virtual then
-- We've done all processing that there is to be done on virtual signals
goto continue
end
-- Ingredients / Consumers
if state.consumers then
local recipe
if entity_type == "assembling-machine" then
recipe = entity.get_recipe()
elseif entity_type == "furnace" then
recipe = entity.get_recipe()
if recipe == nil then
-- Even if the furnace has stopped smelting, this records the last item it was smelting
recipe = entity.previous_recipe
end
end
if recipe then
local ingredients = recipe.ingredients
for _, ingredient in pairs(ingredients) do
local name = ingredient.name
if name == target_name then
SearchResults.add_entity_product(entity, surface_data.consumers, recipe)
end
end
end
if target_is_item and entity_type == "lab" then
local item_count = entity.get_item_count(target_name)
if item_count > 0 then
SearchResults.add_entity(entity, surface_data.consumers)
end
end
if target_is_fluid and entity_type == "generator" then
local fluid_count = entity.get_fluid_count(target_name)
if fluid_count > 0 then
SearchResults.add_entity(entity, surface_data.consumers)
end
end
local burner = entity.burner
if burner then
local currently_burning = burner.currently_burning
if currently_burning then
if currently_burning.name == target_name then
SearchResults.add_entity(entity, surface_data.consumers)
end
end
end
-- Consuming ammo
if target_is_item and (entity_type == "artillery-turret" or entity_type == "artillery-wagon" or entity_type == "ammo-turret") then
local item_count = entity.get_item_count(target_name)
if item_count > 0 then
SearchResults.add_entity_storage(entity, surface_data.consumers, item_count)
end
elseif target_is_fluid and entity_type == "fluid-turret" then
local fluid_count = entity.get_fluid_count(target_name)
if fluid_count > 0 then
SearchResults.add_entity_storage_fluid(entity, surface_data.consumers, fluid_count)
end
end
end
-- Producers
if state.producers then
local recipe
if entity_type == "assembling-machine" then
recipe = entity.get_recipe()
elseif entity_type == "furnace" then
recipe = entity.get_recipe()
if recipe == nil then
-- Even if the furnace has stopped smelting, this records the last item it was smelting
recipe = entity.previous_recipe
end
elseif entity_type == "mining-drill" then
local mining_target = entity.mining_target
if mining_target then
local mineable_properties = mining_target.prototype.mineable_properties
for _, product in pairs(mineable_properties.products or {}) do
if product.name == target_name then
SearchResults.add_entity(entity, surface_data.producers)
end
end
end
elseif target_is_fluid and entity_type == "offshore-pump" then
if entity.get_fluid_count(target_name) > 0 then
SearchResults.add_entity(entity, surface_data.producers)
end
end
if recipe then
local products = recipe.products
for _, product in pairs(products) do
local name = product.name
if name == target_name then
SearchResults.add_entity_product(entity, surface_data.producers, recipe)
end
end
end
end
-- Storage
if state.storage then
if target_is_fluid and (entity_type == "storage-tank" or entity_type == "fluid-wagon") then
local fluid_count = entity.get_fluid_count(target_name)
if fluid_count > 0 then
SearchResults.add_entity_storage_fluid(entity, surface_data.storage, fluid_count)
end
elseif target_is_item and (entity_type == "character-corpse" or item_storage_entities[entity_type]) then
-- Entity is an inventory entity
local item_count = entity.get_item_count(target_name)
if item_count > 0 then
SearchResults.add_entity_storage(entity, surface_data.storage, item_count)
end
end
end
-- Modules
if state.modules then
if target_is_item and modules_entities[entity_type] then
local inventory
if entity_type == "beacon" then
inventory = entity.get_inventory(defines.inventory.beacon_modules)
elseif entity_type == "lab" then
inventory = entity.get_inventory(defines.inventory.lab_modules)
elseif entity_type == "mining-drill" then
inventory = entity.get_inventory(defines.inventory.mining_drill_modules)
elseif entity_type == "assembling-machine" or entity_type == "furnace" or entity_type == "rocket-silo" then
inventory = entity.get_inventory(defines.inventory.assembling_machine_modules)
end
if inventory then
local item_count = inventory.get_item_count(target_name)
if item_count > 0 then
SearchResults.add_entity_module(entity, surface_data.modules, item_count)
end
end
end
end
-- Requesters
if target_is_item and state.requesters then
-- Buffer and Requester chests
if entity_type == "logistic-container" then
for i=1, entity.request_slot_count do
local request = entity.get_request_slot(i)
if request and request.name == target_name then
local count = request.count
if count then
SearchResults.add_entity_request(entity, surface_data.requesters, count)
end
end
end
elseif entity_type == "character" then
for i=1, entity.request_slot_count do
local request = entity.get_personal_logistic_slot(i)
if request and request.name == target_name then
local count = request.min
if count and count > 0 then
SearchResults.add_entity_request(entity, surface_data.requesters, request.min)
end
end
end
elseif entity_type == "spider-vehicle" then
for i=1, entity.request_slot_count do
local request = entity.get_vehicle_logistic_slot(i)
if request and request.name == target_name then
local count = request.min
if count and count > 0 then
SearchResults.add_entity_request(entity, surface_data.requesters, request.min)
end
end
end
elseif entity_type == "item-request-proxy" then
local request_count = entity.item_requests[target_name]
if request_count ~= nil then
SearchResults.add_entity_request(entity.proxy_target, surface_data.requesters, request_count)
end
end
end
-- Ground
if target_is_item and state.ground_items then
if entity_type == "item-entity" and entity.name == "item-on-ground" then
if entity.stack.name == target_name then
SearchResults.add_entity(entity, surface_data.ground_items)
end
end
end
-- Logistics
if state.logistics then
if item_logistic_entities[entity_type] then
if entity_type == "inserter" then
local held_stack = entity.held_stack
if held_stack and held_stack.valid_for_read and held_stack.name == target_name then
SearchResults.add_entity_storage(entity, surface_data.logistics, held_stack.count)
end
else
local item_count = entity.get_item_count(target_name)
if item_count > 0 then
SearchResults.add_entity_storage(entity, surface_data.logistics, item_count)
end
end
elseif fluid_logistic_entities[entity_type] then
-- So target.type == "fluid"
local fluid_count = entity.get_fluid_count(target_name)
if fluid_count > 0 then
SearchResults.add_entity_storage_fluid(entity, surface_data.logistics, fluid_count)
end
end
end
::continue::
end
end
function Search.blocking_search(force, state, target_item, surface_list, type_list, neutral_type_list, player)
local target_name = target_item.name
local target_type = target_item.type
local target_is_item = target_type == "item"
local target_is_fluid = target_type == "fluid"
local target_is_virtual = target_type == "virtual"
local data = {}
for _, surface in pairs(surface_list) do
local surface_data = table.deepcopy(default_surface_data)
local entities = {}
if next(type_list) then
entities = surface.find_entities_filtered{
type = type_list,
force = force,
}
end
-- Corpses and items on ground don't have a force: find seperately
if next(neutral_type_list) then
local neutral_entities = surface.find_entities_filtered{
type = neutral_type_list,
}
extend(entities, neutral_entities)
end
Search.process_found_entities(entities, state, surface_data, target_item)
-- Map tags
if state.map_tags then
local tags = force.find_chart_tags(surface.name)
for _, tag in pairs(tags) do
local tag_icon = tag.icon
if tag_icon and tag_icon.type == target_type and tag_icon.name == target_name then
SearchResults.add_tag(tag, surface_data.map_tags)
end
end
end
-- Entities
if state.entities then
local target_entity_name = mod_placeholder_entities[target_name]
if not target_entity_name then
-- Check if the item is produced by mining any entities
target_entity_name = global.item_to_entities[target_name]
if not target_entity_name then
-- Otherwise, check for the item's place_result
local item_prototype = game.item_prototypes[target_name]
if item_prototype and item_prototype.place_result then
target_entity_name = item_prototype.place_result.name
else
-- Or just try an entity with the same name as the item
target_entity_name = target_name
end
end
end
entities = surface.find_entities_filtered{
name = target_entity_name,
force = { force, "neutral" },
}
for _, entity in pairs(entities) do
if entity.type == "resource" then
local amount
if entity.initial_amount then
amount = entity.amount / 3000 -- Calculate yield from amount
else
amount = entity.amount
end
SearchResults.add_entity_resource(entity, surface_data.entities, amount)
else
SearchResults.add_entity(entity, surface_data.entities)
end
end
end
if surface == player.surface then
generate_distance_data(surface_data, player.position)
end
remove_uncharted_groups(surface_data, surface, force)
data[surface.name] = surface_data
end
return data
end
function Search.non_blocking_search(force, state, target_item, surface_list, type_list, neutral_type_list, player)
search_data = {
force = force,
state = state,
target_item = target_item,
type_list = type_list,
neutral_type_list = neutral_type_list,
player = player,
data = {},
not_started_surfaces = surface_list,
completed_surfaces = {}
}
global.current_searches[player.index] = search_data
end
function Search.on_tick()
local player_index, search_data = next(global.current_searches)
if not search_data then return end
if search_data.search_complete then
local player_data = global.players[player_index]
local refs = player_data.refs
Gui.build_results(search_data.data, refs.result_flow)
global.current_searches[player_index] = nil
end
local current_surface = search_data.current_surface
if not current_surface or not current_surface.valid then
-- Start next surface
current_surface = table.remove(search_data.not_started_surfaces)
if not current_surface then
-- All surfaces are complete
local player = search_data.player
local surface_data = search_data.data[player.surface.name]
if surface_data then
generate_distance_data(surface_data, player.position)
end
search_data.search_complete = true
return
end
if not current_surface.valid then return end -- Will try another surface next tick
-- Setup next surface data
search_data.current_surface = current_surface
search_data.surface_data = table.deepcopy(default_surface_data)
search_data.chunk_iterator = current_surface.get_chunks()
-- Update results
local player_data = global.players[player_index]
local refs = player_data.refs
Gui.build_results(search_data.data, refs.result_flow, false, true)
Gui.add_loading_results(refs.result_flow)
return -- Start next surface processing on next tick
end
local chunk_iterator = search_data.chunk_iterator
if not chunk_iterator.valid then
search_data.current_surface = nil
return
end
local force = search_data.force
local chunks_processed = 0
local chunks_per_tick = settings.global["fs-chunks-per-tick"].value
while chunks_processed < chunks_per_tick do
local chunk = chunk_iterator()
if not chunk then
-- Surface is complete
search_data.data[current_surface.name] = search_data.surface_data
search_data.current_surface = nil
return
end
if force.is_chunk_charted(current_surface, chunk) then
chunks_processed = chunks_processed + 1
else
goto continue
end
local target_item = search_data.target_item
local target_name = target_item.name
local target_type = target_item.type
local target_is_item = target_type == "item"
local target_is_fluid = target_type == "fluid"
local target_is_virtual = target_type == "virtual"
local state = search_data.state
local surface_data = search_data.surface_data
local chunk_area = chunk.area
local entities = {}
if next(search_data.type_list) then
entities = current_surface.find_entities_filtered{
area = chunk_area,
type = search_data.type_list,
force = force,
}
end
-- Corpses and items on ground don't have a force: find seperately
if next(search_data.neutral_type_list) then
local neutral_entities = current_surface.find_entities_filtered{
area = chunk_area,
type = search_data.neutral_type_list,
}
extend(entities, neutral_entities)
end
for i, entity in pairs(entities) do
if not math2d.bounding_box.contains_point(chunk_area, entity.position) then
entities[i] = nil
end
end
Search.process_found_entities(entities, state, surface_data, target_item)
-- Map tags
if state.map_tags then
local tags = force.find_chart_tags(current_surface.name, chunk_area)
for _, tag in pairs(tags) do
local tag_icon = tag.icon
if tag_icon and tag_icon.type == target_type and tag_icon.name == target_name then
SearchResults.add_tag(tag, surface_data.map_tags)
end
end
end
-- Entities
if state.entities then
local target_entity_name = mod_placeholder_entities[target_name]
if not target_entity_name then
-- Check if the item is produced by mining any entities
target_entity_name = global.item_to_entities[target_name]
if not target_entity_name then
-- Otherwise, check for the item's place_result
local item_prototype = game.item_prototypes[target_name]
if item_prototype and item_prototype.place_result then
target_entity_name = item_prototype.place_result.name
else
-- Or just try an entity with the same name as the item
target_entity_name = target_name
end
end
end
entities = current_surface.find_entities_filtered{
area = chunk_area,
name = target_entity_name,
force = { force, "neutral" },
}
for i, entity in pairs(entities) do
if not math2d.bounding_box.contains_point(chunk_area, entity.position) then
entities[i] = nil
end
end
for _, entity in pairs(entities) do
if entity.type == "resource" then
local amount
if entity.initial_amount then
amount = entity.amount / 3000 -- Calculate yield from amount
else
amount = entity.amount
end
SearchResults.add_entity_resource(entity, surface_data.entities, amount)
else
SearchResults.add_entity(entity, surface_data.entities)
end
end
end
::continue::
end
end
event.on_tick(Search.on_tick)
function Search.find_machines(target_item, force, state, player, override_surface)
local data = {}
local target_name = target_item.name
if target_name == nil then
-- 'Unknown signal selected'
return data
end
-- Crafting Combinator adds signals for recipes, which players sometimes mistake for items/fluids
if target_item.type == "virtual" and not state.signals
and (game.active_mods["crafting_combinator"] or game.active_mods["crafting_combinator_xeraph"]) then
local recipe = game.recipe_prototypes[target_name]
if recipe then
player.print("[Factory Search] It looks like you selected a recipe from the \"Crafting combinator recipes\" tab. Instead select an item or fluid from a different tab.")
return data
end
end
local target_type = target_item.type
local target_is_item = target_type == "item"
local target_is_fluid = target_type == "fluid"
local target_is_virtual = target_type == "virtual"
local entity_types = {}
local neutral_entity_types = {}
if (target_is_item or target_is_fluid) and state.consumers then
add_entity_type(entity_types, ingredient_entities)
-- Only add turrets if target is ammo
if target_is_item and game.get_filtered_item_prototypes({{filter = "type", type = "ammo"}})[target_name] then
add_entity_type(entity_types, item_ammo_ingredient_entities)
elseif target_is_fluid then
add_entity_type(entity_types, fluid_ammo_ingredient_entities)
end
end
if (target_is_item or target_is_fluid) and state.producers then
add_entity_type(entity_types, product_entities)
end
if target_is_item and state.storage then
add_entity_type(entity_types, item_storage_entities)
add_entity_type(neutral_entity_types, neutral_item_storage_entities)
end
if target_is_fluid and state.storage then
add_entity_type(entity_types, fluid_storage_entities)
end
if target_is_item and state.requesters then
add_entity_type(entity_types, request_entities)
end
if target_is_item and state.modules then
add_entity_type(entity_types, modules_entities)
end
if target_is_item and state.logistics then
add_entity_type(entity_types, item_logistic_entities)
end
if target_is_fluid and state.logistics then
add_entity_type(entity_types, fluid_logistic_entities)
end
if target_is_item and state.ground_items then
add_entity_type(neutral_entity_types, ground_entities)
end
if state.signals then
add_entity_type(entity_types, signal_entities)
end
local type_list = map_to_list(entity_types)
local neutral_type_list = map_to_list(neutral_entity_types)
local surface_list = filtered_surfaces(override_surface, player.surface)
local non_blocking_search = settings.global["fs-non-blocking-search"].value
if non_blocking_search == "on" or (non_blocking_search == "multiplayer" and game.is_multiplayer()) then
-- Do non blocking search
Search.non_blocking_search(force, state, target_item, surface_list, type_list, neutral_type_list, player)
data = { non_blocking_search = true }
else
data = Search.blocking_search(force, state, target_item, surface_list, type_list, neutral_type_list, player)
end
return data
end
return Search