Finaltwist

Squire
the circled is what i want a timer for ultimately. since its in a while loop, i don't want it to run superfast, instead id like to have a delay for each cycle of the loop.
also, that brings me to another question - if i wanted miliseconds, i can change the timer type, but how do i tell it to delay 500 ms?
Post automatically merged:

1595956141165.png
Post automatically merged:

1595956224183.png

we are using onetime on runuo for the healing orbs (you posted the fix to make it on time compatible and that works fine)
but its implemented in a different way there
Post automatically merged:

am i in the right direction here?
1595956341157.png
 

GoldDraco13

Squire
One time is always running in the back ground so basically you are picking up on its tick cycle, the interface min interval is 1 second and goes up from there do to the cpu overload the millisecond and tick caused. The events allow millisecond and tick but as per your script you only were using one second so this was a better fit. By having the interface attached to the item, the method in that item will be called on tick, now if you want to further work with delays longer then the base time of the tick, use a counter and switch statements within that method to call on specific ticks! I hope that makes sense!
Post automatically merged:

hrm, I see what you mean, let me get my head around your methods, I didn't really dive into your logic, just replaced the implementation!
Post automatically merged:

ok I see what you were doing, you wanted a one second delay to revert the bool back to true, so I would add this to the onetime method

Code:
        private int Delay { get; set; }
        private void OneTimeTick() 
        {
            if (!draintimer)
            {
                if (Delay > 0)
                {
                    draintimer = true;
                    Delay = 0;
                }
                else
                {
                    Delay++;
                }
            }
            else
            {
                Delay = 0;
            }
        }

No need to do anything in the curesedrain method, this will trigger the true after one sec of it going false!!
 
Last edited:

Voxpire

Vita-Nex: Core
Administrator
Simple delayed health drain mechanics traditional vs OneTime implementations...

Traditional: Initiating a local repeating timer, where 'from' is the drain target;
C#:
private Timer m_DrainTimer;
C#:
if (this.m_DrainTimer != null)
    this.m_DrainTimer.Stop();

this.m_DrainTimer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromMilliseconds(500), this.CursedDrain, from);
C#:
private void CursedDrain(Mobile from)
{
    if (this.Deleted || this.Hits >= this.HitsMax || from == null || from.Deleted || !from.Alive || from.Hits <= 0)
    {
        this.m_DrainTimer.Stop();
        this.m_DrainTimer = null;
    }
    else
    {
        int drain = Math.Min(5, from.Hits);

        from.Hits -= drain;
        this.Hits += drain;
    }
}

OnTime: Subscribe to the milliseconds event and implement sub-second delay handling, where 'm_DrainFrom' is the drain target inferred by 'from';
C#:
private long m_NextDrain;
private Mobile m_DrainFrom;
C#:
if (this.m_DrainFrom != null)
    OneTimeMilliEvent.MilliTimerTick -= this.CursedDrainHandler;

this.m_DrainFrom = from;
this.m_NextDrain = 0;

OneTimeMilliEvent.MilliTimerTick += this.CursedDrainHandler;
C#:
private void CursedDrainHandler(object sender, EventArgs args)
{
    if (this.Deleted || this.Hits >= this.HitsMax || this.m_DrainFrom == null || this.m_DrainFrom.Deleted || !this.m_DrainFrom.Alive || this.m_DrainFrom.Hits <= 0)
    {
        OneTimeMilliEvent.MilliTimerTick -= this.CursedDrainHandler;
        this.m_DrainFrom = null;
    }
    else if (Core.TickCount >= this.m_NextDrain)
    {
        int drain = Math.Min(5, this.m_DrainFrom.Hits);

        this.m_DrainFrom.Hits -= drain;
        this.Hits += drain;

        this.m_NextDrain = Core.TickCount + 500;
    }
}

Note these examples were written entirely in the forum editor and I cannot guarantee their functionality.
They are not intended to be copy/pasted, but merely to give reference to both perspectives for implementation.

'this' represents the current BaseCursed mobile reference, the context of these examples is taken from the code being placed in BaseCursed itself.

The main difference with OneTime is that you must cache a reference to anything you want to use in your event handler, whereas traditional timers allow you to pass those references directly to the handler.
 

Finaltwist

Squire
Thanks for the thorough write-up!

MY issue is that i am running a while loop

e.g.
while ( from.Hits >0 && this.InLOS(from) )

inside the loop, i need to run the health drain every x intervals, with a delay between each drain.

Would i then put this inside the while loop?

OneTimeMilliEvent.MilliTimerTick -= this.CursedDrainHandler;

this.m_DrainFrom = from;
this.m_NextDrain = 0;

OneTimeMilliEvent.MilliTimerTick += this.CursedDrainHandler;
 

Voxpire

Vita-Nex: Core
Administrator
Don't use a while statement for this.
Move everything from inside the while statement scope to a place that makes sense inside CursedDrainHandler
 

Kimuji

Citizen
Your events class are bugged:

It should be :
C#:
        public static void SendTick(object o, int time)
        {
            if (time == 1)
            {

                if (MinTimerTick != null)
                {
                    MinTimerTick.Invoke(o, EventArgs.Empty);
                }
                OneTimeEventHelper.SendIOneTime(4);
            }
        }

and not :
C#:
        public static void SendTick(object o, int time)
        {
            if (time == 1)
            {

                if (MinTimerTick != null)
                {
                    MinTimerTick.Invoke(o, EventArgs.Empty);
                   
                    OneTimeEventHelper.SendIOneTime(4);
                }
            }
        }


Because if you dont 'use MinTimerTick += ...

MinTimerTick is NULL and the interface IOneTime are not Ticked
 

GoldDraco13

Squire
The system uses one timer for both event and interface, so they both are within the null check as they BOTH use the tick! The system is NOT bugged!
 

Kimuji

Citizen
Try a clean install, without any of your example, and only make 1 item with " Item, IOneTime" and OneTimeType = 4;

You'll see the "OneTimeEventHelper.SendIOneTime(4);" is never called if it's in the != NULL check
 

Finaltwist

Squire
Hi there, hoping someone could help here - i created a container that does something on every onetimetick, and the system works great when the item is newly spawned. But as soon as you save/restart, the


public void OneTimeTick()
{

stops for some reason. I did a debug console message to make sure the method was ticking, but it isn't (after save/restart). As i said before, works great when the item is newly spawned, but as soon as i restart the system stops.
Post automatically merged:

did some more testing:

1. placed a onetime item with an overhead message saying "tick". it begins to tick every second (type 3)
2. save and restart
3. said item no longer ticks
4. placed another item right next to it, it ticks
5. save and restart
6. both items no longer tick

im running Runuo, but would there be a reason why those items are being dropped off from the onetime event handler list?
would there be a way to manually add the items back on restart (by using deserialize method?)
Post automatically merged:

i think i got it... onetimetype isn't being serialized....
Post automatically merged:

nope. negative. is it because the itms list in OneTimeEventHelper isn't restated every server restart?

I'm at a loss. help appreciated.
 
Last edited:

Kimuji

Citizen
Your events class are bugged:

It should be :
C#:
        public static void SendTick(object o, int time)
        {
            if (time == 1)
            {

                if (MinTimerTick != null)
                {
                    MinTimerTick.Invoke(o, EventArgs.Empty);
                }
                OneTimeEventHelper.SendIOneTime(4);
            }
        }

and not :
C#:
        public static void SendTick(object o, int time)
        {
            if (time == 1)
            {

                if (MinTimerTick != null)
                {
                    MinTimerTick.Invoke(o, EventArgs.Empty);
                  
                    OneTimeEventHelper.SendIOneTime(4);
                }
            }
        }


Because if you dont 'use MinTimerTick += ...

MinTimerTick is NULL and the interface IOneTime are not Ticked
The system uses one timer for both event and interface, so they both are within the null check as they BOTH use the tick! The system is NOT bugged!


Glad you finally recognized there was a bug and fixed it in the latest release with my suggestion

C#:
using System;

namespace Server.OneTime.Events
{
    public static class OneTimeMinEvent
    {
        public static event EventHandler MinTimerTick;

        public static void SendTick(object o, int time)
        {
            if (time == 1)
            {
                if (MinTimerTick != null)
                {
                    MinTimerTick.Invoke(o, EventArgs.Empty);
                 }

                OneTimeEventHelper.SendIOneTime(3);
            }
        }
    }
}