460 lines
15 KiB
Lua
460 lines
15 KiB
Lua
local blueprint = require("lualib.blueprint")
|
|
local circuit = require("circuit")
|
|
local configchange = require("configchange")
|
|
local event = require("lualib.event")
|
|
local miniloader = require("lualib.miniloader")
|
|
local gui = require("gui")
|
|
local snapping = require("snapping")
|
|
local util = require("lualib.util")
|
|
|
|
local compat_pickerextended = require("compat.pickerextended")
|
|
|
|
local use_snapping = settings.global["miniloader-snapping"].value
|
|
|
|
--[[
|
|
loader_type = "input"
|
|
+------------------+
|
|
| |
|
|
| P |
|
|
| |
|
|
| | |
|
|
| | | chest dir
|
|
| | |
|
|
| | v
|
|
| |
|
|
+------------------+
|
|
D D
|
|
--
|
|
loader_type = "output"
|
|
+------------------+
|
|
| |
|
|
| D D |
|
|
| |
|
|
| | |
|
|
| | | chest dir
|
|
| | |
|
|
| | v
|
|
| |
|
|
+------------------+
|
|
P
|
|
--
|
|
D: drop positions
|
|
P: pickup position
|
|
]]
|
|
|
|
local function register_bobs_blacklist()
|
|
for _, interface_name in ipairs{"bobinserters", "boblogistics"} do
|
|
local interface = remote.interfaces[interface_name]
|
|
if interface and interface["blacklist_inserter"] then
|
|
for entity_name in pairs(game.entity_prototypes) do
|
|
if util.is_miniloader_inserter_name(entity_name) then
|
|
remote.call(interface_name, "blacklist_inserter", entity_name)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Event Handlers
|
|
|
|
local function on_init()
|
|
global.player_placed_blueprint = {}
|
|
global.previous_opened_blueprint_for = {}
|
|
global.split_lane_configuration = {}
|
|
circuit.on_init()
|
|
compat_pickerextended.on_load()
|
|
gui.on_init()
|
|
register_bobs_blacklist()
|
|
end
|
|
|
|
local function on_load()
|
|
circuit.on_load()
|
|
compat_pickerextended.on_load()
|
|
gui.on_load()
|
|
end
|
|
|
|
local function on_configuration_changed(configuration_changed_data)
|
|
local mod_change = configuration_changed_data.mod_changes["miniloader"]
|
|
if mod_change and mod_change.old_version and mod_change.old_version ~= mod_change.new_version then
|
|
configchange.on_mod_version_changed(mod_change.old_version)
|
|
circuit.on_configuration_changed()
|
|
gui.on_configuration_changed()
|
|
end
|
|
register_bobs_blacklist()
|
|
configchange.fix_inserter_counts()
|
|
end
|
|
|
|
local fast_replace_miniloader_state
|
|
|
|
local function on_built_miniloader(entity, orientation, tags)
|
|
if not orientation then
|
|
orientation = {direction = util.opposite_direction(entity.direction), type = "input"}
|
|
end
|
|
if not tags
|
|
and util.is_output_miniloader_inserter(entity)
|
|
and fast_replace_miniloader_state
|
|
and fast_replace_miniloader_state.tick == game.tick
|
|
and fast_replace_miniloader_state.surface == entity.surface
|
|
and fast_replace_miniloader_state.position.x == entity.position.x
|
|
and fast_replace_miniloader_state.position.y == entity.position.y
|
|
then
|
|
tags = {
|
|
right_lane_settings = fast_replace_miniloader_state.right_lane_settings,
|
|
}
|
|
fast_replace_miniloader_state = nil
|
|
end
|
|
return miniloader.fixup(entity, orientation, tags)
|
|
end
|
|
|
|
local function on_robot_built(ev)
|
|
local entity = ev.created_entity
|
|
if util.is_miniloader_inserter(entity) then
|
|
on_built_miniloader(entity, util.orientation_from_inserters(entity), ev.tags)
|
|
end
|
|
end
|
|
|
|
local function on_script_built(ev)
|
|
local entity = ev.entity
|
|
if entity and util.is_miniloader_inserter(entity) then
|
|
on_built_miniloader(entity, util.orientation_from_inserters(entity))
|
|
end
|
|
end
|
|
|
|
local function on_script_revive(ev)
|
|
local entity = ev.entity
|
|
if entity and util.is_miniloader_inserter(entity) then
|
|
on_built_miniloader(entity, util.orientation_from_inserters(entity), ev.tags)
|
|
end
|
|
end
|
|
|
|
local function on_player_built(ev)
|
|
local entity = ev.created_entity
|
|
|
|
if util.is_miniloader_inserter(entity) then
|
|
local orientation = util.orientation_from_inserters(entity)
|
|
local loader = on_built_miniloader(entity, orientation, ev.tags)
|
|
if use_snapping and not orientation then
|
|
-- adjusts direction & loader_type
|
|
snapping.snap_loader(loader)
|
|
end
|
|
elseif use_snapping
|
|
and entity.type == "entity-ghost"
|
|
and util.is_miniloader_inserter_name(entity.ghost_name) then
|
|
-- remove duplicate ghosts
|
|
local colocated_ghosts = entity.surface.find_entities_filtered{
|
|
position = entity.position,
|
|
ghost_name = entity.ghost_name,
|
|
}
|
|
for _, ghost in pairs(colocated_ghosts) do
|
|
if ghost ~= entity then
|
|
ghost.destroy()
|
|
end
|
|
end
|
|
if util.orientation_from_inserters(entity) == nil then
|
|
snapping.snap_loader(entity)
|
|
end
|
|
elseif use_snapping then
|
|
snapping.check_for_loaders(ev)
|
|
end
|
|
end
|
|
|
|
local function on_rotated(ev)
|
|
local entity = ev.entity
|
|
if util.is_miniloader_inserter(entity) then
|
|
local miniloader = util.find_miniloaders{
|
|
surface = entity.surface,
|
|
position = entity.position,
|
|
force = entity.force,
|
|
}[1]
|
|
miniloader.rotate{ by_player = game.players[ev.player_index] }
|
|
util.update_inserters(miniloader)
|
|
elseif util.is_miniloader(entity) then
|
|
util.update_inserters(entity)
|
|
elseif use_snapping then
|
|
snapping.check_for_loaders(ev)
|
|
end
|
|
end
|
|
|
|
local function on_miniloader_mined(ev)
|
|
local entity = ev.entity
|
|
local buffer = ev.buffer and ev.buffer.valid and ev.buffer
|
|
local inserters = util.get_loader_inserters(entity)
|
|
if buffer and inserters[1] then
|
|
local _, item_to_place = next(inserters[1].prototype.items_to_place_this)
|
|
buffer.insert{desired_count=1, name=item_to_place.name}
|
|
end
|
|
for i=1,#inserters do
|
|
-- return items to player / robot if mined
|
|
if buffer and inserters[i] ~= entity and inserters[i].held_stack.valid_for_read then
|
|
buffer.insert(inserters[i].held_stack)
|
|
end
|
|
inserters[i].destroy()
|
|
end
|
|
local chest = entity.surface.find_entity("miniloader-target-chest", entity.position)
|
|
if chest then
|
|
chest.destroy()
|
|
end
|
|
end
|
|
|
|
local function on_miniloader_inserter_mined(ev)
|
|
local entity = ev.entity
|
|
local buffer = ev.buffer and ev.buffer.valid and ev.buffer
|
|
local loader = entity.surface.find_entities_filtered{
|
|
position = entity.position,
|
|
type = "loader-1x1",
|
|
}[1]
|
|
if loader then
|
|
if buffer then
|
|
for i=1,2 do
|
|
local tl = loader.get_transport_line(i)
|
|
for j=1,math.min(#tl, 256) do
|
|
buffer.insert(tl[j])
|
|
end
|
|
tl.clear()
|
|
end
|
|
end
|
|
loader.destroy()
|
|
end
|
|
|
|
local inserters = util.get_loader_inserters(entity)
|
|
if util.is_output_miniloader_inserter(entity)
|
|
and global.split_lane_configuration[entity.unit_number] then
|
|
fast_replace_miniloader_state = {
|
|
position = entity.position,
|
|
right_lane_settings = util.capture_settings(inserters[2]),
|
|
surface = entity.surface,
|
|
tick = ev.tick,
|
|
}
|
|
global.split_lane_configuration[entity.unit_number] = nil
|
|
end
|
|
for i=1,#inserters do
|
|
if inserters[i] ~= entity then
|
|
-- return items in inserter hand to player / robot if mined
|
|
if buffer and inserters[i].held_stack.valid_for_read then
|
|
buffer.insert(inserters[i].held_stack)
|
|
end
|
|
inserters[i].destroy()
|
|
end
|
|
end
|
|
|
|
local chest = entity.surface.find_entity("miniloader-target-chest", entity.position)
|
|
if chest then
|
|
chest.destroy()
|
|
end
|
|
end
|
|
|
|
local function on_mined(ev)
|
|
local entity = ev.entity
|
|
if util.is_miniloader(entity) then
|
|
on_miniloader_mined(ev)
|
|
elseif util.is_miniloader_inserter(entity) then
|
|
on_miniloader_inserter_mined(ev)
|
|
end
|
|
end
|
|
|
|
local function on_placed_blueprint(ev, player, bp_entities)
|
|
if not next(bp_entities) then return end
|
|
|
|
global.player_placed_blueprint[ev.player_index] = ev.tick
|
|
|
|
local surface = player.surface
|
|
local bp_area = blueprint.bounding_box(bp_entities)
|
|
local surface_area = util.move_box(
|
|
util.rotate_box(bp_area, ev.direction),
|
|
ev.position
|
|
)
|
|
|
|
local blueprint_contained_miniloader = false
|
|
for _, bp_entity in pairs(bp_entities) do
|
|
if util.is_miniloader_inserter_name(bp_entity.name) then
|
|
blueprint_contained_miniloader = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if blueprint_contained_miniloader then
|
|
-- remember where we have placed a blueprint so we can check for changes next tick
|
|
if not global.placed_blueprint_areas then global.placed_blueprint_areas = {} end
|
|
global.placed_blueprint_areas[#global.placed_blueprint_areas+1] = {
|
|
surface = surface,
|
|
area = surface_area,
|
|
}
|
|
end
|
|
end
|
|
|
|
-- A blueprint placed over existing miniloaders in the previous tick
|
|
-- may have changed their orientation.
|
|
local function check_placed_blueprints_for_miniloaders()
|
|
if not global.placed_blueprint_areas or not next(global.placed_blueprint_areas) then return end
|
|
for _, data in ipairs(global.placed_blueprint_areas) do
|
|
local surface = data.surface
|
|
local area = data.area
|
|
if surface.valid then
|
|
local inserter_entities = surface.find_entities_filtered{
|
|
area = area,
|
|
type = "inserter",
|
|
}
|
|
for _, e in pairs(inserter_entities) do
|
|
if util.is_miniloader_inserter(e) then
|
|
miniloader.fixup(e, util.orientation_from_inserters(e))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
global.placed_blueprint_areas = {}
|
|
end
|
|
|
|
local function on_pre_build(ev)
|
|
local player_index = ev.player_index
|
|
local player = game.players[player_index]
|
|
local bp_entities = player.get_blueprint_entities()
|
|
if bp_entities then
|
|
return on_placed_blueprint(ev, player, bp_entities)
|
|
end
|
|
end
|
|
|
|
local function on_pre_player_mined_item(ev)
|
|
local entity = ev.entity
|
|
if entity.name == "entity-ghost" and entity.tags and entity.tags.right_lane_settings then
|
|
fast_replace_miniloader_state = {
|
|
position = entity.position,
|
|
right_lane_settings = entity.tags.right_lane_settings,
|
|
surface = entity.surface,
|
|
tick = ev.tick,
|
|
}
|
|
end
|
|
end
|
|
|
|
local function on_player_mined_entity(ev)
|
|
on_mined(ev)
|
|
end
|
|
|
|
local function on_entity_settings_pasted(ev)
|
|
local src = ev.source
|
|
local dst = ev.destination
|
|
if util.is_miniloader_inserter(src) and util.is_miniloader_inserter(dst) then
|
|
local src_loader = src.surface.find_entities_filtered{type="loader-1x1",position=src.position}[1]
|
|
local dst_loader = dst.surface.find_entities_filtered{type="loader-1x1",position=dst.position}[1]
|
|
if src_loader and dst_loader then
|
|
dst_loader.loader_type = src_loader.loader_type
|
|
util.update_inserters(dst_loader)
|
|
end
|
|
if util.is_output_miniloader_inserter(src) then
|
|
local right_src = util.get_loader_inserters(src)[2]
|
|
local right_dst = util.get_loader_inserters(dst)[2]
|
|
if right_src and right_dst then
|
|
global.split_lane_configuration[dst.unit_number] = global.split_lane_configuration[src.unit_number]
|
|
circuit.copy_inserter_settings(right_src, right_dst)
|
|
end
|
|
end
|
|
circuit.sync_behavior(dst)
|
|
circuit.sync_filters(dst)
|
|
end
|
|
end
|
|
|
|
local function on_gui_closed(event)
|
|
local player = game.get_player(event.player_index)
|
|
if event.gui_type == defines.gui_type.item
|
|
and event.item
|
|
and event.item.is_blueprint
|
|
and event.item.is_blueprint_setup()
|
|
and player.cursor_stack
|
|
and player.cursor_stack.valid_for_read
|
|
and player.cursor_stack.is_blueprint
|
|
and not player.cursor_stack.is_blueprint_setup()
|
|
then
|
|
global.previous_opened_blueprint_for[event.player_index] = {
|
|
blueprint = event.item,
|
|
tick = event.tick,
|
|
}
|
|
else
|
|
global.previous_opened_blueprint_for[event.player_index] = nil
|
|
end
|
|
end
|
|
|
|
local function on_setup_blueprint(ev)
|
|
local bp = blueprint.get_blueprint_to_setup(ev.player_index)
|
|
if not (bp and bp.valid_for_read) then return end
|
|
blueprint.filter_miniloaders(bp, ev.surface)
|
|
end
|
|
|
|
local function on_marked_for_deconstruction(ev)
|
|
local entity = ev.entity
|
|
if not (util.is_miniloader(entity) or util.is_miniloader_inserter(entity)) then return end
|
|
for _, ent in ipairs(entity.surface.find_entities_filtered{position=entity.position}) do
|
|
-- order_deconstruction() causes event handlers to be fired which may invalidate entities
|
|
if ent.valid and (util.is_miniloader(ent) or util.is_miniloader_inserter(ent)) then
|
|
if not ent.to_be_deconstructed(ent.force) then
|
|
ent.order_deconstruction(ent.force)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function on_canceled_deconstruction(ev)
|
|
local entity = ev.entity
|
|
for _, ent in ipairs(entity.surface.find_entities_filtered{position=entity.position}) do
|
|
if util.is_miniloader(ent) or util.is_miniloader_inserter(ent) then
|
|
if ent.to_be_deconstructed(ent.force) then
|
|
ent.cancel_deconstruction(ent.force)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function on_marked_for_upgrade(ev)
|
|
local entity = ev.entity
|
|
if not util.is_miniloader_inserter(entity) then return end
|
|
local main_inserter = entity.surface.find_entity(entity.name, entity.position)
|
|
if entity == main_inserter then return end
|
|
local force = ev.player_index and game.get_player(ev.player_index).force or entity.force
|
|
entity.cancel_upgrade(force)
|
|
end
|
|
|
|
-- lifecycle events
|
|
|
|
script.on_init(on_init)
|
|
script.on_load(on_load)
|
|
script.on_configuration_changed(on_configuration_changed)
|
|
|
|
-- entity events
|
|
|
|
event.register(defines.events.on_built_entity, on_player_built)
|
|
event.register(defines.events.on_robot_built_entity, on_robot_built)
|
|
event.register(defines.events.on_player_rotated_entity, on_rotated)
|
|
|
|
event.register(defines.events.on_pre_player_mined_item, on_pre_player_mined_item)
|
|
event.register(defines.events.on_player_mined_entity, on_player_mined_entity)
|
|
event.register(defines.events.on_robot_mined_entity, on_mined)
|
|
event.register(defines.events.on_entity_died, on_mined)
|
|
event.register(defines.events.script_raised_built, on_script_built)
|
|
event.register(defines.events.script_raised_revive, on_script_revive)
|
|
event.register(defines.events.script_raised_destroy, on_mined)
|
|
|
|
event.register(defines.events.on_entity_settings_pasted, on_entity_settings_pasted)
|
|
event.register(defines.events.on_pre_build, on_pre_build)
|
|
|
|
event.register(defines.events.on_player_setup_blueprint, on_setup_blueprint)
|
|
event.register(defines.events.on_marked_for_deconstruction, on_marked_for_deconstruction)
|
|
event.register(defines.events.on_canceled_deconstruction, on_canceled_deconstruction)
|
|
|
|
event.register(defines.events.on_marked_for_upgrade, on_marked_for_upgrade)
|
|
|
|
event.register(defines.events.on_gui_closed, on_gui_closed)
|
|
|
|
event.register(defines.events.on_runtime_mod_setting_changed, function(ev)
|
|
if ev.setting == "miniloader-snapping" then
|
|
use_snapping = settings.global["miniloader-snapping"].value
|
|
elseif ev.setting == "miniloader-lock-stack-sizes" then
|
|
local size = settings.global["miniloader-lock-stack-sizes"].value and 1 or 0
|
|
miniloader.forall(function(surface, miniloader)
|
|
for _, inserter in pairs(util.get_loader_inserters(miniloader)) do
|
|
inserter.inserter_stack_size_override = size
|
|
end
|
|
end)
|
|
end
|
|
end)
|
|
|
|
event.register(defines.events.on_tick, check_placed_blueprints_for_miniloaders)
|