More Utilities

Things that we aren't going to implement
User avatar
ludsoe
Fast Inserter
Fast Inserter
Posts: 243
Joined: Tue Feb 11, 2014 8:16 am
Contact:

More Utilities

Post by ludsoe »

After talking to kovarex about a crash problem through PMs. He mentioned that some of the utilities I've develped for MoLogicCore included in MoMods. Should be part of the base game for performance reasons. I agree that some of the utilities should be part of the modding interface.
Timer System.
Entity Subscriptions.
User avatar
rk84
Filter Inserter
Filter Inserter
Posts: 556
Joined: Wed Feb 13, 2013 9:15 am
Contact:

Re: More Utilities

Post by rk84 »

I would like to have timer system. I also made one myself, not as neat looking as yours, I used sorted table to only check timer(s) with lowest tick.
Test mode
Searching Flashlight
[WIP]Fluid handling expansion
[WIP]PvP gamescript
[WIP]Rocket Express
Autofill: The torch has been pass to Nexela
User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: More Utilities

Post by FreeER »

Useful. A couple proposed suggestions/changes (that may or may not be better, up to other modders and the devs).

Timer.CreateTimer()
  • First, I propose that it uses (or is overloaded to use) a table instead of separate parameters. I suggest this because many of the other functions provided by Factorio take tables rather than a parameters list. (also, during code refactoring I might suggest making all functions conform to using a table (or other chosen standard), if they take more than one parameter. This could be discussed elsewhere however :))
  • Name: couldn't Factorio instead generate and return a timer object so a creation would look like myTimer=game.timers.createTimer(Length,Repeat,CallBack,Data) and you could then use myTimer.deleteTimer() and myTimer.timeLeft()
  • Length: first, I think 'duration' might be a better name...but more importantly is whether this should be specified in seconds or ticks (I would think ticks)
  • Repeat: perhaps instead of 0 and less being infinite repeat, negative (less than 0) would be infinite repeat and a repeat of 0 would be a 'run once and remove' timer. A value of 1 would repeat 1 time (so it'd run twice in total) and 2 would repeat twice, etc.
  • Repeat2: would it be possible to change the duration after the function is run (or from within it)? So that you could create a timer (at game start) that ran it's function after an hour, and then it's duration decreases to half an hour (and then to 20 minutes, and then 10, etc. and perhaps it could be killed (from the passed function) after running with a duration of 1 minute..)
  • Data: more of a question (for clarification) than a suggestion but, how would this work? I assume it would update the data before passing it to the function (or use a pointer/reference to the data), otherwise if you had a timer that sent x number of biters at the player every 20 minutes and the x was data being passed to the function you would have to remove the timer and recreate it to send a larger group of biters.
  • Timers.GetTimers(): with the change to the name, IF this only returned the mod's timers, would it even be needed?
Entity Subscriptions
  • Name: Factorio could return a generated ID (it would probably have to have one anyways), pretty much like it does for custom events now...Honestly I'm just not sure why you'd 'need' to name it :) Especially since it's based on entity types and not specific entities.
User avatar
ludsoe
Fast Inserter
Fast Inserter
Posts: 243
Joined: Tue Feb 11, 2014 8:16 am
Contact:

Re: More Utilities

Post by ludsoe »

FreeER wrote:
Snip
I guess using names isn't required, but its how I initially thought of the system. One of the reasons you want to name a timer is for simplicity sake, you'd just have to create the timer and you where it is. But that I imagine returning a timer object as-well as keeping the name system can be useful.
Regarding Timer duration("Length") I guess it can be measured in game ticks for exact tuning, but initially i was thinking it would take seconds. As for changing the duration of a running timer every-time it triggers, I imagine we can have another function that's called every time the timer renews. That returns the duration of the new timer. As for the extra data that's passed to the function I was picturing it would be sent in its purest form.
Copern
Burner Inserter
Burner Inserter
Posts: 10
Joined: Tue Jan 21, 2014 7:56 pm
Contact:

Re: More Utilities

Post by Copern »

I'll throw in my two cents and a different timer.

Like FreeER mentioned, "name" I really don't think is necessary. You'll likely get a reference and I can't think of a reason why you would need to "name" it. Again as FreeER mentioned, "duration" makes more sense as a variable name for the timer as when you see "length" you would think length of an array/list or other dimensional object. "Repeat" and "data" isn't actually needed either to be honest.

All we really need is two variables. Now instead of calling the time it runs for "length" or "duration", let's say it's the time between callback calls and name it "interval." We just need to pass in an interval and an action/callback. We can perform whatever actions we want in the callback, including changing the interval of the timer. The timer can even be available for GC after the timer runs out without further action from the user if no references are kept to it; there's no need to manually remove it. So how is that done? Well here's the timer.

Code: Select all

local Timer = {}

-- Creates a new Timer that acts in intervals
-- game: the main game object
-- timers: the table where timers are stored
-- interval: the time in ticks between actions
-- action: the ontick callback function
function Timer:new(game, timers, interval, action)
	if not action or type(action) ~= "function" then
		error("Timer action for ontick must be a function.")
	end
	local instance = {}
	local ticksleft
	local running = false
	local next = 0
	instance.ontick = action
	instance.interval = interval

	function instance:getnext()
		return next
	end

	function instance:isrunning()
		return running
	end

	-- Starts the timer from the beginning or from the time left if restarted without resetting
	function instance:start()
		if running or interval <= 0 then return end

		next = game.tick + (ticksleft or interval)
		ticksleft = nil
		running = true
		timers[self] = self
	end

	-- Stops the timer and stores the ticks left
	function instance:stop()
		if not running then return end

		ticksleft = next - game.tick
		running = false
		timers[self] = nil
	end

	-- Resets the timer
	function instance:reset()
		if running then
			next = game.tick + interval
		else
			ticksleft = nil
		end
	end

	return instance
end

return Timer
There are two other variables passed in to the timer creation (game and timers) but they can easily be removed, they are there for unit testing which I'll exclude for brevity. But let's keep those two there and assume we have this somewhere else.

Code: Select all

local Timer = require "lib/timer"
local timers = {}

game.onevent(defines.events.ontick, function(event)
	for _, timer in pairs(timers) do
		if timer.ontick and timer.interval > 0 then
			if game.tick >= timer:getnext() then
				timer:ontick()
				timer:reset()
			end
		else
			timer:stop()
		end
	end
end)

local createtimer = function(interval, action)
	return Timer:new(game, timers, interval, action)
end
Now for some actual examples.
Examples
This is how I prefer a Timer work at least. You're of course free to use this in your own projects if you wish, all I ask is a little credit. It would be nice to see something like this built into the game of course.
Last edited by Copern on Mon Mar 31, 2014 1:23 pm, edited 1 time in total.
User avatar
ssilk
Global Moderator
Global Moderator
Posts: 12889
Joined: Tue Apr 16, 2013 10:35 pm
Contact:

Re: More Utilities

Post by ssilk »

This is more ore less also the preferred method how it's done in other programming languages.
Cool suggestion: Eatable MOUSE-pointers.
Have you used the Advanced Search today?
Need help, question? FAQ - Wiki - Forum help
I still like small signatures...
Post Reply

Return to “Won't implement”