1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  4. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  5. The results are out! Check them out.
    Dismiss Notice
  6. The poll for Hive's 12th Concept Art Contest is up! Go cast your vote for your favourite genie!
    Dismiss Notice
  7. The raddest synthwave tracks were chosen - Check out our Music Contest #12 - Results and congratulate the winners!
    Dismiss Notice
  8. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[vJass] SleepAction - The new "Wait"

Discussion in 'Graveyard' started by Bribe, Sep 7, 2010.

  1. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,030
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    When I was making cinematic scripts last year, I was disappointed by the inaccuracies of
    TriggerSleepAction()
    , so I moved to fix that problem with Waldbaer's Exact-Timing Cinematic tutorial. Unfortunately, that looked like a mess and was getting tiresome to create the trigger queues for every wait period that I wanted to be exact.

    I moved to JASS.

    What happened then was the precedence-behavior of programming messed everything up in a whole new way. The
    TimerStart()
    call only compiles functions above it, which made my cinematic script look out-of-order and I was finding it hard to expand on it and to locate a specific section (because everything was in reverse-chronological order).

    I tried learning Anitarf's Cinematic System but I found myself drifting further and further away from the approach I wanted to take with creating the cinematic. I wanted to have a script that looked like it was mine and would be easy for someone to pick up on.

    The SleepAction library is the realization of those dreams I had. Now, thanks to a textmacro, it is an easy thing to implement a wait period. The only parts that require thinking are in the parameters passed to the macro.

    Example 1:

    Code (vJASS):
    scope foo initializer bar // requires SleepAction
     
        private function bar takes nothing returns nothing
            //! runtextmacro SleepAction("5.5", "1")
            call BJDebugMsg("Hello,") // Executed exactly 5 and a half seconds into the game.
            //! runtextmacro SleepAction("0.1", "A")
            call BJDebugMsg("World!") // Executed exactly 1/10th of a second after the last message.
        endfunction
     
    endscope
     


    The first of the parameters is the period you want to wait, which must be a
    real
    value or variable. Everything below the line of the textmacro will not execute until the *exact moment* the wait period has ended. Not slightly before or slightly after which you get from
    TriggerSleepAction()
    and without disorganizing and/or complicating your script to accomplish something which should not have ever been a complicated process.

    The textmacro must be within a
    scope or library
    (pretty much every vJass user does this anyway) and within a vJass
    function
    (not a
    method
    or a Zinc function [Zinc users have anonymous functions to make up for all the features Zinc didn't get]). Note that
    local
    variables are not remembered after the textmacro line, though it is possible to declare new local variables after the line. How it works:

    Invisible to you while scripting, the textmacro breaks the function in two. A
    timer
    gets started with the duration you specified and then, using a vJass
    function interface
    combined with TimerData from Vexorian's TimerUtils, the "second part" of the function is executed when the timer expires. For this reason, the second parameter must be a scope-unique sequence of letters and/or numbers and/or underscores as that parameter more or less gives the hidden function a name.

    I find it user-friendly to just name each part a sequencial number (1,2,3...) as you scroll down. The hidden function is a
    private function
    which is prefixed with SleepAction_ and, being
    private
    , prefixed with the scope's name as well, with the second parameter's name tacked on at the end of it all.

    Hopefully, this script allows you to create cinematics in an environment which is suitable for you!

    Example 2:

    Code (vJASS):

       
        scope Scene1 initalizer Init // requires SleepAction
           
            private function Message takes real duration, string msg returns nothing
                call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, duration, "|cff888888" + msg + "|r")
            endfunction
           
            private function Init takes nothing returns nothing
           
                //! runtextmacro SleepAction("0.0", "1")
                // Actions below this line happen exactly 0 seconds into the game.
                call Message(5.0, "This is an easy method to create cinematics.")
               
                //! runtextmacro SleepAction("5.0", "2")
                // Actions below this line happen exactly 5 seconds after the last message.
                call Message(7.0, "Using this tool, you can create perfect wait-periods without " + /*
                                */
    "distorting the look and feel of your cinematic scripts.")
                           
                //! runtextmacro SleepAction("7.0", "3")
                // Actions below this line happen exactly 7 seconds after the last message.
                call Message(10.0, "All you have to do is fill in the blanks:\n" + /*
                                 */
    "//! runtextmacro SleepAction(\"<Real Duration>\", \"<Scope-Unique Name>\")")
               
                call TriggerSleepAction(10.0)
                // Yes, you can safely mix regular TriggerSleepActions in, if you want.
            endfunction
           
        endscope
       
     


    Cons



    I can just butter this whole thing up, but there are some real things to consider and to review from what I mentioned already.

    A) The textmacro may only be enclosed in a function which
    takes nothing returns nothing
    .
    B) The function may not be a method and may not be in the Zinc language.
    C) The function must be contained in a scope or a library.
    D) Local variables are forgotten after the textmacro line.
    E) The textmacro line may not be embedded within a block such as
    if/then/else/endif
    or
    loop/endloop
    .
    F) You must input a scope-unique name as a second textmacro parameter.

    SleepAction script:

    Code (vJASS):

    library SleepAction requires TimerUtils
       
        function interface SleepActionFunc takes nothing returns nothing
       
        private function Sleep takes nothing returns nothing
            local timer t = GetExpiredTimer()
            call SleepActionFunc(GetTimerData(t)).execute()
            call ReleaseTimer(t)
        endfunction
       
        function DoSleepAction takes SleepActionFunc func, real duration returns nothing
            local timer t = NewTimer()
            call SetTimerData(t, integer(func))
            call TimerStart(t, duration, false, function Sleep)
        endfunction
       
        //! textmacro SleepAction takes RealSleepDuration, FuncName
                globals
                    private keyword SleepAction_$FuncName$X
                endglobals
                call DoSleepAction(SleepAction_$FuncName$X, $RealSleepDuration$)
            endfunction
           
            private function SleepAction_$FuncName$X takes nothing returns nothing
        //! endtextmacro

    endlibrary
     
     
    Last edited: Sep 10, 2010
  2. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,665
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    Basically this doesn't have much practical use, I'd rather just use timers directly.
     
  3. busterkomo

    busterkomo

    Joined:
    Jun 17, 2007
    Messages:
    1,423
    Resources:
    1
    Tutorials:
    1
    Resources:
    1
    Is there any reason why you're using a global timer?
     
  4. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,030
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Local variables suck for handling handles.
     
    Last edited: Sep 8, 2010
  5. busterkomo

    busterkomo

    Joined:
    Jun 17, 2007
    Messages:
    1,423
    Resources:
    1
    Tutorials:
    1
    Resources:
    1
    They don't in this instance.
     
  6. Anachron

    Anachron

    Joined:
    Sep 9, 2007
    Messages:
    6,167
    Resources:
    66
    Icons:
    49
    Packs:
    2
    Tools:
    1
    Maps:
    3
    Spells:
    9
    Tutorials:
    1
    JASS:
    1
    Resources:
    66
    The thing is that this does not support local variables.
     
  7. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,030
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Even without nullifying, using a global variable is faster than generating a local variable. TimerUtils does not leak, though fewer pointers in general saves memory.
     
  8. Anachron

    Anachron

    Joined:
    Sep 9, 2007
    Messages:
    6,167
    Resources:
    66
    Icons:
    49
    Packs:
    2
    Tools:
    1
    Maps:
    3
    Spells:
    9
    Tutorials:
    1
    JASS:
    1
    Resources:
    66
    I had the same idea before. I called it TempUtils or so.
    No matter whether they are faster or not, locals make things easier to understand.
    You see "this is where it belongs to" and not "where the hell is this global from?".
     
  9. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,030
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    OK, that makes a lot of sense. I have changed it to have more scope-precision.

    Makes me wish I still had the game installed. I had a WarChasers map that had a cinematic that would have really benefitted from something like this.
     
  10. busterkomo

    busterkomo

    Joined:
    Jun 17, 2007
    Messages:
    1,423
    Resources:
    1
    Tutorials:
    1
    Resources:
    1
    Do you have any benchmark to prove that globals are faster than locals? I vaguely remember doing a test a few years ago that proved the inverse of that.
     
  11. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,149
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Actually it depends.. if you have very few globals, the globals will be faster than the locals. If you have very many globals, the globals will be much slower than the locals. Essentially, the more globals you have, the slower reading a global value gets.

    This means that you want to minimize global variables, not maximize them.


    These results were from many benchmarks conducted by myself and other members at thehelper.net. Some of the benchmarks were under the direction of jesus4lyf.
     
  12. Anachron

    Anachron

    Joined:
    Sep 9, 2007
    Messages:
    6,167
    Resources:
    66
    Icons:
    49
    Packs:
    2
    Tools:
    1
    Maps:
    3
    Spells:
    9
    Tutorials:
    1
    JASS:
    1
    Resources:
    66
    Actually globals were faster, but only in certain conditions.
    AFAIK locals are only at worst 10% slower then globals.
     
  13. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,149
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Like if you have few globals ... >.>
     
    Last edited: Sep 14, 2010
  14. busterkomo

    busterkomo

    Joined:
    Jun 17, 2007
    Messages:
    1,423
    Resources:
    1
    Tutorials:
    1
    Resources:
    1
    These last few posts have confirmed that my original statement was true: locals variables are ideal in this instance.
     
  15. azlier

    azlier

    Joined:
    Oct 3, 2008
    Messages:
    354
    Resources:
    4
    JASS:
    4
    Resources:
    4
    A method of making this decent to use has not yet been developed. It would take a lot of work to get anything good out of the concept. This just happens to hit some of Jasshelper's limitations like a bird does a window. Graveyarded.