Aleksei-bird 7c9c708c92 Первый фикс
Пачки некоторых позиций увеличены
2024-03-01 20:54:33 +03:00

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