Timer Setups

DreTaX

Probably knows the answer...
Administrator
Jun 29, 2014
4,093
4,784
113
At your house.
github.com
Description:

Timers can be handled through the Plugin class. When the interval elapses the timer will repeat itself and raise a callback (<timerName>Callback), with the TimedEvent as a parameter. You can run only one basic timer with the same name, however you can run more simultaneously of Parallel Timers. Use Parallel Timers only if you have to.

Timer specific methods:

C#:
CreateParallelTimer(string Name, int Interval, Dictionary<string, object> Args):TimedEventCreateParallelTimer(..
CreateTimer(string Name, int Interval, Dictionary<string, object> Args):TimedEvent
CreateTimer(string Name, int Interval):TimedEvent
GetParallelTimer(string Name):List<TimedEvent>
GetTimer(string Name):TimedEvent
KillParallelTimer(string Name):void
KillTimer(string Name):void
KillTimers():void


ParallelTimer:

Parallel Timers are having the same structure, as the normal Timers, the difference is that they are must have a Dictionary.

Dictionary Represents a collection of keys and values.


Python:
def On_PlayerConnected(self, Player):
ConnectionData = Plugin.CreateDict()
ConnectionData["PlayerID"] = Player.SteamID
ConnectionData["Player"] = Player
# 10 seconds
Plugin.CreateParallelTimer("Connect", 10000, ConnectionData).Start()

def ConnectCallback(self, ATimedEvent):
ATimedEvent.Kill()
data = ATimedEvent.Args
playerID = data["PlayerID"]
StoredPlayer = data["Player"] # Instead of finding you can use this, and check if StoredPlayer.IsOnline:
Player = Server.FindPlayer(playerID)
if Player is not None:
Player.Message("Hey, I think the timer found you!")
JavaScript:
function On_PlayerConnected(Player)
{
var ConnectionData = Plugin.CreateDict();
ConnectionData["PlayerID"] = Player.SteamID;
// 10 seconds
Plugin.CreateParallelTimer("Connect", 10000, ConnectionData).Start();
}

function ConnectCallback(ATimedEvent)
{
ATimedEvent.Kill();
var data = ATimedEvent.Args;
var playerID = data["PlayerID"];
var Player = Server.FindPlayer(playerID);
if (Player != null) {
Player.Message("Hey, I think the timer found you!");
}
}
Code:
function On_PlayerConnected(Player)
local ConnectionData = Plugin.CreateDict()
ConnectionData["PlayerID"] = Player.SteamID
-- 10 seconds
Plugin:CreateParallelTimer("Connect", 10000, ConnectionData):Start()
end

function ConnectCallback(ATimedEvent)
ATimedEvent.Kill()
local data = ATimedEvent.Args
local playerID = data["PlayerID"]
local Player = Server:FindPlayer(playerID)
if Player ~= nil then
Player.Message("Hey, I think the timer found you!")
end
end
RegularTimer:

Regular Timers are being called without anykind of extra stuffs.


Python:
    def On_PluginInit(self):
# Launching a timer (5 seconds)
Plugin.CreateTimer("PingCheck", 5000).Start()

def PingCheckCallback(self, ATimedEvent):
ATimedEvent.Kill()
for pl in Server.Players:
if int(pl.Ping) >= 250:
pl.MessageFrom("[High Ping Kicker]", "[color#FF2222]Your Ping: " + str(pl.Ping) +
" Maximum you can have: 250")
pl.Disconnect()
Plugin.CreateTimer("PingCheck", 5000).Start()
JavaScript:
function On_PluginInit()
{
// Launching a timer (5 seconds)
Plugin.CreateTimer("PingCheck", 5000).Start();
}

function PingCheckCallback(ATimedEvent)
{
ATimedEvent.Kill();
for (var pl in Server.Players)
{
if (pl.Ping >= 250)
{
pl.MessageFrom("[High Ping Kicker]", "[color#FF2222]Your Ping: "
+ pl.Ping + " Maximum you can have: 250");
pl.Disconnect();
}
}
Plugin.CreateTimer("PingCheck", 5000).Start();
}
Code:
function On_PluginInit()
-- Launching a timer (5 seconds)
Plugin:CreateTimer("PingCheck", 5000):Start()
end

function PingCheckCallback(ATimedEvent)
ATimedEvent.Kill()
-- This might be wrong, sorry I'm not a lua fan
for i, pl in ipairs(Server.Players) do
if pl.Ping >= 250 then
pl:MessageFrom("[High Ping Kicker]", "[color#FF2222]Your Ping: "
+ pl.Ping + " Maximum you can have: 250")
pl:Disconnect()
end
end
Plugin:CreateTimer("PingCheck", 5000):Start()
end

C# Parallel timers.

C#:
    public class PluginTimedEvent
{

private Dictionary<string, object> _args;
private readonly System.Timers.Timer _timer;
private long lastTick;
private int _elapsedCount;

internal delegate void TimedEventFireDelegate(PluginTimedEvent evt);

internal event TimedEventFireDelegate OnFire;

internal PluginTimedEvent(double interval)
{
this._timer = new System.Timers.Timer();
this._timer.Interval = interval;
this._timer.Elapsed += new ElapsedEventHandler(this._timer_Elapsed);
this._elapsedCount = 0;
}

internal PluginTimedEvent(double interval, Dictionary<string, object> args)
: this(interval)
{
this.Args = args;
}

private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (this.OnFire != null)
{
this.OnFire(this);
}

this._elapsedCount += 1;
this.lastTick = DateTime.UtcNow.Ticks;
}

internal void Start()
{
this._timer.Start();
this.lastTick = DateTime.UtcNow.Ticks;
}

internal void Stop()
{
this._timer.Stop();
}

internal void Kill()
{
this._timer.Stop();
this._timer.Dispose();
}

internal Dictionary<string, object> Args
{
get { return this._args; }
set { this._args = value; }
}

internal double Interval
{
get { return this._timer.Interval; }
set { this._timer.Interval = value; }
}

internal double TimeLeft
{
get { return (this.Interval - ((DateTime.UtcNow.Ticks - this.lastTick) / 0x2710L)); }
}

internal int ElapsedCount
{
get { return this._elapsedCount; }
}
}

C#:
internal PluginTimedEvent CreateParallelTimer(int timeoutDelay, Dictionary<string, object> args)
{
PluginTimedEvent timedEvent = new PluginTimedEvent (timeoutDelay);
timedEvent.Args = args;
timedEvent.OnFire += Callback;
return timedEvent;
}

internal void Callback(PluginTimedEvent e)
{
e.Kill();
var data = e.Args;
Fougerite.Player player = (Fougerite.Player) data["Player"];
//todo do something here
}

public void OnPlayerSpawned(Fougerite.Player player, SpawnEvent se)
{
var dict = new Dictionary<string, object>();
dict["Player"] = player;
CreateParallelTimer(5000, dict).Start();
}

 
Last edited:

MasterPeace

Retired Staff
Retired Staff
Feb 2, 2015
269
69
28
45
Poland
Hey DreTax. When you was writing for me example code how to fix my rad damage for Fougerite 1.0.8 (no proper methods/functions) you wrote me "timer.Kill()". I'm wondering if this is how we should kill timers now, or it's just for this parallel-timers?

http://fougerite.com/threads/rad-zones-and-animals-stronger.473/page-3#post-5304

And are these parallel timers more stable maybe? Should I change my code for them? Or it's just new feature "when-you-need"?
 

DreTaX

Probably knows the answer...
Administrator
Jun 29, 2014
4,093
4,784
113
At your house.
github.com
In the old times, timer callbacks didnt have a parameter. So the only way you could get the timer is the Get timer and then you could use the killtimer method. IPM module checks if your callback has a parameter, if It doesnt then It will just pass. If It has, It will give the data to the parameter. Parallel timer allows you to create a dictionary, and pass any objects to that. Even a Player. If you dont need to pass an object to the timer, then you should stay at the simple timer. But yes, you can also give the parameter "timer" to the callback even at the single timer. Besides parallel timer allows you to create more timers with the same name, but all would have a unique timer parameter because of the list. This means you can create a single timer for a player, without overwriting the other ones. If you would create a simple timer named as Hello, and create a new one also named as Hello after that, It would overwrite the first one. Using Parallel timers will make that not happening.

Sent from my Samsung Galaxy S4
 
  • Like
Reactions: MasterPeace

MasterPeace

Retired Staff
Retired Staff
Feb 2, 2015
269
69
28
45
Poland
How to remove player from dictionary after he disconnect? When player reconnect there are like two timers, or two same players in one timer.
 

DreTaX

Probably knows the answer...
Administrator
Jun 29, 2014
4,093
4,784
113
At your house.
github.com
How to remove player from dictionary after he disconnect? When player reconnect there are like two timers, or two same players in one timer.
I have two ideas.

1. Fun around with this: https://github.com/balu92/IronPythonModule/blob/master/IronPythonModule/IPPlugin.cs#L26


2. Do an array ( PlayersInTimer = [] )

Put the player object every time in there when you launch a timer. If the timer ran, you can remove the player from It. And If the array contains the player, then dont launch a timer.
 

MasterPeace

Retired Staff
Retired Staff
Feb 2, 2015
269
69
28
45
Poland
When I'm using array, like in basic timers, for some reason it's working only for once. Of course no error or something. They stopped working that way after 1.0.8 RC5.

So I decided to use this Parallel and now I need to use array again... So Parallel becomes not needed...

How is it possible? Do you see sense there? xD I almost done my plugins and I would like to finally end those Zones and Arena. But I stuck in just this one thing. Amazing. I'll sit on this later.
 

DreTaX

Probably knows the answer...
Administrator
Jun 29, 2014
4,093
4,784
113
At your house.
github.com
When I'm using array, like in basic timers, for some reason it's working only for once. Of course no error or something. They stopped working that way after 1.0.8 RC5.

So I decided to use this Parallel and now I need to use array again... So Parallel becomes not needed...

How is it possible? Do you see sense there? xD I almost done my plugins and I would like to finally end those Zones and Arena. But I stuck in just this one thing. Amazing. I'll sit on this later.
Working only for once? What do you mean? MHm.

I think you could do:

Python:
timer = Plugin.GetParallelTimer(name)
#if you so str(timer), I think that will return a list.
#I think it should also print the dictionary in it. Try It

#If it does: if str(Player) in str(timer) OR if Player.SteamID in str(timer)
 

MasterPeace

Retired Staff
Retired Staff
Feb 2, 2015
269
69
28
45
Poland
Str is not working. I realized that problem is maybe in setting timers from PlayerConnect (creating second, third, fourh timer when player reconnect), but now I can't run it another way. It's just not working:

Could you show example of timer created from plugin start?

Python:
PlayerIDData = Plugin.CreateDict()

class SomeClass:

    def On_PluginInit(self):
        Plugin.CreateParallelTimer("Timer", 20000, PlayerIDData).Start()

    def On_PlayerConnected(self, Player):
        PlayerIDData["PlayerID"] = Player.SteamID
This code won't work. Man I hate when I have no errors in console, but I know that it's not going on. It's also after this 1.0.8 version, and only with timers.
 

DreTaX

Probably knows the answer...
Administrator
Jun 29, 2014
4,093
4,784
113
At your house.
github.com
Str is not working. I realized that problem is maybe in setting timers from PlayerConnect (creating second, third, fourh timer when player reconnect), but now I can't run it another way. It's just not working:

Could you show example of timer created from plugin start?

Python:
PlayerIDData = Plugin.CreateDict()

class SomeClass:

    def On_PluginInit(self):
        Plugin.CreateParallelTimer("Timer", 20000, PlayerIDData).Start()

    def On_PlayerConnected(self, Player):
        PlayerIDData["PlayerID"] = Player.SteamID
This code won't work. Man I hate when I have no errors in console, but I know that it's not going on. It's also after this 1.0.8 version, and only with timers.
I don't think that anything has to do with 1.0.8... Besides, not even with IPM. I don't see you are having a "Timer" callback at all. The timer is unlogical.

You launch a timer with an empty dictionary. The timer already received the data, and will never update It from the variable. Since, you started It with an empty dictionary again, just to make you sure what the problem is. You update the dictionary, but not the timer. If you want to update It, you have to kill the timer, and relaunch It. But instead:

The reason why your code won't work since you keep overwriting a key in a dictionary. So It's impossible that all the players will be in the timer

Python:
class SomeClass:

    def TimerCallback(self, timer):
        timer.Kill()
        #blablabla

    def On_PlayerConnected(self, Player):
        PlayerIDData = Plugin.CreateDict()
        id = Player.SteamID
        PlayerIDData["PlayerID"] = id
        Plugin.CreateParallelTimer("Timer", 20000, PlayerIDData).Start()
Even safer in legacy:
Python:
class SomeClass:

    def TimerCallback(self, timer):
        timer.Kill()
        #blablabla

    def On_PlayerConnected(self, Player):
        id = Player.SteamID
        DataStore.Add("Connected", id, "JustConnected")

    def On_PlayerSpawned(self, Player, SpawnEvent):
        if DataStore.ContainsKey("Connected", Player.SteamID):
             # launch timer
             # delete the guy from the datastore
 
  • Agree
Reactions: Snake

MasterPeace

Retired Staff
Retired Staff
Feb 2, 2015
269
69
28
45
Poland
1. No I just forgot to paste Callback in my code. It was example of doing it another way, because code from your first post is like: http://fougerite.com/threads/parallel-timers.515/#post-5671

2. Your first example is same like in first post and it wont work man. Please check it first, I wont copy my last post about it here: http://fougerite.com/threads/parallel-timers.515/#post-5671

Second example looks better, hope it will work... But it looks like just basic timer what somehow didn't want to repeat. But I'll check it first of course before I say something.

--

Offtopic: Why I think 1.0.8 have something about it? Because when we updated our servers with new releases, my Rad checker (http://fougerite.com/threads/rad-zones-and-animals-stronger.473/page-3#post-5459) was not showing any errors after update. It always showed me errors before, when something didn't work. Sometimes even looped error in console. Now if anything is wrong, it'll not show me anything. You just searching for ghost error in your code, because you have no debug. No matter what I'll do wrong in timer it will not say that timer have error. Just don't run and that's all, fock you MasterPeace, your code, you search, you repair.
 

DreTaX

Probably knows the answer...
Administrator
Jun 29, 2014
4,093
4,784
113
At your house.
github.com
Lel. Well the only reason why I think Its not the problem, because the timer gets created in the Ipm module which wasnt updated. Do you have error and exception logging inabled in the Fougerite.cfg?


So you want a timer which has an updated list all the time?
 

MasterPeace

Retired Staff
Retired Staff
Feb 2, 2015
269
69
28
45
Poland
Yea I know what you mean, but for some reason it stopped working after update. I have all logging enabled, it's always showing errors but not from timers.

Let's say I want to give C4 player after every 48 minutes of playing. So perfect would be when all players would have their own timers. But when I do it that way from first post, player gets second timer after reconnect (2 C4s/48), and after third reconnect (3 C4s/48).

But maybe using DataStore will work like you said on your last post, so please wait until I'll check it and write here what's going on.
 

DreTaX

Probably knows the answer...
Administrator
Jun 29, 2014
4,093
4,784
113
At your house.
github.com
I think having a single timer for this should be enough. But I get what you mean. The time. Yes you could check if the id in the ds exists, maybe the best would be in that place is the onplayrrconnected, instead of spawned. Just be sure to remove the player from the ds if he disconnects.
 

P0LENT4 2

Member
Trusted Member
Member
Dec 26, 2016
31
2
8
27
Parts Unknown
How to use times in C #?

Times to perform an action after a certain time and another to perform an action several times in a certain time.
 

Jakkee

Retired Staff
Retired Staff
Plugin Developer
Jul 28, 2014
1,465
932
113
Australia
How to use times in C #?

Times to perform an action after a certain time and another to perform an action several times in a certain time.
In C# it's common to create a new class for the timer methods
I'll post an example within the next hour or so,
You could look into other C# plugins for examples
 

Jakkee

Retired Staff
Retired Staff
Plugin Developer
Jul 28, 2014
1,465
932
113
Australia
Nevermind, the example it already posted
Create a new class in your project called PluginNameTimedEvent.cs
and paste in:
C#:
    public class PluginNameTimedEvent
    {

        private Dictionary<string, object> _args;
        private readonly System.Timers.Timer _timer;
        private long lastTick;
        private int _elapsedCount;

        internal delegate void TimedEventFireDelegate(PluginNameTimedEvent evt);

        internal event TimedEventFireDelegate OnFire;

        internal PluginNameTimedEvent(double interval)
        {
            this._timer = new System.Timers.Timer();
            this._timer.Interval = interval;
            this._timer.Elapsed += new ElapsedEventHandler(this._timer_Elapsed);
            this._elapsedCount = 0;
        }

        internal PluginNameTimedEvent(double interval, Dictionary<string, object> args)
            : this(interval)
        {
            this.Args = args;
        }

        private void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (this.OnFire != null)
            {
                this.OnFire(this);
            }

            this._elapsedCount += 1;
            this.lastTick = DateTime.UtcNow.Ticks;
        }

        internal void Start()
        {
            this._timer.Start();
            this.lastTick = DateTime.UtcNow.Ticks;
        }

        internal void Stop()
        {
            this._timer.Stop();
        }

        internal void Kill()
        {
            this._timer.Stop();
            this._timer.Dispose();
        }

        internal Dictionary<string, object> Args
        {
            get { return this._args; }
            set { this._args = value; }
        }

        internal double Interval
        {
            get { return this._timer.Interval; }
            set { this._timer.Interval = value; }
        }

        internal double TimeLeft
        {
            get { return (this.Interval - ((DateTime.UtcNow.Ticks - this.lastTick) / 0x2710L)); }
        }

        internal int ElapsedCount
        {
            get { return this._elapsedCount; }
        }
    }
then in your plugin use this as an example:
(Rename PluginNameTimedEvent to your pluginnameTimedEvent)
C#:
internal PluginNameTimedEvent CreateParallelTimer(int timeoutDelay, Dictionary<string, object> args)
{
    PluginNameTimedEvent TimedEvent = new PluginNameTimedEvent (timeoutDelay);
    TimedEvent.Args = args;
    TimedEvent.OnFire += Callback;
    return TimedEvent;
}

internal void Callback(PluginNameTimedEvent e)
{
    e.Kill();
    var data = e.Args;
    Fougerite.Player Player = (Fougerite.Player) data["Player"];
    //todo do something here
}

public void OnPlayerSpawned(Fougerite.Player Player, SpawnEvent se)
{
    var dict = new Dictionary<string, object>();
    dict["Player"] = Player;
    CreateParallelTimer(5000, dict).Start();
}
 
  • Like
Reactions: salva