script.once_at_tick as a specialized offspring of script.on_nth_tick

Place to ask discuss and request the modding support of Factorio. Don't request mods here.
Post Reply
Quezler
Burner Inserter
Burner Inserter
Posts: 11
Joined: Fri Mar 25, 2016 6:37 pm
Contact:

script.once_at_tick as a specialized offspring of script.on_nth_tick

Post by Quezler »

Cleaned up summary of a recent factorio discord discussion: https://discord.com/channels/1396775903 ... 2641071205

Whilst i do see value in this myself, i doubt i'll be able to convince someone at wube of its usefulness, just posting this here because i got "challenged" to :)

The idea is near the bottom, with 2 current/alternative ways of doing it posted between here and there:

Difficulty level 1: Scheduling something via script.on_tick

This works and accomplishes the task, however the lua handler runs every tick, not very practical if you only have something to schedule occasionally.

Code: Select all

global.task_for_tick = {}
...
global.task_for_tick[tick] = 'some task'
...
script.on_tick(function (event)
  if global.task_for_tick[tick] then
    -- do the task
    global.task_for_tick[tick] = nil
  end
end)
Difficulty level 2: Scheduling something via script.on_nth_tick

Register the handler to only run for the ticks you want tasks to run in, comes with a little managerial overhead, as well as requiring proper on_load handling.

Code: Select all

global.task_for_tick = {}
...
global.task_for_tick[tick] = 'some task'
script.on_nth_tick(tick, handler)
...
function handler(event)
  if global.task_for_tick[tick] then
    -- do the task
    global.task_for_tick[tick] = nil
    script.on_nth_tick(tick, nil)
  end
end
...
script.on_load(function (event)
  for tick, _ in pairs(global.task_for_tick) do
    script.on_nth_tick(tick, handler)
  end
end)
Difficulty level 3: Scheduling something via script.once_at_tick

The script interface i am proposing:
- you will not need to un-register in the handler to prevent it from running on a future modulus tick, since it unregisters itself automatically
- scheduling on the same tick as an on_nth_tick will not cause that handler to reset
- trying to register a handler for the current or a previous tick should fail, should also quickly expose any flaws in the on_load handler
- might be a little too advanced for most, since unlike using on_nth_tick as a cronjob requires management of global & knowledge of on_load
- uses == instead of % to determine on the c++ side whether or not to trigger the lua handler (instead of e.g. doing it from within lua's on_tick)

I do understand that it is possible to emulate the above using on_nth_tick just fine, this would just be a "cleaner shortcut" for scheduling, which in theory should be better for performance in marginally small amounts (no task checks every tick in lua, and not running a modulus for each scheduled on_nth_tick)

Code: Select all

global.task_for_tick = {}
...
global.task_for_tick[tick] = 'some task'
script.once_at_tick(tick, handler)
...
function handler(event)
  if global.task_for_tick[tick] then
    -- do the task
    global.task_for_tick[tick] = nil
  end
end
...
script.on_load(function (event)
  for tick, _ in pairs(global.task_for_tick) do
    script.once_at_tick(tick, handler)
  end
end)
Thanks for reading 🥔

User avatar
Deadlock989
Smart Inserter
Smart Inserter
Posts: 2528
Joined: Fri Nov 06, 2015 7:41 pm

Re: script.once_at_tick as a specialized offspring of script.on_nth_tick

Post by Deadlock989 »

I wanted this so badly that I wrote a version of it myself. My use case was to "schedule" things for N ticks in the future where N was typically not long, i.e. typically 10 to 120 ticks in the future - but in theory a lot of of them could be scheduled at once. The way I got happy with it performance-wise was to unregister the tick handler if there is nothing in the queue. In that scenario, 99.9% of the time in a typical game there is no overhead from running schedules, and the overhead for the other 0.1% is very minimal.

It is not a huge amount of code.
Image

User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5206
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: script.once_at_tick as a specialized offspring of script.on_nth_tick

Post by eradicator »

My library uses exactly the same abbroach as deadlock says (including unregister when not in use) because I was also sorely missing it. Takes the target tick, method name and (a table of) paramters (without paramters it would be useless imho because of cases where the same handler happens multiple times a tick and order is important). I think I originally made it because there's a bunch of things that need a 1 tick delay due to processing order of factorios engine.

https://lossycrypt.github.io/eradicator ... on.enqueue
(Library is unmaintaind, link is just for reference not actual use.)

Post Reply

Return to “Modding interface requests”