Author Topic: Timer Help?
blingblangbloaw 
Posts: 224
Registered: Aug 29, '11
Extended Info (if available)
Real Post Cnt: 224
User ID: 1,428,431
Subject: Timer Help?
I'm fairly new to all of this, Decal, C#, and well programming in general. I've been going through pretty much every source I can find and piecing things together as I go (thanks primarily to the sample plugin provided by Mag-nus). It may be trivial, but I can't seem to find the best way to make a sleep/delay function work. I have seen numerous references towards System.Windows.Forms.Timer as being the best choice, but I can't seem to wrap my head around how to actually implement it correctly.

If anyone has a useful source explaining how to get this to work, or link to some source code that implements it in a somewhat basic (read easy) manner, it would help a lot.

As of right now I've been following this example: http://snipplr.com/view/22250/systemwindowsformstimer-example/

Basically, I want a checkbox that when toggled on, action will be taken every x minutes. Right now, the game just begins not responding after I click the checkbox for the first time.

I've added the "static System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();" to my class. I've subscribed/unsubscribed to the events in both the LoginComplete and Logoff methods, respectively, adding the timer.Interval = 60000; alongside where I subscribed to the event.



static System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
bool started = false;



[ControlEvent("Checkbox", "Change")]
void Checkbox_Change(object sender, CheckBoxChangeEventArgs e)
{
----try
----{
-------while (Checkbox.Checked == true)
-------{
--------------timer.Start();
--------------started = true;

--------------while (started == true)
--------------{
-----------------Application.DoEvents();

-----------------if (Checkbox.Checked == true)
-----------------{

-----------------}
-----------------else
-----------------{
---------------------started = false;
-----------------}
--------------}
-------}
----}
----catch (Exception ex) { Util.LogError(ex); }
}


public void timer_Tick(object sender, EventArgs e)
{
----try
----{
-------timer.Stop();

-------Host.Actions.AddChatText("...", 5);

-------timer.Start();
----}
----catch(Exception ex) { Util.LogError(ex); }
}


Any help would be greatly appreciated. I apologize if my terminology isn't quite correct, or if I'm incredibly far off on how to get this working. I'm doing this mostly as a learning experience, as I know I have a lot left to learn.

Thanks.

 

-----signature-----
(none)
Link to this post
Mag-nus 
Posts: ????
Registered: ????
Extended Info (if available)
Real Post Cnt: 0
User ID: 0
Subject: Timer Help?
Get rid of that entire while{} block. Thats locking up your program.

Don't do Application.Doevents, pretty much ever, and especially not in a decal plugin.

Also, that while{} is blocking your program. AC/Decal share the same thread. If you block in decal, it will block the game.

Also, the while (checkbox.checked) is bad.

My code would look like:


// remove the static here, doesn't make sense to be static
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
bool started = false;




[ControlEvent("Checkbox", "Change")]
void Checkbox_Change(object sender, CheckBoxChangeEventArgs e)
{
----try
----{
if (checkbox.checked)
{
started = true;
timer.start();
}
else
{
started = false;
timer.stop();
}

----}
----catch (Exception ex) { Util.LogError(ex); }
}


public void timer_Tick(object sender, EventArgs e)
{
----try
----{
-------timer.Stop();

if (!started)
return;

-------Host.Actions.AddChatText("...", 5);

if (started)
-------timer.Start();
----}
----catch(Exception ex) { Util.LogError(ex); }
}

 

-----signature-----
Link to this post
blingblangbloaw 
Posts: 224
Registered: Aug 29, '11
Extended Info (if available)
Real Post Cnt: 224
User ID: 1,428,431
Subject: Timer Help?
Thank you. Something that now looks so simple, I managed to turn into a huge mess lol. I should have been able to get that.

 

-----signature-----
(none)
Link to this post
shontsu 
Posts: ????
Registered: ????
Extended Info (if available)
Real Post Cnt: 0
User ID: 0
Subject: Timer Help?
Is there some benefit to the stop/start in the tick event? If I just want a regular tick I just leave it running.

Ahh, checked the example. Fairly sure its only doing that because of the message box popping up, so it stops and waits for you to respond to that.

 

-----signature-----
Link to this post
Virindi-Inquisitor 
Posts: 6,908
Registered: Nov 18, '01
Extended Info (if available)
Real Post Cnt: 6,646
User ID: 511,923
Subject: Timer Help?
System.Windows.Forms.Timer will not raise the tick event after it has been stopped. However, it is possible that several tick events could queue up in the message queue if for some reason they are not being processed fast enough to keep up, like if the client experiences 'frame lag' or if your tick handler takes a really long time to execute.

The effect of this is that if your handler takes nontrivial execution time, then there is a certain framerate below which you will end up ticking more than once per frame. Depending on the speed of the computer and the complexity of your handler, this can be disastrous. In the worst case scenario, the client freezes as it constantly runs nothing but your handler over and over again.

For this reason, anytime a handler is firing at a decent rate (more than once a second) or contains a nontrivial amount of code, I recommend using a timer class which limits the firing to a maximum of once per client rendered frame. For instance, VTank's logic operates in this manner.

To achieve this, my MyTimer class keeps a frame counter and merely exits any timer tick which occurs in the same frame as the previous tick. For additional safety, it shuts itself down automatically when plugins are terminated (as ticks firing after logout are a major cause of plugins crashing at character select). It also catches all exceptions in your tick handler and forwards them to an error function of your choice. Call MyTimer.Init() in your plugin startup before creating any MyTimer instances.

The class is available here:
http://www.virindi.net/repos/virindi_public/trunk/SharedCode/MyTimer.cs
http://www.virindi.net/repos/virindi_public/trunk/SharedCode/IMyTimer.cs

 

-----signature-----
Virindi
---
****Virindi Plugins FAQ**** http://www.virindi.net/wiki/index.php/Virindi_Plugins_FAQ
http://www.virindi.net - Virindi Tank, Follower, Integrator, Reporter, VCS5, XPHelper, Item Tool, HUDs, etc...
Decal Core Dev - http://www.decaldev.com
Link to this post
mrFlipo 
Posts: 476
Registered: Jun 24, '03
Extended Info (if available)
Real Post Cnt: 465
User ID: 815,685
Subject: Timer Help?
Different approach I use is pseudo coded below. You do not want a lot of System.Windows.Forms.Timers as it consumes
global resources.

Create a single System.Windows.Forms.Timer and in its event handler do below.



if Shutdown or InTimer then exit; //Shutdown is boolean set by seeing logout message and/or terminate event.
InTimer:=True;

try
ClassX.TimerEvent;
ClassY.TimerEvent;
...
...

finally
InTimer:=false; //Handle Exceptions etc so we always set this.
end;




In your ClassX.TimerEvent you want something like below


if not ClassX.active or ClassX.EventTime>now then exit; //don't need to service i'm not using ClassX or its not time yet.
..
blah blah code
..

ClassX.EventTime:=IncSeconds(now,1);//set time when we want to process this class's code. Maybe I'm checking buffs and once every 30 seconds is frequent enough.



You want to minimize the time spent in main timer event ( think Get-In Get-Out) and balance it so that
all your classes working off timers are serviced. If you have a process that chews up time
consider coding it so when timer event fires its the only one being service on that timer tick.
Also need to think about frequency that you really need your class to do their process. You
really don't need to check mana charges every second right?


You also can implement a counter that increments each time your main timer event begins
to do the services. You could use this to control which classes have there events triggered to
better distribute the cpu load/time issues. Example would be timer is set to one second and I have
counter that increments 1 to 10. I can then do some process on the 1 counter and other on 2 counter thus
distributed the load over 2 seconds intervals.


Another issue is to pause and think any time you are doing loop code( i.e. for..next,repeat..until).
It must be fast else you need to off load the work and let a timer event do the work incrementally over time.

Lets say for a trivial case that I need to move contents of pack 1 to main pack. It would not be pretty in a timer event
to do a loop with decal command to move items. You can move only one item at a time and you have to wait up to several
seconds for it to move or fail to move.

Waiting for seconds in a timer event would so freeze the game. It is a way to find out how long before turbine boots you for no activity. happy

What you can do is have a loop that creates a list of IDs (in essence a Queue system) and enable a class so that on the timer event you issue the decal move command using the first item in your list and removing from list. Just set the ClassX.EventTime for say 3 seconds and now you won't have to worry about being booted from game. If you want to make it more robust you can add code to handle issues like success/failure. Maybe you want to speed up moving so that when move succeeds you set the timer to zero so next timer event will do next move command. Nice thing about using a timer is what happens if you don't get a success or failure event,it just goes on to the next thing or even repeats the command.

Yes you in the back.... well yes you could just have a timer event that looks for an item in pack 1 and moves it to main pack, but then it would
not highlight that code loops in a timer event are not necessarily evil...just needs to be fast.


Unrolling a loop to a timer is also a way to spread the time load out.
Lets say you have a
For x:=0 to somenumber
Block of code to do somestuff.

You can let the timer event increment the X and then do the single block of code.


Oh well I was inspired and so enjoyed V's post that I had to make this one.


 

-----signature-----
(none)
Link to this post
Virindi-Inquisitor 
Posts: 6,908
Registered: Nov 18, '01
Extended Info (if available)
Real Post Cnt: 6,646
User ID: 511,923
Subject: Timer Help?
Some additional information about my timer philosophy:

1) Yes, adding more timers does require the OS to keep track of them. However, the OS does this at the very least in a list sorted by end time (if not in a balanced tree or other O(logn) data structure). In the case of a large number of timers, this approach is faster than checking every single thing which might need to fire every time, unless you are doing that infrequently. With the number of timers typically used, the two approaches should be essentially identical. If you are creating thousands of timers or something, enough to matter, then you are probably doing it wrong anyway.

2) Something that I do which I haven't mentioned yet is try to make sure timer ticks do not all happen at once, by making each timer interval a prime number. This is roughly the same idea as making the size of a hashtable prime; timer firings will be guaranteed not to have perfect harmonics with each other.

For instance, say you have one timer which is 1000ms and another which is 500ms. If both are started at the same time, then forever more they will fire at exactly the same time. If you make one timer 1087ms and the other 509ms (prime numbers), they will quickly get 'out of sync' and will not often fire in the same frame.

To maintain the smoothness of the game, it is generally best to break up separate tasks and have them process during different frames. Doing a lot at once and then nothing in the next frame will cause the game to stutter, and a more equal framerate is preferable to the player.

Of course, this effect is not very large and if you are doing a lot in each tick it is even better to make your handlers themselves faster. However, this approach is pretty much the opposite of what the result will be if you put every timed event in the same handler.


Not all of my intervals are like this, but many are. In VTank, for instance, the timed UI update interval is 3271ms. The timers which are not prime will probably be changed to fit this theory in the future.

 

-----signature-----
Virindi
---
****Virindi Plugins FAQ**** http://www.virindi.net/wiki/index.php/Virindi_Plugins_FAQ
http://www.virindi.net - Virindi Tank, Follower, Integrator, Reporter, VCS5, XPHelper, Item Tool, HUDs, etc...
Decal Core Dev - http://www.decaldev.com
Link to this post
Virindi-Inquisitor 
Posts: 6,908
Registered: Nov 18, '01
Extended Info (if available)
Real Post Cnt: 6,646
User ID: 511,923
Subject: Timer Help?
An extra note: according to the .net docs, timer has a "resolution" of 55ms. Depending on how you interpret this, it may be better to make your intervals prime numbers multiplied by 55.

Unfortunately, the timer documentation is relatively light.

 

-----signature-----
Virindi
---
****Virindi Plugins FAQ**** http://www.virindi.net/wiki/index.php/Virindi_Plugins_FAQ
http://www.virindi.net - Virindi Tank, Follower, Integrator, Reporter, VCS5, XPHelper, Item Tool, HUDs, etc...
Decal Core Dev - http://www.decaldev.com
Link to this post
Gali_Nala 
Posts: 8,486
Registered: Mar 13, '01
Extended Info (if available)
Real Post Cnt: 8,380
User ID: 73,503
Subject: Timer Help?
Disclaimer: I know nothing of programing...

Since I see two active devs here I thought I'd ask

Would it be possible to create a plugin or add to a plugin the ability to use the focus stone repeatedly?

i.e. Toon #2 every 30 seconds uses the focus stone to cast brilliance on Toon #1 (tinker)until such time as the checkbox is unchecked or a /stop tell is sent? (more complicated would be to add mana recharging of the stone)

Thanks happy

 

-----signature-----
Gali Nala grin ¤ Izz The Forgotten grin ¤ Lil' Marie grin
•OotS•

Atropa: Wow, took me about 20 minutes to take down that Crystal Lord
Crizznizzle: Did you throw all your wealth at it?
Link to this post
Virindi-Inquisitor 
Posts: 6,908
Registered: Nov 18, '01
Extended Info (if available)
Real Post Cnt: 6,646
User ID: 511,923
Subject: Timer Help?
http://ac.ranta.info/WandMonkey

It is generally appropriate though to keep threads on topic.

 

-----signature-----
Virindi
---
****Virindi Plugins FAQ**** http://www.virindi.net/wiki/index.php/Virindi_Plugins_FAQ
http://www.virindi.net - Virindi Tank, Follower, Integrator, Reporter, VCS5, XPHelper, Item Tool, HUDs, etc...
Decal Core Dev - http://www.decaldev.com
Link to this post
shontsu 
Posts: ????
Registered: ????
Extended Info (if available)
Real Post Cnt: 0
User ID: 0
Subject: Timer Help?
Interesting. I've always taken the approach of keeping work in timers to an absolute minimum so these haven't been issues for me, that said I've never tried anything as complicated as a full combat bot either. I can see how for some uses this info would be really useful.

 

-----signature-----
Link to this post
Gali_Nala 
Posts: 8,486
Registered: Mar 13, '01
Extended Info (if available)
Real Post Cnt: 8,380
User ID: 73,503
Subject: Timer Help?
Sorry didn't mean to hijack.

I thought it was sort of on topic because of the timer going off every 30 secs.

Thanks for the link happy

 

-----signature-----
Gali Nala grin ¤ Izz The Forgotten grin ¤ Lil' Marie grin
•OotS•

Atropa: Wow, took me about 20 minutes to take down that Crystal Lord
Crizznizzle: Did you throw all your wealth at it?
Link to this post

Valid XHTML 1.0 Transitional Powered by PHP