222 lines
7.9 KiB
Lua
222 lines
7.9 KiB
Lua
--[[ Copyright (c) 2018 Optera
|
|
* Part of LTN Content Reader
|
|
*
|
|
* See LICENSE.md in the project directory for license information.
|
|
--]]
|
|
|
|
-- localize often used functions and strings
|
|
local match = string.match
|
|
local format = string.format
|
|
local match_string = "([^,]+),([^,]+)"
|
|
local btest = bit32.btest
|
|
local signal_network_id = {type="virtual", name="ltn-network-id"}
|
|
local content_readers = {
|
|
["ltn-provider-reader"] = {table_name = "ltn_provided"},
|
|
["ltn-requester-reader"] = {table_name = "ltn_requested"},
|
|
["ltn-delivery-reader"] = {table_name = "ltn_deliveries"},
|
|
}
|
|
|
|
-- get default network from LTN
|
|
local default_network = settings.global["ltn-stop-default-network"].value
|
|
script.on_event(defines.events.on_runtime_mod_setting_changed, function(event)
|
|
if not event then return end
|
|
if event.setting == "ltn-stop-default-network" then
|
|
default_network = settings.global["ltn-stop-default-network"].value
|
|
end
|
|
end)
|
|
|
|
-- LTN interface event functions
|
|
function OnStopsUpdated(event)
|
|
--log("Stop Data:"..serpent.block(event.data) )
|
|
global.ltn_stops = event.logistic_train_stops or {}
|
|
end
|
|
|
|
|
|
function OnDispatcherUpdated(event)
|
|
-- ltn provides data per stop, aggregate over network and item
|
|
global.ltn_provided = {}
|
|
global.ltn_requested = {}
|
|
global.ltn_deliveries = {}
|
|
|
|
-- event.provided_by_stop = { [stopID], { [item], count } }
|
|
for stopID, items in pairs(event.provided_by_stop) do
|
|
local network_id = global.ltn_stops[stopID] and global.ltn_stops[stopID].network_id
|
|
if network_id then
|
|
global.ltn_provided[network_id] = global.ltn_provided[network_id] or {}
|
|
for item, count in pairs(items) do
|
|
global.ltn_provided[network_id][item] = (global.ltn_provided[network_id][item] or 0) + count
|
|
end
|
|
end
|
|
end
|
|
|
|
-- event.requests_by_stop = { [stopID], { [item], count } }
|
|
for stopID, items in pairs(event.requests_by_stop) do
|
|
local network_id = global.ltn_stops[stopID] and global.ltn_stops[stopID].network_id
|
|
if network_id then
|
|
global.ltn_requested[network_id] = global.ltn_requested[network_id] or {}
|
|
for item, count in pairs(items) do
|
|
global.ltn_requested[network_id][item] = (global.ltn_requested[network_id][item] or 0) - count
|
|
end
|
|
end
|
|
end
|
|
|
|
-- event.deliveries = { trainID = {force, train, from, to, network_id, started, shipment = { item = count } } }
|
|
for trainID, delivery in pairs(event.deliveries) do
|
|
if delivery.network_id then
|
|
global.ltn_deliveries[delivery.network_id] = global.ltn_deliveries[delivery.network_id] or {}
|
|
for item, count in pairs(delivery.shipment) do
|
|
global.ltn_deliveries[delivery.network_id][item] = (global.ltn_deliveries[delivery.network_id][item] or 0) + count
|
|
end
|
|
end
|
|
end
|
|
|
|
-- event.update_interval = LTN update interval (depends on existing ltn stops and stops per tick setting
|
|
global.update_interval = event.update_interval
|
|
end
|
|
|
|
-- spread out updating combinators
|
|
function OnTick(event)
|
|
-- global.update_interval LTN update interval are synchronized in OnDispatcherUpdated
|
|
local offset = event.tick % global.update_interval
|
|
local cc_count = #global.content_combinators
|
|
for i=cc_count - offset, 1, -1 * global.update_interval do
|
|
-- log( "("..tostring(event.tick)..") on_tick updating "..i.."/"..cc_count )
|
|
local combinator = global.content_combinators[i]
|
|
if combinator.valid then
|
|
Update_Combinator(combinator)
|
|
else
|
|
table.remove(global.content_combinators, i)
|
|
if #global.content_combinators == 0 then
|
|
script.on_event(defines.events.on_tick, nil)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function Update_Combinator(combinator)
|
|
-- get network id from combinator parameters
|
|
local first_signal = combinator.get_control_behavior().get_signal(1)
|
|
local max_signals = combinator.get_control_behavior().signals_count
|
|
local selected_network_id = default_network
|
|
|
|
if first_signal and first_signal.signal and first_signal.signal.name == "ltn-network-id" then
|
|
selected_network_id = first_signal.count
|
|
else
|
|
log(format("Error: combinator must have ltn-network-id set at index 1. Setting network id to %s.", default_network) )
|
|
end
|
|
|
|
local signals = { { index = 1, signal = signal_network_id, count = selected_network_id } }
|
|
local index = 2
|
|
|
|
-- for many signals performance is better to aggregate first instead of letting factorio do it
|
|
local items = {}
|
|
local reader = content_readers[combinator.name]
|
|
if reader then
|
|
for network_id, item_data in pairs(global[reader.table_name]) do
|
|
if btest(selected_network_id, network_id) then
|
|
for item, count in pairs(item_data) do
|
|
items[item] = (items[item] or 0) + count
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- generate signals from aggregated item list
|
|
for item, count in pairs(items) do
|
|
local itype, iname = match(item, match_string)
|
|
if itype and iname and (itype == "item" and game.item_prototypes[iname] or itype == "fluid" and game.fluid_prototypes[iname]) then
|
|
if max_signals >= index then
|
|
if count > 2147483647 then count = 2147483647 end
|
|
if count < -2147483648 then count = -2147483648 end
|
|
signals[#signals+1] = {index = index, signal = {type=itype, name=iname}, count = count}
|
|
index = index+1
|
|
else
|
|
log("[LTN Content Reader] Error: signals in network "..selected_network_id.." exceed "..max_signals.." combinator signal slots. Not all signals will be displayed.")
|
|
break
|
|
end
|
|
end
|
|
end
|
|
combinator.get_control_behavior().parameters = signals
|
|
|
|
end
|
|
|
|
|
|
-- add/remove event handlers
|
|
function OnEntityCreated(event)
|
|
local entity = event.created_entity
|
|
if content_readers[entity.name] then
|
|
-- if not set use default network id
|
|
local first_signal = entity.get_control_behavior().get_signal(1)
|
|
if not (first_signal and first_signal.signal and first_signal.signal.name == "ltn-network-id") then
|
|
entity.get_or_create_control_behavior().parameters = {{ index = 1, signal = signal_network_id, count = default_network }}
|
|
end
|
|
|
|
table.insert(global.content_combinators, entity)
|
|
|
|
if #global.content_combinators == 1 then
|
|
script.on_event(defines.events.on_tick, OnTick)
|
|
end
|
|
end
|
|
end
|
|
|
|
function OnEntityRemoved(event)
|
|
local entity = event.entity
|
|
if content_readers[entity.name] then
|
|
for i=#global.content_combinators, 1, -1 do
|
|
if global.content_combinators[i].unit_number == entity.unit_number then
|
|
table.remove(global.content_combinators, i)
|
|
end
|
|
end
|
|
|
|
if #global.content_combinators == 0 then
|
|
script.on_event(defines.events.on_tick, nil)
|
|
end
|
|
end
|
|
end
|
|
|
|
---- Initialisation ----
|
|
do
|
|
local function init_globals()
|
|
global.ltn_stops = global.ltn_stops or {}
|
|
global.ltn_provided = global.ltn_provided or {}
|
|
global.ltn_requested = global.ltn_requested or {}
|
|
global.ltn_deliveries = global.ltn_deliveries or {}
|
|
global.content_combinators = global.content_combinators or {}
|
|
global.update_interval = global.update_interval or 60
|
|
|
|
-- remove unused globals froms save
|
|
global.last_update_tick = nil
|
|
global.ltn_contents = nil
|
|
global.stop_network_ID = nil
|
|
end
|
|
|
|
local function register_events()
|
|
-- register events from LTN
|
|
if remote.interfaces["logistic-train-network"] then
|
|
script.on_event(remote.call("logistic-train-network", "on_stops_updated"), OnStopsUpdated)
|
|
script.on_event(remote.call("logistic-train-network", "on_dispatcher_updated"), OnDispatcherUpdated)
|
|
end
|
|
|
|
-- register game events
|
|
script.on_event({defines.events.on_built_entity, defines.events.on_robot_built_entity}, OnEntityCreated)
|
|
script.on_event({defines.events.on_pre_player_mined_item, defines.events.on_robot_pre_mined, defines.events.on_entity_died}, OnEntityRemoved)
|
|
if #global.content_combinators > 0 then
|
|
script.on_event(defines.events.on_tick, OnTick)
|
|
end
|
|
end
|
|
|
|
|
|
script.on_init(function()
|
|
init_globals()
|
|
register_events()
|
|
end)
|
|
|
|
script.on_configuration_changed(function(data)
|
|
init_globals()
|
|
register_events()
|
|
end)
|
|
|
|
script.on_load(function(data)
|
|
register_events()
|
|
end)
|
|
end |