PDA

View Full Version : Timer



mattekure
June 2nd, 2022, 18:30
This extension adds a timer capability into FG. While the extension may be useful for some purely for its timer function, it is also intended for other extension authors which can tie into the timer system. The inspiration for this came from the Combat Timer extension, but its implementation is entirely different, so it doesnt have the same limitations of that method, though it does have its own set of limitations as detailed below.

Forge: https://forge.fantasygrounds.com/shop/items/665/view

Details
Description: This extension uses the recently added Interface.openURL() function to create an internal counter. It uses the worldtimeapi.org functionality to retrieve the time and increment the timer. Due to the asynchronous nature of that function call, it is possible to recursively call it without much impact to FG performance. The counter has a resolution of 1 second. When the timer is started, it continuously counts up. There is a button in the sidebar to open the timer window. The timer will continue running even if the window is closed. You can also start/stop the timer using the slash command /timer [start|stop]

Caveats: The counter running is heavily dependant on the hosts network stability. While it does not add much CPU usage to FG, in my testing it did use about 500kbps of network bandwidth constantly. The timer may unexpectedly stop if there is network instability or issues with the worldtimeapi.org site. In my testing, I have had it running successfully for over 3 hours. I have also had it stop in a few as 5 minutes, so YMMV. There is nothing sent to/from FG clients connected, so all of the network traffic occurs on the host side.

Extension Authors
One of my goals in creating this extension is to make it useful for other extension authors to have a way to hook into a timer. For that reason, I am leaving it installed to the extensions directory so anyone can take a look at how I made it. I have also included an API to hook into the timers. At any time, there should only ever be 1 timer running. For other extensions, they should use the register/unregister api functions below to hook into the running timer.

If anyone has any suggestions for improving it, I'd love to hear it.

API Functions
TimerManager.startTimer() - Begins the timer.
Parameters: none
Return Value: none

TimerManager.stopTimer() - Stops the timer
Parameters: None
Return Value: None

TimerManager.registerTimerAction(fn, delay) - Register a callback function to occur when the timer updates its value. (I typically register this in a windows onInit())
Parameters:
fn - The function to call
delay - An integer number of seconds between calls. Min 1. A value of 1 will call the registered callback function once per second. a value of 2 will occur every 2 seconds, etc.
Return Value: none

TimerManager.unregisterTimerAction(fn, delay) - Unregister a previously registered function. If you have functions registered by a window, I highly recommend to unregister all actions when the window is closed to avoid having old or unlinked entries in the callback list. Examples in the timerwindow in the extension. the parameters must match exactly for it to unregister properly.
Parameters:
fn - the function previously registered.
delay - the delay value previously registered.

TimerManager.outputTime(nTime) - Output the current timer value in HRS:MIN:SEC to the chat.

mattekure
June 2nd, 2022, 18:41
v1.5 - Incorporated code and included script from user JustinFreitas. Many thanks for the additions. Now includes a turn timer option. You can output the amount of time it takes for a user to take their turn in combat. It begins counting when their turn starts, and when they pass their turn, the time elapsed is output to chat. Can be disabled in the options.

Also, now adds the option to use a local URL instead of the default built in one. If the option to use a local URL is selected, it will attempt to use "http://localhost:1803/" to run the timer. In order to use this option, you need to have a timer script running on your local machine. Attached to this post is a script which can do this. This script requires Node.js be installed. Once downloaded and extracted, it can be run via Node with the command 'node delayed-response.js'.

YAKO SOMEDAKY
June 3rd, 2022, 09:38
What's the idea behind the Timer extension, is it enabling and disabling effects? Is it to control day and night effect on a map, is it to make the lighting resources fade automatically? I ask and quote this and even mention a Foundry module that seems possible in the FGU which is a kind of Timer where the Master sets the time, sets the speed of this Timer and then doesn't worry if the player forgot or not to deactivate the armor arcana of your character, if the character's Torch is still illuminating and even if it's day or night after a long journey from one realm to another realm and yes I think that's amazing and I believe the FGU can have that.

mattekure
June 3rd, 2022, 12:34
What's the idea behind the Timer extension, is it enabling and disabling effects? Is it to control day and night effect on a map, is it to make the lighting resources fade automatically? I ask and quote this and even mention a Foundry module that seems possible in the FGU which is a kind of Timer where the Master sets the time, sets the speed of this Timer and then doesn't worry if the player forgot or not to deactivate the armor arcana of your character, if the character's Torch is still illuminating and even if it's day or night after a long journey from one realm to another realm and yes I think that's amazing and I believe the FGU can have that.

Without getting into the technical details of why and how, the extension adds a new functionality that did not exist in FG before, the ability to set a running timer and have events fire on some set schedule. I deliberately made it so that other extensions could hook into the timer capabilities so that they can do all kinds of fancy stuff, that go way beyond the scope of this extension.

YAKO SOMEDAKY
June 3rd, 2022, 13:20
So in theory can I use it with the Clock Adjuster?

mattekure
June 3rd, 2022, 14:15
So in theory can I use it with the Clock Adjuster?

If the author adds the hooks, yes.

DustyLensCap42
January 28th, 2023, 18:15
I'm looking to track time on turns, and I've developed another extension to interact with your added hooks. It simply restarts the time at as the combat tracker moves through the characters (PC & NPC). Is there a reason why it reaches out to a website rather than using the lua function os.date (https://www.lua.org/manual/5.1/manual.html#pdf-os.date)? Feels like it might be more efficient for my purposes in that it wouldn't use the 500kbps, but I'm new to lua and I've never created an extension before. I am but a mere coding hobbyist. It'll take me a bit to try and change it out to test it, so I thought I'd ask. Because I know date functions in some coding applications can be dangerous to system resources if they're calling a time function constantly.

Thank you so much for putting out this extension mattekure!

mattekure
January 28th, 2023, 19:38
I'm looking to track time on turns, and I've developed another extension to interact with your added hooks. It simply restarts the time at as the combat tracker moves through the characters (PC & NPC). Is there a reason why it reaches out to a website rather than using the lua function os.date (https://www.lua.org/manual/5.1/manual.html#pdf-os.date)? Feels like it might be more efficient for my purposes in that it wouldn't use the 500kbps, but I'm new to lua and I've never created an extension before. I am but a mere coding hobbyist. It'll take me a bit to try and change it out to test it, so I thought I'd ask. Because I know date functions in some coding applications can be dangerous to system resources if they're calling a time function constantly.

Thank you so much for putting out this extension mattekure!

Certainly. The reason for the website usage is touched upon briefly in the description. Basically it would be very simple to use a function like os.clock or os.date to get the time, but this creates a problem. Typically using a function like this would require some form of loop to check the time, see how much has passed, then check again. Lua doenst have any available functions for waiting or delaying anything, so you cant just say "wait for 1 second". So you end up looping. The major problem with looping like this is that your function isnt returning, so the rest of the FG code on that thread is not being run. This basically causes the rest of FG to come to a grinding halt.

FG does however offer 2 asynchronous functions, meaning that using them allows them to run, but the rest of FG continues to run on its own thread. The two functions are sending an Out of Band (OOB) message and sending a request for a URL. Both of these functions rely on waiting for something else to respond, so FG allows them to fire and continue the processing thread while it waits for a response. When the response arrives, it gets processed in its own separate thread. This allows the clock to run without impacting the rest of FG. So basically it works like this.

Start timer
Timer requests the time from the website and immediately returns allowing FG to run.
When the website returns with the time, it records it, then immediately calls the web function again. starting a loop that we use to track the time.

without the web calls, FG would lock up or you wouldnt be able to keep the timer running.

DustyLensCap42
February 1st, 2023, 04:50
Okay cool, thanks so much for taking the time to give a good explanation! I'm going to play with sending it to a third-party timekeeper with a delay function like the website but is a local file, maybe HTML, pulling data from the os clock. Thanks again.

DustyLensCap42
September 11th, 2023, 23:43
With this extension, I've made another extension that resets the timer when the Next Actor button is pressed in the combat trackers. It's called TurnTimer. With it and Mattekure's Timer, you can actively track the duration of the current turn. I have a few players in 5e that love to absolutely optimize every turn. Sometimes taking more than 20 minutes for them to take their first action on their turn. I tried pushing them for a quicker decision without imposing a homebrewed rule and it led to some players feeling frustrated at my nagging them to decide. So I homebrewed that they get a base minimum of 30 seconds plus 20 seconds for every +1 to intelligence in combat turns to declare their first action or lose your turn. I am lax on it in more complex scenarios. For the most part, it's been great. No one has lost a turn, they're just far quicker to decide. And more proactively pay attention between turns. My games move so much faster, and the optimizers love the mechanical aspect of it. Thanks to Mattekure for the base extension. You will need both Timer.ext and TurnTimer.ext turned on for it to work.
Dropbox link: https://www.dropbox.com/scl/fi/6cz8ipbvdjazpsa55ipmt/TurnTimer.ext?rlkey=syq1xvg2cbslbr1142ahmycwl&dl=0

mattekure
September 11th, 2023, 23:45
With this extension, I've made another extension that resets the timer when the Next Actor button is pressed in the combat trackers. It's called TurnTimer. With it and Mattekure's Timer, you can actively track the duration of the current turn. I have a few players in 5e that love to absolutely optimize every turn. Sometimes taking more than 20 minutes for them to take their first action on their turn. I tried pushing them for a quicker decision without imposing a homebrewed rule and it led to some players feeling frustrated at my nagging them to decide. So I homebrewed that they get a base minimum of 30 seconds plus 20 seconds for every +1 to intelligence in combat turns to declare their first action or lose your turn. I am lax on it in more complex scenarios. For the most part, it's been great. No one has lost a turn, they're just far quicker to decide. And more proactively pay attention between turns. My games move so much faster, and the optimizers love the mechanical aspect of it. Thanks to Mattekure for the base extension. You will need both Timer.ext and TurnTimer.ext turned on for it to work.

Awesome, this sounds great!

JustinFreitas
October 16th, 2023, 22:24
Thanks for including my 1.5 changes! I've been loving the extension for tracking my player's turn times, so I was excited about the opportunity to contribute to the project. Lemme know if you ever need anything else! Thanks Again, Justin

Arnagus
October 17th, 2023, 06:39
Have you seen/are you aware of any other extensions (than TurnTime) which make use of the timer? I am rather looking for the opposite: my players are discussing at length outside of combat and I would love the clock the progress at the same time (or perhaps double speed). So time progresses outside turn based combat and can be stopped when turn based combat starts. Still need to jump ahead (using ClockAdjuster) from time to time, but a baseline progress would be helpful.

mattekure
October 17th, 2023, 13:24
Have you seen/are you aware of any other extensions (than TurnTime) which make use of the timer? I am rather looking for the opposite: my players are discussing at length outside of combat and I would love the clock the progress at the same time (or perhaps double speed). So time progresses outside turn based combat and can be stopped when turn based combat starts. Still need to jump ahead (using ClockAdjuster) from time to time, but a baseline progress would be helpful.

You can use the timer to track time on its own, without using the turn timer. Just open the timer using the button in the top right and click start. it will run the timer and you can see how much time has elapsed.

Arnagus
October 17th, 2023, 20:02
You can use the timer to track time on its own, without using the turn timer. Just open the timer using the button in the top right and click start. it will run the timer and you can see how much time has elapsed.
Sure, that's pretty much how I currently do it. Just hoping for an integration which advances the internal (campaign) clock.

SieferSeesSomething
January 3rd, 2024, 00:58
Hey mattekure, do you know what I might be doing wrong with hooking up a function to the timer? Do I need to use specific parameter names or something?

I put this in the onInit function:

TimerManager.registerTimerAction("onTimerUpdate", 2);

Then I have this function:

function onTimerUpdate(nCurrentTimerSeconds, tExtraParams)
if not Session.IsHost then
return;
end

Debug.console("ExtensionTutorial.onTimerUpdate - Current Timer Seconds", nCurrentTimerSeconds);
end

Once I start the timer and it hits 2 seconds, I get this error in the console log instead of the debug statement that should say the current timer seconds:

[ERROR] Script execution error: [string "Timer:TimerManager.lua"]:127:attempt to call a field '?' (a string value)

mattekure
January 3rd, 2024, 01:37
Hey mattekure, do you know what I might be doing wrong with hooking up a function to the timer? Do I need to use specific parameter names or something?

I put this in the onInit function:


Then I have this function:


Once I start the timer and it hits 2 seconds, I get this error in the console log instead of the debug statement that should say the current timer seconds:

You are passing the wrong argument to the registerTimerAction. you need to pass the function as the first parameter, not the name of the function in a string.

so from your code, remove the quotes around the function name so its actually passing the function reference.


TimerManager.registerTimerAction(onTimerUpdate, 2);

function onTimerUpdate(nCurrentTimerSeconds, tExtraParams)
if not Session.IsHost then
return;
end

Debug.console("ExtensionTutorial.onTimerUpdate - Current Timer Seconds", nCurrentTimerSeconds);
end

SieferSeesSomething
January 3rd, 2024, 04:25
That was definitely it. Sorry it was something so simple, but thanks for the help!

Arnagus
March 30th, 2024, 16:10
I have build a very basic extension which progresses the time minute by minute (using Clock Adjuster (https://forge.fantasygrounds.com/shop/items/574/view)) as long as the timer is running.
You should make sure that the options for turn-based progress are disabled as otherwise, effects expire too early (unless your players and you can each complete their turn in less than 59 seconds :) )

Update:
Now added an option to switch in-between „run during combat“ (reset on turn) and „run outside of combat“.

Original:
No options, does not even check if all required extension are loaded, just registering the clock advancement.

Real time runs when timer is running, and stops if timer is stopped.

Now on the Forge (https://forge.fantasygrounds.com/shop/items/1702/view)(hence removing the attachment).

mattekure
March 30th, 2024, 23:10
I have build a very basic extension which progresses the time minute by minute (using Clock Adjuster (https://forge.fantasygrounds.com/shop/items/574/view)) as long as the timer is running.
You should make sure that the options for turn-based progress are disabled as otherwise, effects expire too early (unless your players and you can each complete their turn in less than 59 seconds :) )

No options, does not even check if all required extension are loaded, just registering the clock advancement.

Real time runs when timer is running, and stops if timer is stopped.

Nice Work!

metaldm007
April 22nd, 2024, 22:40
Hey there, love the extension (my campaigns have an actual passage of time now!), was just wondering if there's any possibility of compatability with the Better Menus (https://www.fantasygrounds.com/forums/showthread.php?58226-Better-Menus-(CoreRPG-5E-etc)/page33) extension? I love how much more convenient Better Menus has been, but it seems like your timer doesn't support it. According to the OP, instructions on how to work with it are included. (https://www.fantasygrounds.com/forums/showthread.php?58226-Better-Menus-(CoreRPG-5E-etc)&p=574918&viewfull=1#post574918)