Page 1 of 1
Hooking a non-logistic entity up to the logistics network
Posted: Mon Sep 04, 2017 10:38 pm
by Alex99
Lets say you have a regular burner furnace entity. How would one go about adding that to the logistics network as a requester, then having it always request 10 coal that would go into it's fuel and have the player be unable to modify this request.
Thanks in advance
Re: Hooking a non-logistic entity up to the logistics network
Posted: Tue Sep 05, 2017 12:58 am
by DaveMcW
Code: Select all
/c
request_fuel = function(entity)
if not entity or entity.type ~= "furnace" then return end
local item = "coal"
local add_more = true
for fuel,amount in pairs(entity.get_inventory(defines.inventory.fuel).get_contents()) do
if amount < 10 then
item = fuel
else
add_more = false
end
end
if add_more and entity.surface.count_entities_filtered{name="item-request-proxy", force=entity.force, area=entity.bounding_box} == 0 then
entity.surface.create_entity{name="item-request-proxy", target=entity, force=entity.force, position=entity.position, modules={{item=item, count=10}}}
end
end
request_fuel(game.player.selected)
This adds a temporary request for a single furnace. You need to add more logic to always update every furnace on the map.
Re: Hooking a non-logistic entity up to the logistics network
Posted: Tue Sep 05, 2017 1:43 am
by Alex99
DaveMcW wrote:Code: Select all
/c
request_fuel = function(entity)
if not entity or entity.type ~= "furnace" then return end
local item = "coal"
local add_more = true
for fuel,amount in pairs(entity.get_inventory(defines.inventory.fuel).get_contents()) do
if amount < 10 then
item = fuel
else
add_more = false
end
end
if add_more and entity.surface.count_entities_filtered{name="item-request-proxy", force=entity.force, area=entity.bounding_box} == 0 then
entity.surface.create_entity{name="item-request-proxy", target=entity, force=entity.force, position=entity.position, modules={{item=item, count=10}}}
end
end
request_fuel(game.player.selected)
This adds a temporary request for a single furnace. You need to add more logic to always update every furnace on the map.
Thanks for the answer
So if I understand this correctly this creates a ghost entity that requires 10 coal to be constructed? then that coal is transferred into the furnace in question.
Also is there any way to use logistic bots instead of construction?
Re: Hooking a non-logistic entity up to the logistics network
Posted: Tue Sep 05, 2017 1:59 am
by DaveMcW
Alex99 wrote:Also is there any way to use logistic bots instead of construction?
Not easily. The only way is to create a hidden logistic entity that requests coal (see defines.events.on_built_entity), then code to transfer it to your furnace.
Re: Hooking a non-logistic entity up to the logistics network
Posted: Tue Sep 05, 2017 2:08 am
by Alex99
DaveMcW wrote:Not easily. The only way is to create a hidden logistic entity that requests coal (see defines.events.on_built_entity), then code to transfer it to your furnace.
OK I think I can do that, is there an event that I could use that isn't on_tick as that would be pretty bad for ups?
Re: Hooking a non-logistic entity up to the logistics network
Posted: Tue Sep 05, 2017 8:11 am
by bobingabout
No, something that is constantly updated must be on the on_tick event. This is one reason why I personally do not include features of this nature in my mods.
There are however some guides around on how to attempt to offset the UPS disruption, such as only checking each chest for requests once a minute, but iterate through this list so that something is checked every tick.
something like
Code: Select all
for i, entity in pairs(list) do
if game.tick % 3600 == i % 3600 do
Re: Hooking a non-logistic entity up to the logistics network
Posted: Tue Sep 05, 2017 1:10 pm
by Optera
bobingabout wrote:No, something that is constantly updated must be on the on_tick event. This is one reason why I personally do not include features of this nature in my mods.
There are however some guides around on how to attempt to offset the UPS disruption, such as only checking each chest for requests once a minute, but iterate through this list so that something is checked every tick.
something like
Code: Select all
for i, entity in pairs(list) do
if game.tick % 3600 == i % 3600 do
modulo is expensive in to run twice for every entity every tick.
It's better to run it only once:
Code: Select all
function OnTick(event)
local tick = game.tick
for i=1, #global.VoidChests do
if (i + tick) % update_interval == 0 then
global.VoidChests[i].get_inventory(defines.inventory.chest).clear()
end
end
end
Even better, don't iterate over the whole array every tick instead step through it a few entites each tick spread out over whatever update cycle you choose.
I've benchmarked that to be 40% faster than above snippet in
Void Chest +.
Code: Select all
function OnTick(event)
global.tickCount = global.tickCount or 1
global.chestIndex = global.chestIndex or 1
-- only work if index is within bounds
if global.chestIndex <= #global.VoidChests then
local stopIndex = global.chestIndex + global.VoidChestStride - 1
if stopIndex >= #global.VoidChests then
stopIndex = #global.VoidChests
end
-- log("[VCP] "..global.tickCount.." / "..game.tick.." clearing chest ids "..global.chestIndex.." to "..stopIndex)
for i=global.chestIndex, stopIndex do
global.VoidChests[i].get_inventory(defines.inventory.chest).clear()
end
global.chestIndex = stopIndex + 1
end
-- reset clock and chest index
if global.tickCount < update_interval then
global.tickCount = global.tickCount + 1
else
global.tickCount = 1
global.chestIndex = 1
end
end
Re: Hooking a non-logistic entity up to the logistics network
Posted: Wed Sep 06, 2017 9:57 am
by eradicator
Optera wrote:
I've benchmarked that to be 40% faster than above snippet in Void Chest +
The last time i tried to to a tick-distrubuted update i used a construct like this:
Code: Select all
local UPDATEDELAY = 60
local function on_tick(event)
local tock = tick % UPDATEDELAY
for index=#global.mystuff-tock,1,-1*UPDATEDELAY do
--stuff
end
end
Features:
- one modulo per tick
- only loops through entities that are actually updated
- updates all entities in a fixed time window (aka does not get slower with more entities)
- (con) if new entites are constructed during an updatecycle some will be skipped until the next cycle
It basically walks backwards through the array (because sometimes i need to delete stuff if it becomes invalid, and forward walking screws up the index in that case) and updates every n-th entity.
I only did some very short tests tho as in my case with very few entities (entity_count < UPDATEDELAY) the numbers seemed to suggest that doing them in bulk every n seconds was faster.
Re: Hooking a non-logistic entity up to the logistics network
Posted: Wed Sep 06, 2017 1:03 pm
by Optera
eradicator wrote:Optera wrote:
I've benchmarked that to be 40% faster than above snippet in Void Chest +
The last time i tried to to a tick-distrubuted update i used a construct like this:
Code: Select all
local UPDATEDELAY = 60
local function on_tick(event)
local tock = tick % UPDATEDELAY
for index=#global.mystuff-tock,1,-1*UPDATEDELAY do
--stuff
end
end
Features:
- one modulo per tick
- only loops through entities that are actually updated
- updates all entities in a fixed time window (aka does not get slower with more entities)
- (con) if new entites are constructed during an updatecycle some will be skipped until the next cycle
It basically walks backwards through the array (because sometimes i need to delete stuff if it becomes invalid, and forward walking screws up the index in that case) and updates every n-th entity.
I only did some very short tests tho as in my case with very few entities (entity_count < UPDATEDELAY) the numbers seemed to suggest that doing them in bulk every n seconds was faster.
That's a nifty way of stepping with stride.
Benchmark results for 480 Void chests using either version as on_tick over 100k ticks:
My current version: avg 11805.281 ms
Your version: avg 11776.126ms
Conclusion:
Your version is 0.25% faster in this benchmark. Both versions may be too fast to be accurately benchmarked with "only" 480 void Chests.
Overall I'd say the wiki should be updated to use your version. It's far more simplistic and unless you have to call different functions depending on accurate execution order your stepping with stride will work perfectly fine.
Re: Hooking a non-logistic entity up to the logistics network
Posted: Wed Sep 06, 2017 1:19 pm
by Bilka
Optera wrote:
Overall I'd say the wiki should be updated to use your version. It's far more simplistic and unless you have to call different functions depending on accurate execution order your stepping with stride will work perfectly fine.
Which wiki (page) talks about this?
Re: Hooking a non-logistic entity up to the logistics network
Posted: Wed Sep 06, 2017 2:31 pm
by Optera
Bilka wrote:Optera wrote:
Overall I'd say the wiki should be updated to use your version. It's far more simplistic and unless you have to call different functions depending on accurate execution order your stepping with stride will work perfectly fine.
Which wiki (page) talks about this?
Well if there isn't a guide or wiki page about how to properly create an on_tick handler there should be one.
I've seen way too many mods wasting a ton of performance due to bad on_tick iteration.
Re: Hooking a non-logistic entity up to the logistics network
Posted: Thu Sep 07, 2017 7:42 am
by eradicator
Optera wrote:
That's a nifty way of stepping with stride.
Benchmark results for 480 Void chests using either version as on_tick over 100k ticks:
My current version: avg 11805.281 ms
Your version: avg 11776.126ms
Thanks (also for the numbers). It's amazing that the difference would be so tiny despite your frequent access to the global table for index management. I guess my intuition about what is expensive and what isn't is pretty bad
. Also btw in your code i think you can call .clear_items_inside() directly on the chest entity, which should save the get_inventory call and thus the passing of another reference object over the c++/lua barrier.
Re: Hooking a non-logistic entity up to the logistics network
Posted: Thu Sep 07, 2017 10:56 am
by Optera
eradicator wrote:
Thanks (also for the numbers). It's amazing that the difference would be so tiny despite your frequent access to the global table for index management. I guess my intuition about what is expensive and what isn't is pretty bad
. Also btw in your code i think you can call .clear_items_inside() directly on the chest entity, which should save the get_inventory call and thus the passing of another reference object over the c++/lua barrier.
Thanks, I didn't even know a shortcut like clear_items_inside() existed.
Using that instead of get_inventory(defines.inventory.chest).clear() made a much more noticeable difference than the on_tick handlers.
clear_items_inside(): avg 10162.627 ms ~13% faster
I'm surprised how close they are together myself, but then again the slowest part in any of my mods is read or write to entities through the API.
Re: Hooking a non-logistic entity up to the logistics network
Posted: Thu Sep 07, 2017 2:22 pm
by Nexela
Want it to be even faster? Save the inventory and work directly on that
global.chest = {ent = ent, inv = ent.get_inventory(defines.inventory.chest)}
global.chest.inv.clear()