System Timer Ticker

Cohadar

master of fugue
Reaction score
209
v4.1 (compatibility release for patch 1.23b)
JASS:

//==============================================================================
//  TT -- TIMER TICKER SYSTEM BY COHADAR -- v4.1
//==============================================================================
//
//  PURPOUSE OF TT:
//       * Passing data to timers
//       * Avoiding direct use of timer handles
//
//  PROS: 
//       * It is easier than using attaching
//       * It is optimized to use only one timer on default high frequency
//       * GetData method is the same for all timer frequencies
//
//  CONS:
//       * You must remember to always return true from your function
//         when you want to stop timer, even if it is of one-shot type.
//         (otherwise it will leak)
//
//  START FUNCTIONS:
//       * TT_Start(userFunc, struct)
//       * TT_StartEx(userFunc, struct, period)
//       * TT_Once(userFunc, struct, timeout)
//       * TT_StartTimerDialog(userFunc, struct, timeout) -> timerdialog
//
//       * userFunc is a user function that takes nothing and returns boolean
//         it will be periodically called by the system until it returns true.
//
//  GET FUNCTIONS:
//       * TT_GetData() -> struct
//       * TT_GetTimerDialog() -> timerdialog
//
//       * These functions can only be called from inside userFunc
//         TT_GetData() will return struct passed to any of the start functions
//         TT_GetTimerDialog() returns timerdialog created by TT_StartTimerDialog
//
//  DETAILS:
//       * On default frequency all user functions are stored in an array.
//         Timer will call all those functions each period.
//
//       * While user function returns false timer will continue to call it each period
//         Once user function returns true it will be removed from system
//
//       * TT is using smart timer preloading and simple hash
//         When colliding timer handle is found that timer is simply discarded
//
//  REQUIREMENTS:
//       * NewGen v4c and above (there might be some problems with older NewGen's)  
//
//  HOW TO IMPORT:
//       * Just create a trigger named TT
//       * convert it to text and replace the whole trigger text with this one
//
//==============================================================================
library TT initializer Init

//==============================================================================
//  Configuration
//==============================================================================
globals
    // List of recommended periods for high-frequency timer:
    // 0.04    = 25 calls per second
    // 0.03125 = 32 calls per second
    // 0.025   = 40 calls per second
    // 0.02    = 50 calls per second
    public constant real PERIOD = 0.03125
    
    // how many low-frequency timers to preload
    // system can safely extend beyond this limit
    private constant integer PRELOAD = 32
endglobals
//==============================================================================
//  End of Configuration
//==============================================================================


//==============================================================================
globals
    // "frames per second" of high-frequency timer
    public constant integer FPS = R2I(1.0/PERIOD)

    // globals for passing data to userFunc
    private integer Data
    private timerdialog timerDialog
    
    // One Timer to rule them all, One Timer to find them,
    // One Timer to call them all and in the jass bind them
    // In the land of warcraft where the desyncs lie.
    private timer   HF_Timer = CreateTimer()
    private integer HF_Counter = 0
    private trigger array HF_Triggz
    private integer array HF_Dataz
    
    // we can safely use dummy hashing here because timers are preloaded
    private constant integer LF_HASH = 8191
    
    private integer array LF_Dataz
    private trigger array LF_Triggz
    private timer array LF_Timerz
    private timerdialog array LF_Dialogz
    
    // recycling
    private integer array LF_Indexz
    private integer LF_Counter = PRELOAD    
endglobals

//==============================================================================
// note how colliding timer handles are discarded
// so TT would work properly even after preload limit break
//==============================================================================
private function NewIndex takes nothing returns integer
    local integer i
    local timer t
    if (LF_Counter==0) then  
        loop
            debug call BJDebugMsg("WARNING: TT reached preloaded timer limit!")
            set t = CreateTimer()
            set i = GetHandleId(t)
            set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
            if LF_Timerz<i> == null then
                set LF_Timerz<i> = t
                set LF_Triggz<i> = CreateTrigger()
                return i
            endif
        endloop
    endif  
    set LF_Counter = LF_Counter - 1 
    return LF_Indexz[LF_Counter]
endfunction

//==============================================================================
private function HF_Handler takes nothing returns nothing
    local trigger swap
    local integer i = HF_Counter
    loop
        exitwhen i&lt;=0
        set Data = HF_Dataz<i>
        if TriggerEvaluate(HF_Triggz<i>) then
            set swap = HF_Triggz<i>
            call TriggerClearConditions(swap)
            set HF_Triggz<i> = HF_Triggz[HF_Counter]
            set HF_Triggz[HF_Counter] = swap
            set HF_Dataz<i> = HF_Dataz[HF_Counter]
            set HF_Counter = HF_Counter - 1
        endif
        set i = i - 1
    endloop
    // who can guess why am I not nulling swap here?
endfunction

//==============================================================================
private function LF_Handler takes nothing returns nothing
    local integer i = GetHandleId(GetExpiredTimer())
    set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
    set Data = LF_Dataz<i>
    if TriggerEvaluate(LF_Triggz<i>) then
        // recycle the trigger and timer
        call TriggerClearConditions(LF_Triggz<i>)
        call PauseTimer(LF_Timerz<i>)
        set LF_Indexz[LF_Counter] = i
        set LF_Counter = LF_Counter + 1
    endif
endfunction

//==============================================================================
//  Periodic timer that runs on TT_PERIOD
//==============================================================================
public function Start takes code userFunc, integer data returns nothing
    debug if userFunc == null then
    debug    call BJDebugMsg(&quot;ERROR: TT_Start - null userFunc&quot;)
    debug    return
    debug endif

    set HF_Counter = HF_Counter + 1    
    
    if HF_Triggz[HF_Counter] == null then
        set HF_Triggz[HF_Counter] = CreateTrigger()
    endif
    
    set HF_Dataz[HF_Counter] = data
    call TriggerAddCondition(HF_Triggz[HF_Counter], Condition(userFunc))
endfunction

//==============================================================================
//  Periodic timer with custom period
//==============================================================================
public function StartEx takes code userFunc, integer data, real period returns nothing
    local integer i
    debug if userFunc == null then
    debug     call BJDebugMsg(&quot;ERROR: TT_StartEx - null userFunc&quot;)
    debug     return
    debug endif
    set i = NewIndex()
    call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
    set LF_Dataz<i> = data
    call TimerStart(LF_Timerz<i>, period, true, function LF_Handler)
endfunction

//==============================================================================
//  One shot timer, remember to return true in userFunc
//==============================================================================
public function Once takes code userFunc, integer data, real timeout returns nothing
    local integer i
    debug if userFunc == null then
    debug     call BJDebugMsg(&quot;ERROR: TT_Once - null userFunc&quot;)
    debug     return
    debug endif
    set i = NewIndex()
    call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
    set LF_Dataz<i> = data
    call TimerStart(LF_Timerz<i>, timeout, false, function LF_Handler)
endfunction

//==============================================================================
public function StartTimerDialog takes code userFunc, integer data, real timeout returns timerdialog
    local integer i
    debug if userFunc == null then
    debug     call BJDebugMsg(&quot;ERROR: TT_StartTimerDialog - null userFunc&quot;)
    debug     return null
    debug endif
    set i = NewIndex()
    call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
    set LF_Dataz<i> = data
    call TimerStart(LF_Timerz<i>, timeout, false, function LF_Handler)
    set bj_lastCreatedTimerDialog = CreateTimerDialog(LF_Timerz<i>)
    set LF_Dialogz<i> = bj_lastCreatedTimerDialog
    return bj_lastCreatedTimerDialog
endfunction

//==============================================================================
//  Call this function only inside the userFunc
//==============================================================================
public function GetData takes nothing returns integer
    return Data
endfunction

//==============================================================================
//  Call this function only inside the userFunc
//==============================================================================
public function GetTimerDialog takes nothing returns timerdialog
    local integer i = GetHandleId(GetExpiredTimer())
    set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
    return LF_Dialogz<i> 
endfunction

//==============================================================================
//  Preload LF timers and start HF timer.
//==============================================================================
private function Init takes nothing returns nothing
    local integer i
    local timer t
    local integer j = 0
    loop
        exitwhen j&gt;=PRELOAD
        set t = CreateTimer()
        set i = GetHandleId(t)
        set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash        
        if LF_Timerz<i> == null then
            set LF_Timerz<i> = t
            set LF_Triggz<i> = CreateTrigger()
            set LF_Indexz[j] = i
            set j = j + 1
        endif        
    endloop

    call TimerStart(HF_Timer, PERIOD, true, function HF_Handler)  
endfunction

endlibrary

//==============================================================================
//  END OF TIMER TICKER SYSTEM
//==============================================================================
</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>




v4.0
JASS:

//==============================================================================
//  TT -- TIMER TICKER SYSTEM BY COHADAR -- v4.0
//==============================================================================
//
//  PURPOUSE OF TT:
//       * Passing data to timers
//       * Avoiding direct use of timer handles
//
//  PROS: 
//       * It is easier than using attaching
//       * It is optimized to use only one timer on default high frequency
//       * GetData method is the same for all timer frequencies
//
//  CONS:
//       * You must remember to always return true from your function
//         when you want to stop timer, even if it is of one-shot type.
//         (otherwise it will leak)
//
//  START FUNCTIONS:
//       * TT_Start(userFunc, struct)
//       * TT_StartEx(userFunc, struct, period)
//       * TT_Once(userFunc, struct, timeout)
//       * TT_StartTimerDialog(userFunc, struct, timeout) -&gt; timerdialog
//
//       * userFunc is a user function that takes nothing and returns boolean
//         it will be periodically called by the system until it returns true.
//
//  GET FUNCTIONS:
//       * TT_GetData() -&gt; struct
//       * TT_GetTimerDialog() -&gt; timerdialog
//
//       * These functions can only be called from inside userFunc
//         TT_GetData() will return struct passed to any of the start functions
//         TT_GetTimerDialog() returns timerdialog created by TT_StartTimerDialog
//
//  DETAILS:
//       * On default frequency all user functions are stored in an array.
//         Timer will call all those functions each period.
//
//       * While user function returns false timer will continue to call it each period
//         Once user function returns true it will be removed from system
//
//       * TT is using smart timer preloading and simple hash
//         When colliding timer handle is found that timer is simply discarded
//
//  REQUIREMENTS:
//       * NewGen v4c and above (there might be some problems with older NewGen&#039;s)  
//
//  HOW TO IMPORT:
//       * Just create a trigger named TT
//       * convert it to text and replace the whole trigger text with this one
//
//==============================================================================
library TT initializer Init

//==============================================================================
//  Configuration
//==============================================================================
globals
    // List of recommended periods for high-frequency timer:
    // 0.04    = 25 calls per second
    // 0.03125 = 32 calls per second
    // 0.025   = 40 calls per second
    // 0.02    = 50 calls per second
    public constant real PERIOD = 0.03125
    
    // how many low-frequency timers to preload
    // system can safely extend beyond this limit
    private constant integer PRELOAD = 32
endglobals
//==============================================================================
//  End of Configuration
//==============================================================================


//==============================================================================
globals
    // &quot;frames per second&quot; of high-frequency timer
    public constant integer FPS = R2I(1.0/PERIOD)

    // globals for passing data to userFunc
    private integer Data
    private timerdialog timerDialog
    
    // One Timer to rule them all, One Timer to find them,
    // One Timer to call them all and in the jass bind them
    // In the land of warcraft where the desyncs lie.
    private timer   HF_Timer = CreateTimer()
    private integer HF_Counter = 0
    private trigger array HF_Triggz
    private integer array HF_Dataz
    
    // we can safely use dummy hashing here because timers are preloaded
    private constant integer LF_HASH = 8191
    
    private integer array LF_Dataz
    private trigger array LF_Triggz
    private timer array LF_Timerz
    private timerdialog array LF_Dialogz
    
    // recycling
    private integer array LF_Indexz
    private integer LF_Counter = PRELOAD    
endglobals

//==============================================================================
private constant function H2I takes handle h returns integer
    return h
    return 0
endfunction

//==============================================================================
// note how colliding timer handles are discarded
// so TT would work properly even after preload limit break
//==============================================================================
private function NewIndex takes nothing returns integer
    local integer i
    local timer t
	if (LF_Counter==0) then  
        loop
            debug call BJDebugMsg(&quot;WARNING: TT reached preloaded timer limit!&quot;)
            set t = CreateTimer()
            set i = H2I(t)
            set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
            if LF_Timerz<i> == null then
                set LF_Timerz<i> = t
                set LF_Triggz<i> = CreateTrigger()
                return i
            endif
		endloop
	endif  
	set LF_Counter = LF_Counter - 1 
	return LF_Indexz[LF_Counter]
endfunction

//==============================================================================
private function HF_Handler takes nothing returns nothing
    local trigger swap
    local integer i = HF_Counter
    loop
        exitwhen i&lt;=0
        set Data = HF_Dataz<i>
        if TriggerEvaluate(HF_Triggz<i>) then
            set swap = HF_Triggz<i>
            call TriggerClearConditions(swap)
            set HF_Triggz<i> = HF_Triggz[HF_Counter]
            set HF_Triggz[HF_Counter] = swap
            set HF_Dataz<i> = HF_Dataz[HF_Counter]
            set HF_Counter = HF_Counter - 1
        endif
        set i = i - 1
    endloop
    // who can guess why am I not nulling swap here?
endfunction

//==============================================================================
private function LF_Handler takes nothing returns nothing
    local integer i = H2I(GetExpiredTimer())
    set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
    set Data = LF_Dataz<i>
    if TriggerEvaluate(LF_Triggz<i>) then
        // recycle the trigger and timer
        call TriggerClearConditions(LF_Triggz<i>)
        call PauseTimer(LF_Timerz<i>)
        set LF_Indexz[LF_Counter] = i
        set LF_Counter = LF_Counter + 1
    endif
endfunction

//==============================================================================
//  Periodic timer that runs on TT_PERIOD
//==============================================================================
public function Start takes code userFunc, integer data returns nothing
    debug if userFunc == null then
    debug    call BJDebugMsg(&quot;ERROR: TT_Start - null userFunc&quot;)
    debug    return
    debug endif

    set HF_Counter = HF_Counter + 1    
    
    if HF_Triggz[HF_Counter] == null then
        set HF_Triggz[HF_Counter] = CreateTrigger()
    endif
    
    set HF_Dataz[HF_Counter] = data
    call TriggerAddCondition(HF_Triggz[HF_Counter], Condition(userFunc))
endfunction

//==============================================================================
//  Periodic timer with custom period
//==============================================================================
public function StartEx takes code userFunc, integer data, real period returns nothing
    local integer i
    debug if userFunc == null then
    debug     call BJDebugMsg(&quot;ERROR: TT_StartEx - null userFunc&quot;)
    debug     return
    debug endif
    set i = NewIndex()
    call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
    set LF_Dataz<i> = data
    call TimerStart(LF_Timerz<i>, period, true, function LF_Handler)
endfunction

//==============================================================================
//  One shot timer, remember to return true in userFunc
//==============================================================================
public function Once takes code userFunc, integer data, real timeout returns nothing
    local integer i
    debug if userFunc == null then
    debug     call BJDebugMsg(&quot;ERROR: TT_Once - null userFunc&quot;)
    debug     return
    debug endif
    set i = NewIndex()
    call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
    set LF_Dataz<i> = data
    call TimerStart(LF_Timerz<i>, timeout, false, function LF_Handler)
endfunction

//==============================================================================
public function StartTimerDialog takes code userFunc, integer data, real timeout returns timerdialog
    local integer i
    debug if userFunc == null then
    debug     call BJDebugMsg(&quot;ERROR: TT_StartTimerDialog - null userFunc&quot;)
    debug     return null
    debug endif
    set i = NewIndex()
    call TriggerAddCondition(LF_Triggz<i>, Condition(userFunc))
    set LF_Dataz<i> = data
    call TimerStart(LF_Timerz<i>, timeout, false, function LF_Handler)
    set bj_lastCreatedTimerDialog = CreateTimerDialog(LF_Timerz<i>)
    set LF_Dialogz<i> = bj_lastCreatedTimerDialog
    return bj_lastCreatedTimerDialog
endfunction

//==============================================================================
//  Call this function only inside the userFunc
//==============================================================================
public function GetData takes nothing returns integer
    return Data
endfunction

//==============================================================================
//  Call this function only inside the userFunc
//==============================================================================
public function GetTimerDialog takes nothing returns timerdialog
    local integer i = H2I(GetExpiredTimer())
    set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash
    return LF_Dialogz<i> 
endfunction

//==============================================================================
//  Preload LF timers and start HF timer.
//==============================================================================
private function Init takes nothing returns nothing
    local integer i
    local timer t
    local integer j = 0
    loop
        exitwhen j&gt;=PRELOAD
        set t = CreateTimer()
        set i = H2I(t)
        set i = i - (i / LF_HASH) * LF_HASH // dummy modulo hash        
        if LF_Timerz<i> == null then
            set LF_Timerz<i> = t
            set LF_Triggz<i> = CreateTrigger()
            set LF_Indexz[j] = i
            set j = j + 1
        endif        
    endloop

    call TimerStart(HF_Timer, PERIOD, true, function HF_Handler)  
endfunction

endlibrary

//==============================================================================
//  END OF TIMER TICKER SYSTEM
//==============================================================================
</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>



This version is a merge of TT v3.4 and ABCT v3.0
Bonus is a support for TimerDialogs.

Function signatures: (for tesh custom highlighting)
JASS:

function TT_Start takes code userFunc, integer data returns nothing
function TT_StartEx takes code userFunc, integer data, real period returns nothing
function TT_Once takes code userFunc, integer data, real timeout returns nothing
function TT_StartTimerDialog takes code userFunc, integer data, real timeout returns timerdialog
function TT_GetData takes nothing returns integer
function TT_GetTimerDialog takes nothing returns timerdialog


In the demo map you will find examples for all possible uses of this system.
Please consult the demo map before asking "how do I .." questions.
 

Attachments

  • TT_v4.0.w3x
    45.1 KB · Views: 479

Pyrogasm

There are some who would use any excuse to ban me.
Reaction score
134
Glad to see you checked to see if your code compiled... You forgot to capitalize "i" in GetData.

And for the record I really don't understand what this is supposed to do; the documentation didn't really cut it.
 

Sim

Forum Administrator
Staff member
Reaction score
534
Why use this system? That is the question.

"It is ridiculously easy to use." doesn't help.
 

Cohadar

master of fugue
Reaction score
209
Glad to see you checked to see if your code compiled... You forgot to capitalize "i" in GetData.

And for the record I really don't understand what this is supposed to do; the documentation didn't really cut it.

I did not forget anything, the forum script obviously have some stupid rule to lowercase I in square brackets.

If you don't believe me try quoting my post and see that is capitalized.

Why use this system?
Dunno.
 

Pyrogasm

There are some who would use any excuse to ban me.
Reaction score
134
You're right; I remember that bug with vBulletin (at least on Wc3c).
 

Cohadar

master of fugue
Reaction score
209
Describe your system. :)

It is the fastest and easiest to use 0.04 timer attaching system that was ever created.
That means that you are looking at best array timer system that exists.

Someone might think that using arrays directly is faster because of additional trigger workz,
but indeed this will defeat any other timer system in performance tests.

The reason for this being that you have to write separate array timer algorithms for every spell you make,
while with this you can use just one timer for entire map!
 

Sim

Forum Administrator
Staff member
Reaction score
534
Don't explain it to me, describe it in the original post.
 

0zaru

Learning vJASS ;)
Reaction score
60
And this works for more than a function at any time ? Wow... nice +rep I will use this
 

Jesus4Lyf

Good Idea™
Reaction score
397
It's pretty clever, I'd say it should pause itself (like it says it does) if theres nothing attached, but because it's just one timer it doesn't really matter.

I know this is the system you said was better than Key Timers (again), but Key Timers serves a different purpose, because you can change the rate (and I don't see how TT could be faster than one Key Timer, dispite your claims). The rate is meant to be variable because it isn't just designed for spells. I use it for heaps of other things.

But here's a useful idea. You could make it so you can specify different periods as well as the code and struct. Just save the period to a Period array, then have a Countdown array, and have the timer execute every 0.02 seconds or so, and deduct 0.02 from Countdown until Countdown <=0. Then add the period to the coundown and continue with the if Evaluate then clause (which I see you liked in Key Timers, or we just think extremely similarly). :p

Or uh... Would adding period lag this timer too much and be better off using Key Timers? I mean looping from 1 to 1000 lags doing nothing, let alone calling triggers.

Edit: Why would this fail is Period > 0.1?
Edit2: I think you forgot the Initfunc requirement for implementing it via copy/paste.
 

~GaLs~

† Ғσſ ŧħə ѕαĸε Φƒ ~Ğ䣚~ †
Reaction score
180
The "PERIOD" is fixed death?...

What if I want multiple things, like 2/3 spell running together, they uses this system. But they need different period?...

I'll need to use back the old, bad, nasty timer attachment?

Edit - call TriggerAddCondition(Triggz[Counter], Condition(userFunc))
What if the "userFunc" returns nothing?... I don't really sure of this, this may cause syntax in the newest PJass as the BoolExpr don't return true/false or null.
 
Reaction score
456
>What if the "userFunc" returns nothing?
Then it's the user's problem. It's not so hard to replace "nothing" with "boolean", and in the very end of the function add "return false".
 

Jesus4Lyf

Good Idea™
Reaction score
397
The "PERIOD" is fixed death?...

What if I want multiple things, like 2/3 spell running together, they uses this system. But they need different period?...

I'll need to use back the old, bad, nasty timer attachment?

Use Key Timers 2 instead if you want a variable period. It works on a similar princible but has a variable period.
 

~GaLs~

† Ғσſ ŧħə ѕαĸε Φƒ ~Ğ䣚~ †
Reaction score
180
>>Then it's the user's problem. It's not so hard to replace "nothing" with "boolean", and in the very end of the function add "return false".
Cohadar didn't add that to his read me, I think so?

>>Use Key Timers 2 instead if you want a variable period. It works on a similar princible but has a variable period.
Omg~ You are stealing Cohadar's business by making another alike system.
I assume that you copy the whole KT1 and modify it, right?
Even the readme are 70% alike...
 
Reaction score
456
>Cohadar didn't add that to his read me, I think so?
If someone knows how to use this system, then the one probably knows what is a boolexpr.

>Omg~ You are stealing Cohadar's business by making another alike system.
It's only text, nothing has been stolen.

Keep it on topic..

So would it be better to use this instead of ABC, if I need only attach struct to a timer?
 

Cohadar

master of fugue
Reaction score
209
It's pretty clever, I'd say it should pause itself (like it says it does) if theres nothing attached, but because it's just one timer it doesn't really matter.
Pausing timer turned out to be less efficient so I removed it from system.

I know this is the system you said was better than Key Timers (again), but Key Timers serves a different purpose, because you can change the rate
No you can't // <-------- Pay special attention now:
Using array systems works ONLY for PERIOD < 0.1
If period is bigger you have to use ABC or CSData or whatever...

(and I don't see how TT could be faster than one Key Timer, dispite your claims).
Read my claims more carefully?

But here's a useful idea. You could make it so you can specify different periods as well as the code and struct. Just save the period to a Period array, then have a Countdown array...
No that method sux, it is actually faster to use attaching for anything that is beyond 0.04 period

Edit: Why would this fail is Period > 0.1?
copy/paste.
Because all array methods fail if Period > 0.1 (including KeyTimers)
The reason being that if you have one timer that runs at 5 second period for example and you cast a spell in second 2 it will take 3 seconds before spell actually gets activated by the system.
Therefore array methods are not precise if Period > 0.1

Edit2: I think you forgot the Initfunc requirement for implementing it via
I always test my systems carefully and I don't forget.

//=================================================
The "PERIOD" is fixed death?...

What if I want multiple things, like 2/3 spell running together, they uses this system. But they need different period?...
I'll need to use back the old, bad, nasty timer attachment?
Not if you use ABCT extension library.

So would it be better to use this instead of ABC, if I need only attach struct to a timer?
Yes
 

~GaLs~

† Ғσſ ŧħə ѕαĸε Φƒ ~Ğ䣚~ †
Reaction score
180
>>ABCT
ABCT..?

>>If someone knows how to use this system, then the one probably knows what is a boolexpr.
You sure?
In the past, I know using CSCache before i acknowledge anything about BoolEpxr.

@Cohadar
You still havent explain about the BoolExpr thingy.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +1
  • The Helper The Helper:
    The recipe today is Sloppy Joe Casserole - one of my faves LOL https://www.thehelper.net/threads/sloppy-joe-casserole-with-manwich.193585/
  • The Helper The Helper:
    Decided to put up a healthier type recipe to mix it up - Honey Garlic Shrimp Stir-Fry https://www.thehelper.net/threads/recipe-honey-garlic-shrimp-stir-fry.193595/
  • The Helper The Helper:
    Here is another comfort food favorite - Million Dollar Casserole - https://www.thehelper.net/threads/recipe-million-dollar-casserole.193614/

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top