1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Reapetable Timer

Discussion in 'Script Support' started by TAChuck, Feb 8, 2017.

  1. TAChuck
    Offline

    TAChuck New Member

    Joined:
    Jul 1, 2015
    Messages:
    28
    Likes Received:
    4
    Hello guys!

    So, I have this Xml Attachment that I'm using for a leveling system "a la" RPG, with levels and xp, attach to every player.

    I want this Attachment to have a Timer that give a amount of xp every x minutes. But I'm not quite sure how to do this, since I'm fairly new to coding.

    I read a couple of existing attachment with timer, but they don't really do what I want, since their timer are not reapetable.

    Maybe you guys know a example of code that I can use to write the effect that I want?

    Thank you for your time!
     
  2. Talow
    Offline

    Talow Member

    Joined:
    Aug 30, 2014
    Messages:
    276
    Likes Received:
    22
    From https://github.com/ServUO/ServUO/blob/master/Server/Timer.cs
    There's a timer with Delegate that you can use to deal with this easily.

    Code (C#):
    1. public static Timer DelayCall(TimeSpan delay, TimeSpan interval, TimerCallback callback)
    Using this is pretty simple. The first argument is the delay for the first tick, the second is the repeat interval and the call back is a delegate method that's executed when the timer ticks. You can find more information about delegates if needed here https://www.servuo.com/tutorials/delegates.20/ as I've already made a tutorial about them.
     
  3. TAChuck
    Offline

    TAChuck New Member

    Joined:
    Jul 1, 2015
    Messages:
    28
    Likes Received:
    4
    Thank you, that worked pretty well!

    Is there a easy way to stop the timer when a player is logout?
     
  4. Talow
    Offline

    Talow Member

    Joined:
    Aug 30, 2014
    Messages:
    276
    Likes Received:
    22
    That starts to get more complicated. For that you'll want to create a new class based on timer class, then you have access to the start and stop methods of the timer, and you use the ontick method to make it do what you want it to do.
     
    • Helpful Helpful x 1
  5. TAChuck
    Offline

    TAChuck New Member

    Joined:
    Jul 1, 2015
    Messages:
    28
    Likes Received:
    4
    So! As advised I created an internal timer for my attachment.

    I added a statement that look if the player is in map.internal or not. Now everything work.

    Thanks for the help!
     
    • Like Like x 1
  6. sahisahi
    Offline

    sahisahi Member

    Joined:
    Jan 13, 2016
    Messages:
    370
    Likes Received:
    12
    You could always post what u have done so it might help other people :)
     
    • Agree Agree x 1
  7. TAChuck
    Offline

    TAChuck New Member

    Joined:
    Jul 1, 2015
    Messages:
    28
    Likes Received:
    4
    If it can help other people, here's what I did:

    I added this timer to my attachment :
    Code (C#):
    1.  
    2. //Method to start the timer
    3. public void DoTimer()
    4.         {
    5.             if (m_Timer != null)
    6.                 m_Timer.Stop();
    7.  
    8.             m_Timer = new InternalTimer(this);
    9.             m_Timer.Start();
    10.         }
    11.  
    12. //The timer
    13. private class InternalTimer : Timer
    14.         {
    15.             private XmlCharManager m_attachment;
    16.  
    17.             public InternalTimer(XmlCharManager attachment)
    18.                 : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0))
    19.             {
    20.                 Priority = TimerPriority.OneSecond;
    21.                 m_attachment = attachment;
    22.             }
    23.  
    24.             protected override void OnTick()
    25.             {
    26.                 if (m_attachment == null) return;
    27.                
    28.                 Mobile m = m_attachment.AttachedTo as Mobile;
    29.  
    30.                 //If the player is online
    31.                 if (m.Map != Map.Internal)
    32.                 {
    33.                     //What the Timer do OnThick
    34.                     m_attachment.GiveXp();
    35.                     if (m_attachment.Xp >= 100)
    36.                     {
    37.                         m_attachment.LevelUp();
    38.                     }
    39.                 }
    40.  
    41.                 else
    42.                 {
    43.                     Stop();
    44.                     return;
    45.                 }
    46.             }
    47.         }
    And I added this to LoginStats.cs

    Code (C#):
    1.  
    2. //Look for the attachment with the timer
    3. XmlCharManager c = (XmlCharManager)XmlAttach.FindAttachment(m, typeof(XmlCharManager));
    4.  
    5.             if (c != null)
    6.             {
    7.                 //Start the timer when the player login.
    8.                 c.DoTimer();
    9.             }
     
    • Two Thumbs Up Two Thumbs Up x 1
  8. Talow
    Offline

    Talow Member

    Joined:
    Aug 30, 2014
    Messages:
    276
    Likes Received:
    22
    Doing well so far. I want to give you another bit of advice, instead of having a new instance of the timer for each attachment you could have a static timer... This timer would have a list for playermobiles and using the events (LoginEvent and LogoutEvent) update the list.

    If the timer shouldn't be global you can use a dictionary instead of a list to keep track of the playermobile and the last DateTime that was ticked for that person. Then when you tick you check against the value to make sure if it applies or not.

    The reason I'm suggesting this is because every new instance of a timer slowly generates more and more lag.

    Let me know if you want more info on how to apply this.
     
    • Two Thumbs Up Two Thumbs Up x 2
    • Like Like x 1
  9. TAChuck
    Offline

    TAChuck New Member

    Joined:
    Jul 1, 2015
    Messages:
    28
    Likes Received:
    4
    This is a bit more advance for me, since I never worked with dictionaries or lists before, but that might be a great opportunity to do it. It is by doing difficult things that you become better!

    The strange thing about this Timer is that I need to be able to set a different TimeSpan on some player (the better your roleplaying is, the quicker you gain xp). Would a Static Timer with a dictionary still work?
     
  10. Talow
    Offline

    Talow Member

    Joined:
    Aug 30, 2014
    Messages:
    276
    Likes Received:
    22
    my suggestion works by having one timer that fires every so often, so you'd have it fire at the fastest you'd ever to want it to trigger. Then checking when fired against the dictionary's values (date time) to see if it should apply to the player (the dictionaries keys). It requires a bit of thought but it's not really that difficult, Question, do you understand arrays?
     
    • Helpful Helpful x 1
  11. TAChuck
    Offline

    TAChuck New Member

    Joined:
    Jul 1, 2015
    Messages:
    28
    Likes Received:
    4
    Well, after reading your post, I went on to read about it! It took me a couple of try, but I managed to write a class using Arrays (a JaggedArray).

    So, know I understand them enough to work with them!
     
  12. Talow
    Offline

    Talow Member

    Joined:
    Aug 30, 2014
    Messages:
    276
    Likes Received:
    22
    • Two Thumbs Up Two Thumbs Up x 1
  13. TAChuck
    Offline

    TAChuck New Member

    Joined:
    Jul 1, 2015
    Messages:
    28
    Likes Received:
    4
    For a first try, I made a list to see If I were able to make It work.

    And It seems to work!

    So here's what I did, If someone need something similare :

    Code (C#):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using Server.Engines.XmlSpawner2;
    6.  
    7. namespace Server.Services.XmlSpawner2
    8. {
    9.     public class CoteTimer : Timer
    10.     {
    11.         private static readonly TimeSpan m_Delay = (TimeSpan.FromSeconds(5.0));
    12.  
    13.         public CoteTimer()
    14.             : base(m_Delay, m_Delay)
    15.         {
    16.             this.Priority = TimerPriority.OneSecond;
    17.         }
    18.  
    19.         private static readonly List<Mobile> m_PlayersList = new List<Mobile>();
    20.  
    21.         public static void Initialize()
    22.         {
    23.             new CoteTimer().Start();
    24.             EventSink.Login += new LoginEventHandler(EventSink_Login);
    25.             EventSink.Logout += new LogoutEventHandler(EventSink_Logout);
    26.         }
    27.  
    28.         private static void EventSink_Login(LoginEventArgs e)
    29.         {
    30.             Mobile mob = e.Mobile;
    31.             m_PlayersList.Add(mob);
    32.         }
    33.  
    34.         private static void EventSink_Logout(LogoutEventArgs e)
    35.         {
    36.             Mobile mob = e.Mobile;
    37.             m_PlayersList.Remove(mob);
    38.         }
    39.  
    40.         protected override void OnTick()
    41.         {
    42.             foreach (Mobile player in m_PlayersList)
    43.             {
    44.                 XmlCharManager c = (XmlCharManager)XmlAttach.FindAttachment(player, typeof(XmlCharManager));
    45.                 if (c != null)
    46.                 {
    47.                     c.GiveXp();
    48.                 }
    49.                 else
    50.                 {
    51.                     player.SendMessage("Erreur : Il vous manque un module");
    52.                 }
    53.             }
    54.         }
    55.     }
    56. }
    57.  
    The next part is to change the list for a Dictionnary with DateTime, so, the most difficult is behind.

    I'll add it to the post when I'll finish it.

    Talow, thank you so much for your advice, you were of a big help!
     
    • Two Thumbs Up Two Thumbs Up x 1
  14. Talow
    Offline

    Talow Member

    Joined:
    Aug 30, 2014
    Messages:
    276
    Likes Received:
    22
    Very welcome. you're doing an awesome job understanding the code.
     
    • Agree Agree x 1
  15. zerodowned
    Online

    Moderator ServUO Developer

    Joined:
    Jun 28, 2014
    Messages:
    1,412
    Likes Received:
    178
    Simple yet effective code; excellent use of lists, eventsinks, and static methods.

    Personally I would add a null check for player somewhere as its possible for one to be deleted but not be removed from the list.
     
    • Informative Informative x 1
Similar Threads: Reapetable Timer
Forum Title Date
Archived Bug Reports BOD timer Jun 7, 2017
Archived Bug Reports Server Crash - A timer issue? Dec 20, 2016
Script Support m_Mobile.Controlled check in CombatTimer in Mobile.cs - child properties in parent class? Nov 26, 2016
Script Support TaxPersistance Timer Problem Nov 23, 2016
Archived Bug Reports Pet bonding timer resetting Oct 17, 2016
Script Support Serializing a List of Timers Sep 30, 2016
Archived Bug Reports Persistance Timer Aug 19, 2016