• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] One timer is cool and all

Status
Not open for further replies.
Level 31
Joined
Jul 10, 2007
Messages
6,306
Ok.... apparently I've been shooting too high on this, rofl... I tried out my tests on KT2 o-o... so... I'm doing good I guess ; ).

KT2 Vs Streams
I bet you would love to see this now wouldn't you : ), but I respect jesus4lyf so I'm not going to say the results =).

Streams (Timers) Vs Streams (Task Manager)
So what's the difference between these two? One uses Blizzard's Timers for Tasking timers and firing things off. The other uses its own custom task manager (runs on one timer ^_^).

Both are pretty much same speed... they lagged at the same rates ^_^; however, the Task Manager version still needs work (a bit complicated). The task manager version might also crash (stop working) on large sets of timers (like 7k+). The reason is because of the looping in it : ).

Both of them are hella faster than plain old timers when using the same periods. They also use precision to merge streams (timers) of the same period that are close to each other. The lower the precision, the less it merges. 0 is 0 merger unless they on exact same time =). The higher the period, the more the merges, and the more the performance, but the less accurate your first tick.

Both of them use data blocks as units. The data block size is that of the STREAM_RATE variable.

Stream Timers Version is a later version, so it uses definition overloading on the functions to make it nicer =), but this'll get introduced to Task Manager version as well.

The Stream Timers version is not that big... not even 200 lines with comments o-o. The Task Manager version is double size : p.

Uh... yea... so you can try them both out I suppose..

Oh yes.. and both of them beat out everything on data attachment : D. SetupStream must be called on both of them (to set your stream up), or the stream dies : (.

So... without further ado, v4.3 of Task Manager of v1.0 of Timers : D.

Timers Demo Code
Task Manager Demo Code isn't out because the Task Manager syntax is going to change to match Timers ^^
JASS:
include "cj_types.j"
include "cj_typesEx.j"
include "cj_print.j"
include "cj_types_priv.j"  
include "cj_typesEx_priv.j"
include "cj_order.j"  
include "cj_antibj_base.j"


scope Demo initializer Initialization {
    int loops
    int i = 1
    int size = 0
    trigger t = CreateTrigger()
    timer ti = CreateTimer()
    
    bool Test() {
        Stream.setup
        printf(I2S(Stream.get))
        return false
    }
    
    bool Setup() {
        loops = 1
        do {
            //TimerStart(CreateTimer(), ++size*.0125, true, function Test)
            size += 32
            Stream.add(size, function Test, 0)
            //KT_Add(function Test, 5, ++size*.0125)
        } whilenot --loops == 0
        return false
    }
    
    void Initialization() {
        TriggerAddCondition(t, Condition(function Setup))
        do {
            TriggerEvaluate(t)
        } whilenot --i == 0
    }
}

The Task Manager
JASS:
library Stream initializer Initialization {
/*System Information
//===================================================================
Name: Streams (Task Manager)
Version: 4.3
Author: Nestharus

Settings:
*///===================================================================
globals
    private constant real STREAM_RATE = .03125
    private constant int PRECISION = 1
endglobals
/*//===================================================================

Description:
This is a very fast and efficient timer system that runs on two timers, or known as streams.
One timer deals with whole numbers and the other timer deals with smaller numbers.

Requirements: None

Installation: NA

Variables:
-STREAM_RATE
    How many often the stream runs. The bigger the bit rate,
    the more accurate your timers can be. .03125 is a good value.

-PRECISION
    How precise streamed code is. The smaller the value, the more precise, but the more
    streams. The less precise, the less stream and higher performance. 0 is maximum precision.
    Each precision is 1 stream block (STREAM_RATE).

Functions:
------------------------------------------------------------------
-public int AddCode(int period, code c, int data)
    Will put code into the system. Returns a unique stream.
    
-public void RemoveCode()
-public void RemoveStreamCode(Stream theStream)
    Will remove a specific or current running stream from the system
    
-public constant int GetAge()
-public constant int GetStreamAge(Stream theStream)
    Will get the age of a specified or current running strema.
    
-public constant int GetTime()
-public constant int GetStreamTime(Stream theStream)
    Will get timeout of a specified or current running stream
    
-public constant int GetStream()
    Will get the current running stream
    
-public void SetData(int value)
-public void SetStreamData(Stream theStream, int value)
    Set data on a specified or current running stream
    
-public int GetData()
-public int GetStreamData(Stream theStream)
    Get data for a specified or current running stream
    
-public constant int GetInterval()
-public constant int GetStreamInterval(Stream theStream)
    Returns a master stream's interval. Will automatically retrieve the master stream
    that a stream is on.

-public void SetStreamInterval(Stream theStream, int value)
-public void SetInterval(int value)
    Will forcefully set a master stream's interval and will take effect on next tick.
    This will change all streams on the master stream. To change a time out, you should
    remove the stream and re-add it into the system! This can also cause two master streams
    to have the same value. Be careful with this function.
    
-public constant int GetRemainingTime(Stream theStream)
    Will return the remaining time of a given stream
    
-public int R2B(real r)
    Will convert a real time into a stream block for use in the system
    
------------------------------------------------------------------*/
//===================================================================    
    private int time = 0
    
    public keyword RunStack
    
    private struct Stream extends array {
        public Stream last
        public int birth
        public int interval
        public Stream master
        public Stream next
        public Stream previous
        public int data
        public triggercondition conditionCode
        public trigger runStream
        public RunStack stack
        public int size
    }
    
    public struct RunStack extends array {
        public static int index = 0
        public static int array stack
        public static int stackIndex = 0
        public static RunStack current = 0
        public static RunStack last = 0
        public int time
        public RunStack previous
        public RunStack next
        public Stream data
    }
    
    private int array streamStack
    private int streamStackIndex = 0
    private int streamIndex = 0
    
    public Stream stream
    
    private Stream masterStream = 0
    public RunStack runStack = 0
    public int i
    private int i2
    private int i3
    private bool fin = false
    
    private hashtable streams = InitHashtable()
    
    private timer streamProcess = CreateTimer()
    
    define SetupStream = {
        if Stream_stream == -1 {Stream_stream = Stream_RunStack(Stream_i).data.next}
        else {Stream_stream = Stream_stream.next}
    }
    
    public int GetData() {
        return stream.data
    }
    
    public void SetData(int value) {
        stream.data = value
    }
    
    public constant int GetStream() {
        return stream
    }
    
    public constant int GetTime() {
        return time
    }
    
    public constant int GetRemainingTime(Stream theStream) {
        return theStream.master.stack.time - time
    }
    
    public constant int GetAge() {
        return time - stream.birth
    }
    
    public constant int GetInterval() {
        return stream.master.interval
    }
    
    public void SetInterval(int value) {
        stream.master.interval = value
    }
    
    public void RemoveCode() {
        RELEASE_STREAM(stream)
        TriggerRemoveCondition(stream.runStream, stream.conditionCode)
        stream.data = 0
        REMOVE_STREAM(stream)
    }
    
    public int GetStreamData(Stream theStream) {
        return theStream.data
    }
    
    public void SetStreamData(Stream theStream, int value) {
        theStream.data = value
    }
    
    public int R2B(real r) {
        return R2I((r/STREAM_RATE)+.5)
    }
    
    public constant int GetStreamTime(Stream theStream) {
        return theStream.master.stack.time
    }
    
    public constant int GetStreamAge(Stream theStream) {
        return time - theStream.birth
    }
    
    public void RemoveStreamCode(Stream theStream) {
        RELEASE_STREAM(theStream)
        TriggerRemoveCondition(theStream.runStream, theStream.conditionCode)
        theStream.data = 0
        REMOVE_STREAM(theStream)
    }
    
    public constant int GetStreamInterval(Stream theStream) {
        return theStream.master.interval
    }
    
    public void SetStreamInterval(Stream theStream, int value) {
        theStream.master.interval = value
    }
    
    define private NEW_STREAM_STACK(streamName) = {
        if RunStack.stackIndex != 0 {
            streamName = RunStack.stack[RunStack.stackIndex--]
        }
        else {
            streamName = ++RunStack.index
        }
    }
    
    define private NEW_STREAM(streamName) = {
        if streamStackIndex != 0 {
            streamName = streamStack[streamStackIndex--]
        }
        else {
            streamName = ++streamIndex
        }
    }
    
    define private RELEASE_STREAM(streamName) = {
        streamStack[++streamStackIndex] = streamName
    }
    
    define private REMOVE_STREAM(streamName) = {
        if streamName.last == streamName {
            streamName.master.last = streamName
        }
        streamName.previous.next = streamName.next
        streamName.next.previous = streamName.previous
        streamName.master.size--
        if streamName.master.size == 0 {
            RemoveSavedInteger(streams, masterStream.interval, masterStream.birth - (masterStream.birth - masterStream.interval))
            masterStream = streamName.master
            RELEASE_STREAM(masterStream)
            DestroyTrigger(masterStream.runStream)
            masterStream.stack.next.previous = masterStream.stack.previous
            masterStream.stack.previous.next = masterStream.stack.next
            if RunStack.current == masterStream.stack {
                RunStack.current = RunStack.current.next
                RunStack.current.previous = 0
            }
            if RunStack.last == masterStream.stack {
                RunStack.last = RunStack.last.previous
                RunStack.last.next = 0
            }
            RunStack.stack[++RunStack.stackIndex] = masterStream.stack
        }
    }
    
    define private RUN_STREAM_STACK_NEW(runStackNew) = {
        if RunStack.current == 0 {
            RunStack.current = runStackNew
            RunStack.last = runStackNew
            runStackNew = runStackNew
            runStackNew = runStackNew
            runStack.time = masterStream.interval + time
            fin = true
        }
    }
    
    define private RUN_STREAM_STACK_DO_GREATER_THAN(runStackOld, runStackNew) = {
        if runStackOld.data.interval+time >= masterStream.interval + time {
            if runStackOld.previous != 0 {
                runStackNew.previous = runStackOld.previous
                runStackOld.previous.next = runStackNew
            }
            else {
                RunStack.current = runStackNew
            }
            runStackOld.previous = runStackNew
            runStackNew.next = runStackOld
        }
    }
    
    define private RUN_STREAM_STACK_DO_LESS_THAN(runStackOld, runStackNew) = {
        if runStackOld.data.interval+time <= masterStream.interval + time {
            if runStackOld.next != 0 {
                runStackNew.next = runStackOld.next
                runStackOld.next.previous = runStackNew
            }
            else {
                RunStack.last = runStackNew
            }
            runStackNew.previous = runStackOld
            runStackOld.next = runStackNew
        }
    }
    
    define private RUN_STREAM_STACK_GREATER_THAN(runStackOld, runStackNew) = {
        if runStackOld.data.interval+time > masterStream.interval + time {
            i = runStackOld
            whilenot RunStack(i).previous.data == 0 || RunStack(i).data.interval+time >= masterStream.interval + time {
                i = RunStack(i).previous
            }
            RUN_STREAM_STACK_DO_GREATER_THAN(RunStack(i), runStackNew)
            RUN_STREAM_STACK_DO_LESS_THAN(RunStack(i), runStackNew)
            runStackNew = runStackNew
            runStackNew = runStackNew
            runStack.time = masterStream.interval + time
            fin = true
        }
    }
    
    define private RUN_STREAM_STACK_LESS_THAN(runStackOld, runStackNew) = {
        if runStackOld.data.interval+time < masterStream.interval + time {
            i = runStackOld
            whilenot RunStack(i).next == 0 || RunStack(i).data.interval+time >= masterStream.interval + time {
                i = RunStack(i).next
            }
            i = RunStack(i)
            RUN_STREAM_STACK_DO_GREATER_THAN(RunStack(i), runStackNew)
            RUN_STREAM_STACK_DO_LESS_THAN(RunStack(i), runStackNew)
            runStackNew = runStackNew
            runStackNew = runStackNew
            runStack.time = masterStream.interval + time
            fin = true
        }
    }
    
    public int AddCode(int period, code c, int data) {
        fin = false
        i2 = PRECISION*-1
        do {
            i = LoadInteger(streams, period, time-(time-period)+i2)
            i2++
        } whilenot i != 0 || i2 == PRECISION
        if i == 0 {
            fin = false
            NEW_STREAM(masterStream)
            masterStream.master = masterStream
            masterStream.last = masterStream
            masterStream.interval = period
            masterStream.birth = time
            masterStream.runStream = CreateTrigger()
            SaveInteger(streams, period, time-(time-period), masterStream)
            NEW_STREAM_STACK(runStack)
            RUN_STREAM_STACK_NEW(runStack)
            if !fin {
                RUN_STREAM_STACK_GREATER_THAN(RunStack.current, runStack)
            }
            if !fin {
                RUN_STREAM_STACK_LESS_THAN(RunStack.current, runStack)
            }
            masterStream.stack = runStack
            runStack.data = masterStream
        }
        else {
            masterStream = i
        }
        NEW_STREAM(stream)
        masterStream.last.next = stream
        stream.previous = masterStream.last
        masterStream.last = stream
        stream.master = masterStream
        stream.birth = time
        stream.conditionCode = TriggerAddCondition(masterStream.runStream, Condition(c))
        masterStream.size++
        stream.data = data
        return stream
    }
    
    private void StreamProcess() {
        time++
        if RunStack.current.time == time {
            if RunStack.current.next != 0 {
                i = RunStack.current
                runStack = RunStack(i).next
                do {
                    stream = -1
                    TriggerEvaluate(RunStack(i).data.runStream)
                    RunStack(i).time = RunStack(i).data.interval + time
                    i3 = RunStack(i).next
                    runStack = i2
                    if (RunStack(i).time < runStack.time && RunStack(i).time < runStack.previous.time) {
                        runStack = RunStack(i).next
                    }
                    whilenot RunStack(i).time < runStack.time || runStack.next == 0 {
                        runStack = runStack.next
                    }
                    if RunStack(i).next != runStack {
                        if RunStack(i).time <= runStack.time {
                            runStack.previous.next = i
                            RunStack(i).previous.next = RunStack(i).next
                            RunStack(i).next.previous = RunStack(i).previous
                            RunStack(i).previous = runStack.previous
                            runStack.previous = i
                            RunStack(i).next = runStack
                        }
                        else {
                            RunStack(i).previous.next = RunStack(i).next
                            RunStack(i).next.previous = RunStack(i).previous
                            RunStack(i).next = runStack.next
                            RunStack(i).previous = runStack
                            runStack.next = i
                        }
                        if RunStack(i) == RunStack.current {
                            RunStack.current = i3
                        }
                        if runStack == RunStack.last {
                            RunStack.last = i
                        }
                    }
                    i2 = i
                    i = i3
                } whilenot RunStack(i).time != time
            }
            else {
                stream = -1
                i = RunStack.current
                TriggerEvaluate(RunStack.current.data.runStream)
                RunStack.current.time = RunStack.current.data.interval + time
            }
        }
    }
    
    private void Initialization() {
        stream = -1
        TimerStart(streamProcess, STREAM_RATE, true, function StreamProcess)
    }
}

Timers
JASS:
library Stream initializer Initialization uses GameTime, Recycle {
/*System Information
//===================================================================
Name: Streams (Timers)
Version: 1.0
Author: Nestharus

Settings:
*///===================================================================
globals
    public constant real STREAM_RATE = .03125
    private constant int PRECISION = 1
endglobals
/*//===================================================================

Description:
A timer system that merges timers into master streams.

Requirements: None

Installation: NA

Variables:
-STREAM_RATE
    Size of a block in a stream

-PRECISION
    How precise streamed code is. The smaller the value, the more precise, but the more
    streams. The less precise, the less stream and higher performance. 0 is maximum precision.

Functions:
------------------------------------------------------------------
Methods/Operators
-Stream.add(int period, code c, int data)
    Will put code into the system. Returns a unique stream.
    
-Stream.remove()
-Stream.removeStream(Stream theStream)
    Will remove a specific or current running stream from the system
    
-Stream.getAge
-Stream.getAge(theStream)
    Will get the age of a specified or current running strema.
    
-Stream.getTime
-Stream.getTime(Stream theStream)
    Will get timeout of a specified or current running stream
    
-Stream.getRemaining
-Stream.getRemaining(Stream theStream)
    Will get remaining time of a specified or current running stream
    
-Stream.get()
    Will get the current running stream
    
-Stream.setData(value)
-Stream.setData(theStream, value)
    Set data on a specified or current running stream
    
-Stream.getData
-Stream.getData(theStream)
    Get data for a specified or current running stream
    
-Stream.getInterval()
-Stream.getInterval(Stream theStream)
    Returns a master stream's interval. Will automatically retrieve the master stream
    that a stream is on.
    
-Stream.R2B(real r)
    Will convert a real time into a stream block for use in the system
    
-Stream.Setup
    Sets the stream up. Must be called on all timer functions
------------------------------------------------------------------*/
//===================================================================
    private int time = 0
    
    public Stream stream = -1
    public Stream masterStream = 0
    public int i = 0
    private int timeout
    
    private boolexpr streamSetup
    
    private hashtable streams = InitHashtable()
    
    struct Stream extends array {
        public static int array stack
        public static int index = 0
        public static int stackIndex = 0
        public Stream master
        public int interval
        public Stream previous
        public Stream next
        public Stream last
        public triggercondition conditionCode
        public trigger runStream
        public timer runStreamTimer
        public int birth
        public int data
        
        public static void remove() {
            ReleaseStream(stream)
            TriggerRemoveCondition(stream.runStream, stream.conditionCode)
            stream.data = 0
            RemoveStream(stream)
        }
        
        public static void removeStream(Stream theStream) {
            ReleaseStream(theStream)
            TriggerRemoveCondition(theStream.runStream, theStream.conditionCode)
            theStream.data = 0
            RemoveStream(theStream)
        }
        
        define private NewStream(streamName) = {
            if Stream.stackIndex != 0 {
                streamName = Stream.stack[Stream.stackIndex--]
            }
            else {
                streamName = ++Stream.index
            }
        }
        
        public static bool StreamSetup() {
            time = R2I(GetElapsedGameTime()*STREAM_RATE)
            timeout = R2I(TimerGetTimeout(GetExpiredTimer())/STREAM_RATE)
            stream = LoadInteger(streams, timeout , time-(time-timeout))
            return false
        }
        
        public static int add(int period, code c, int data) {
            i = PRECISION*-1
            time = R2I(GetElapsedGameTime()*STREAM_RATE)
            do {
                masterStream = LoadInteger(streams, period, time-(time-period)+i)
                i++
            } whilenot integer(masterStream) != 0 || i == PRECISION
            if integer(masterStream) == 0 {
                NewStream(masterStream)
                masterStream.last = masterStream
                masterStream.interval = period
                masterStream.birth = time
                masterStream.runStream = CreateTrigger()
                masterStream.runStreamTimer = Timer.get()
                TriggerRegisterTimerExpireEvent(masterStream.runStream, masterStream.runStreamTimer)
                TriggerAddCondition(masterStream.runStream, streamSetup)
                TimerStart(masterStream.runStreamTimer, I2R(period)*STREAM_RATE, true, null)
                SaveInteger(streams, period, time-(time-period), masterStream)
            }
            NewStream(stream)
            masterStream.last.next = stream
            stream.previous = masterStream.last
            masterStream.last = stream
            stream.master = masterStream
            stream.birth = time
            stream.conditionCode = TriggerAddCondition(masterStream.runStream, Condition(c))
            stream.data = data
            return stream
        }
    }
    
    define {
        <Stream.getData> = Stream_stream.data
        <Stream.getData>(theStream) = Stream_Stream(theStream).data
        <Stream.setData>(value) = Stream_stream.data
        <Stream.setData>(theStream, value) = Stream_Stream(theStream) = value
        <Stream.get> = Stream_stream
        <Stream.getAge> = GetElapsedGameTime() - I2R(Stream_stream.birth)/STREAM_RATE
        <Stream.getAge>(theStream) = GetElapsedGameTime() - I2R(Stream_Stream(theStream).birth)/STREAM_RATE
        <Stream.R2B>(realVal) = R2I((realVal/Stream_STREAM_RATE)+.5)
        <Stream.getTime> = TimerGetElapsed(Stream_stream.master.runStreamTimer)
        <Stream.getTime>(theStream) = TimerGetElapsed(Stream_Stream(theStream).master.runStreamTimer)
        <Stream.getInterval> = Stream_stream.master.interval
        <Stream.getInterval>(theStream) = Stream_Stream(theStream).master.interval
        <Stream.getRemaining> = TimerGetRemaining(Stream_stream.master.runStreamTimer)
        <Stream.getRemaining>(theStream) = TimerGetRemaining(Stream_stream.master.runStreamTimer)
        <Stream.setup> = Stream_stream = Stream_stream.next
    }
    
    define private ReleaseStream(streamName) = Stream.stack[++Stream.stackIndex] = streamName
    
    define private RemoveStream(streamName) = {
        if streamName.master.last == streamName {
            streamName.master.last = streamName.previous
        }
        streamName.previous.next = streamName.next
        streamName.next.previous = streamName.previous
        if streamName.master.last == streamName.master {
            masterStream = streamName.master
            RemoveSavedInteger(streams, masterStream.interval, masterStream.birth - (masterStream.birth - masterStream.interval))
            ReleaseStream(masterStream)
            DisableTrigger(masterStream.runStream)
            TriggerRemoveCondition(masterStream.runStream, masterStream.conditionCode)
            DestroyTrigger(masterStream.runStream)
            PauseTimer(masterStream.runStreamTimer)
            Timer.release(masterStream.runStreamTimer)
        }
    }
    
    private void Initialization() {
        streamSetup = Condition(function Stream.StreamSetup)
    }
}
 
Last edited:
Level 29
Joined
Jul 29, 2007
Messages
5,174
Put that code in a hidden tag.
Put your comments in a COMMENT block.
You should probably mention this uses cJass (I suppose that's what it is?).
Where the hell is there a description that says what's this supposed to do? Because "This is a very fast ... other timer deals with smaller numbers." doesn't explain a thing.
 
Status
Not open for further replies.
Top