407 lines
12 KiB
Lua
407 lines
12 KiB
Lua
local bulk = require "bulk"
|
|
local configchange = require "configchange"
|
|
local delaydestroy = require "delaydestroy"
|
|
local ghostconnections = require "ghostconnections"
|
|
local inserter_config = require "inserterconfig"
|
|
local util = require "util"
|
|
|
|
-- constants
|
|
|
|
local num_inserters = 2
|
|
|
|
local allowed_items_setting = settings.global["railloader-allowed-items"].value
|
|
|
|
local function on_init()
|
|
global.previous_opened_blueprint_for = {}
|
|
delaydestroy.on_init()
|
|
inserter_config.on_init()
|
|
end
|
|
|
|
local function on_load()
|
|
delaydestroy.on_load()
|
|
inserter_config.on_load()
|
|
end
|
|
|
|
local function on_configuration_changed(configuration_changed_data)
|
|
local mod_change = configuration_changed_data.mod_changes["railloader"]
|
|
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)
|
|
end
|
|
end
|
|
|
|
local function show_error(entity)
|
|
entity.surface.create_entity{
|
|
name = "flying-text",
|
|
position = entity.position,
|
|
text = {"railloader.invalid-position"},
|
|
}
|
|
end
|
|
|
|
local function abort_build(event)
|
|
local entity = event.created_entity or event.entity
|
|
show_error(entity)
|
|
if event.player_index then
|
|
local player = game.players[event.player_index]
|
|
player.mine_entity(entity, true)
|
|
else
|
|
entity.order_deconstruction(entity.force)
|
|
end
|
|
end
|
|
|
|
local function sync_interface_inserters(loader)
|
|
local type = util.railloader_type(loader.name)
|
|
local interface_chests = util.find_chests_from_railloader(loader)
|
|
for _, interface_chest in ipairs(interface_chests) do
|
|
local inserter = util.find_inserter_for_interface(loader, interface_chest)
|
|
if not inserter then
|
|
local main_chest_position = util.loader_position_for_interface(loader, interface_chest)
|
|
inserter = loader.surface.create_entity{
|
|
name = util.interface_inserter_name_for_loader(loader),
|
|
position = loader.position,
|
|
force = loader.force,
|
|
}
|
|
inserter.destructible = false
|
|
inserter.pickup_position = type == "loader" and interface_chest.position or main_chest_position
|
|
inserter.drop_position = type == "unloader" and interface_chest.position or main_chest_position
|
|
inserter.direction = inserter.direction
|
|
end
|
|
inserter_config.connect_and_configure_inserter_control_behavior(inserter, loader)
|
|
end
|
|
end
|
|
|
|
local function remove_interface_inserter(loader, chest, buffer)
|
|
local inserter = util.find_inserter_for_interface(loader, chest)
|
|
if inserter then
|
|
util.insert_or_spill(loader, inserter.held_stack, {loader.get_inventory(defines.inventory.chest), buffer})
|
|
inserter.destroy()
|
|
end
|
|
end
|
|
|
|
local function rail_positions(proxy)
|
|
local direction = proxy.direction
|
|
local position = proxy.position
|
|
|
|
if direction == defines.direction.north or direction == defines.direction.south then
|
|
if position.x % 2 ~= 1 then
|
|
return nil
|
|
end
|
|
if position.y % 2 == 1 then
|
|
return {
|
|
util.moveposition(position, {x = 0, y = -2}),
|
|
position,
|
|
util.moveposition(position, {x = 0, y = 2}),
|
|
}
|
|
else
|
|
return {
|
|
util.moveposition(position, {x = 0, y = -1}),
|
|
util.moveposition(position, {x = 0, y = 1}),
|
|
}
|
|
end
|
|
else
|
|
if position.y % 2 ~= 1 then
|
|
return nil
|
|
end
|
|
if position.x % 2 == 1 then
|
|
return {
|
|
util.moveposition(position, {x = -2, y = 0}),
|
|
position,
|
|
util.moveposition(position, {x = 2, y = 0}),
|
|
}
|
|
else
|
|
return {
|
|
util.moveposition(position, {x = -1, y = 0}),
|
|
util.moveposition(position, {x = 1, y = 0}),
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
local function create_entities(proxy, tags, rail_poss)
|
|
local type = util.railloader_type(proxy.name)
|
|
local surface = proxy.surface
|
|
local direction = proxy.direction
|
|
if direction >= 4 then
|
|
direction = direction - 4
|
|
end
|
|
local position = proxy.position
|
|
local force = proxy.force
|
|
local last_user = proxy.last_user
|
|
|
|
-- place rails
|
|
for _, rail_position in ipairs(rail_poss) do
|
|
local rail = surface.create_entity{
|
|
name = "railloader-rail",
|
|
position = rail_position,
|
|
direction = direction,
|
|
force = force,
|
|
}
|
|
rail.destructible = false
|
|
rail.minable = false
|
|
end
|
|
|
|
-- place chest
|
|
local chest = surface.create_entity{
|
|
name = "rail" .. type .. "-chest",
|
|
position = position,
|
|
force = force,
|
|
}
|
|
chest.last_user = last_user
|
|
if tags and tags.bar then
|
|
chest.get_inventory(defines.inventory.chest).set_bar(tags.bar)
|
|
end
|
|
|
|
-- recreate circuit connections
|
|
--[[for _, ccd in ipairs(proxy.circuit_connection_definitions) do
|
|
chest.connect_neighbour(ccd)
|
|
end
|
|
for _, ccd in ipairs(ghostconnections.get_connections(proxy)) do
|
|
chest.connect_neighbour(ccd)
|
|
end]]
|
|
|
|
-- place cargo wagon inserters
|
|
local inserter_name =
|
|
"rail" .. type .. (allowed_items_setting == "any" and "-universal" or "") .. "-inserter"
|
|
for i=1,num_inserters do
|
|
-- alternate direction to support half-size wagons sticking out both sides of the (un)loader
|
|
local inserter_direction = (direction + (i-1) * 4) % 8
|
|
local inserter = surface.create_entity{
|
|
name = inserter_name,
|
|
position = position,
|
|
direction = inserter_direction,
|
|
force = force,
|
|
}
|
|
inserter.destructible = false
|
|
sync_interface_inserters(inserter)
|
|
if i==1 then
|
|
temp = inserter,
|
|
inserter_config.connect_and_configure_inserter_control_behavior(inserter, temp, true)
|
|
else
|
|
inserter_config.connect_and_configure_inserter_control_behavior(inserter, temp, false)
|
|
end
|
|
end
|
|
|
|
inserter_config.configure_or_register_loader(chest)
|
|
|
|
-- place structure
|
|
local structure_name = "rail" .. type .. "-structure-vertical"
|
|
if direction == defines.direction.east or direction == defines.direction.west then
|
|
structure_name = "rail" .. type .. "-structure-horizontal"
|
|
end
|
|
local placed = surface.create_entity{
|
|
name = structure_name,
|
|
position = position,
|
|
force = force,
|
|
}
|
|
placed.destructible = false
|
|
|
|
-- place interface inserters for pre-existing chests
|
|
--sync_interface_inserters(chest)
|
|
end
|
|
|
|
local function on_railloader_proxy_built(event)
|
|
local proxy = event.created_entity or event.entity
|
|
local tags = event.tags
|
|
local rail_pos = rail_positions(proxy)
|
|
if not rail_pos then
|
|
return abort_build(event)
|
|
end
|
|
create_entities(proxy, tags, rail_pos)
|
|
proxy.destroy()
|
|
end
|
|
|
|
local function on_ghost_built(ghost)
|
|
local rail_pos = rail_positions(ghost)
|
|
if not rail_pos then
|
|
show_error(ghost)
|
|
ghost.destroy()
|
|
end
|
|
end
|
|
|
|
local function on_container_built(entity)
|
|
for _, loader in ipairs(util.find_railloaders_from_chest(entity)) do
|
|
sync_interface_inserters(loader)
|
|
end
|
|
end
|
|
|
|
local function on_built(event)
|
|
local entity = event.created_entity or event.entity
|
|
local type = util.railloader_type(entity.name)
|
|
if type then
|
|
return on_railloader_proxy_built(event)
|
|
elseif entity.type == "entity-ghost" then
|
|
type = util.railloader_type(entity.ghost_name)
|
|
if type then
|
|
return on_ghost_built(entity)
|
|
end
|
|
elseif string.find(entity.type, "container$") then
|
|
return on_container_built(entity)
|
|
end
|
|
end
|
|
|
|
local function on_railloader_mined(entity, buffer)
|
|
local entities = entity.surface.find_entities_filtered{
|
|
area = entity.bounding_box,
|
|
}
|
|
for _, ent in ipairs(entities) do
|
|
if ent.type == "inserter" then
|
|
if buffer and ent.held_stack.valid_for_read then
|
|
buffer.insert(ent.held_stack)
|
|
end
|
|
ent.destroy()
|
|
elseif string.find(ent.name, "^railu?n?loader%-structure") then
|
|
ent.destroy()
|
|
elseif ent.type == "straight-rail" then
|
|
local success = ent.destroy()
|
|
if not success then
|
|
delaydestroy.register_to_destroy(ent)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function on_container_mined(entity, buffer)
|
|
for _, loader in ipairs(util.find_railloaders_from_chest(entity)) do
|
|
remove_interface_inserter(loader, entity, buffer)
|
|
end
|
|
end
|
|
|
|
local died_direction
|
|
|
|
local function on_post_entity_died(event)
|
|
local ghost = event.ghost
|
|
if ghost then
|
|
local loader_type = util.railloader_type(ghost.ghost_name)
|
|
if loader_type then
|
|
local new_ghost = ghost.surface.create_entity{
|
|
name = "entity-ghost",
|
|
inner_name = "rail" .. loader_type .. "-placement-proxy",
|
|
force = ghost.force,
|
|
direction = died_direction,
|
|
position = ghost.position,
|
|
}
|
|
new_ghost.last_user = ghost.last_user
|
|
ghost.destroy()
|
|
end
|
|
end
|
|
end
|
|
|
|
local function on_mined(event)
|
|
local entity = event.entity
|
|
local type = util.railloader_type(entity.name)
|
|
if type then
|
|
died_direction = util.loader_direction(entity)
|
|
return on_railloader_mined(entity, event.buffer)
|
|
elseif string.find(entity.type, "container$") then
|
|
return on_container_mined(entity, event.buffer)
|
|
end
|
|
end
|
|
|
|
local function on_robot_pre_mined(event)
|
|
if event.instant_deconstruction then
|
|
on_mined(event)
|
|
end
|
|
end
|
|
|
|
local function on_gui_closed(event)
|
|
if event.gui_type == defines.gui_type.item
|
|
and event.item
|
|
and event.item.is_blueprint
|
|
and event.item.is_blueprint_setup()
|
|
then
|
|
global.previous_opened_blueprint_for[event.player_index] = {
|
|
blueprint = event.item,
|
|
tick = event.tick,
|
|
}
|
|
end
|
|
end
|
|
|
|
local function get_blueprint_to_setup(player_index)
|
|
local opened_blueprint = global.previous_opened_blueprint_for[player_index]
|
|
if opened_blueprint and opened_blueprint.tick == game.tick then
|
|
return opened_blueprint.blueprint
|
|
end
|
|
|
|
local player = game.players[player_index]
|
|
|
|
local blueprint_to_setup = player.blueprint_to_setup
|
|
if blueprint_to_setup
|
|
and blueprint_to_setup.valid_for_read then
|
|
return blueprint_to_setup
|
|
end
|
|
|
|
local cursor_stack = player.cursor_stack
|
|
if cursor_stack
|
|
and cursor_stack.valid_for_read
|
|
and cursor_stack.is_blueprint
|
|
and cursor_stack.is_blueprint_setup() then
|
|
return cursor_stack
|
|
end
|
|
end
|
|
|
|
local function on_blueprint(event)
|
|
local bp = get_blueprint_to_setup(event.player_index)
|
|
if not bp then return end
|
|
local player = game.players[event.player_index]
|
|
local entities = bp.get_blueprint_entities()
|
|
if not entities then return end
|
|
|
|
for _, bp_entity in pairs(entities) do
|
|
if bp_entity.name == "railloader-chest" or bp_entity.name == "railunloader-chest" then
|
|
local chest_entity = player.surface.find_entities_filtered{
|
|
type = "container",
|
|
position = bp_entity.position,
|
|
}[1]
|
|
if not chest_entity then goto continue end
|
|
|
|
local rail = player.surface.find_entities_filtered{
|
|
type = "straight-rail",
|
|
area = chest_entity.bounding_box,
|
|
}[1]
|
|
if not rail then goto continue end
|
|
|
|
bp_entity.name = (bp_entity.name == "railloader-chest")
|
|
and "railloader-placement-proxy"
|
|
or "railunloader-placement-proxy"
|
|
-- base direction on direction of rail
|
|
bp_entity.direction = rail.direction
|
|
-- preserve chest limit
|
|
bp_entity.tags = { bar = chest_entity.get_inventory(defines.inventory.chest).get_bar() }
|
|
end
|
|
::continue::
|
|
end
|
|
|
|
bp.set_blueprint_entities(entities)
|
|
end
|
|
|
|
local function on_setting_changed(event)
|
|
allowed_items_setting = settings.global["railloader-allowed-items"].value
|
|
inserter_config.on_setting_changed(event)
|
|
end
|
|
|
|
-- setup remotes
|
|
|
|
remote.add_interface("railloader", {
|
|
add_bulk_item = bulk.add_bulk_item,
|
|
add_bulk_item_pattern = bulk.add_bulk_item_pattern,
|
|
})
|
|
|
|
-- setup event handlers
|
|
|
|
script.on_init(on_init)
|
|
script.on_load(on_load)
|
|
script.on_configuration_changed(on_configuration_changed)
|
|
|
|
local es = defines.events
|
|
script.on_event({es.on_built_entity, es.on_robot_built_entity, es.script_raised_built, es.script_raised_revive}, on_built)
|
|
script.on_event({es.on_player_mined_entity, es.on_robot_mined_entity, es.script_raised_destroy}, on_mined)
|
|
script.on_event(es.on_robot_pre_mined, on_robot_pre_mined)
|
|
script.on_event(es.on_entity_died, on_mined)
|
|
script.on_event(es.on_post_entity_died, on_post_entity_died, {{filter = "type", type = "container"}})
|
|
|
|
script.on_event(es.on_gui_closed, on_gui_closed)
|
|
script.on_event(es.on_player_setup_blueprint, on_blueprint)
|
|
|
|
script.on_event(es.on_train_changed_state, inserter_config.on_train_changed_state)
|
|
|
|
script.on_event(defines.events.on_runtime_mod_setting_changed, on_setting_changed)
|