1. Vote on the best bounty the oceans have to offer! The poll for the 34th Modeling Contest has begun.
    Dismiss Notice
  2. Awaken what lies in the heart of your swarm. The 17th Techtree Contest has arrived!
    Dismiss Notice
  3. Check out the Staff Job Openings thread.
    Dismiss Notice
Dismiss Notice
Hive 3 Remoosed BETA - NOW LIVE. Go check it out at BETA Hive Workshop! Post your feedback in this new forum BETA Feedback.
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[Snippet] FireCode

Discussion in 'Graveyard' started by Magtheridon96, Dec 11, 2011.

  1. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    5,542
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Instead of using your own forces and triggers to fire code and boolexprs, you can use this library.
    It doesn't even affect efficiency! You can queue codes/boolexprs instead of firing them if you're going
    to need to run a lot of code. That's only one Trigger Evaluation per X amount of code where X is the op-limit.

    Also, instead of making your resource responsible for the way it executes/evaluates code/boolexprs, you can blame it
    on this one. Pretty sweet, ey?

    Code (vJASS):
    /***********************************************
    *
    *   FireCode
    *   v4.0.0.0
    *   By Magtheridon96
    *
    *   - Executes Codes and Boolexprs
    *   - Allows the creation of both static and dynamic
    *     queues of code and boolexprs.
    *   - Allows all the standardized ways of executing
    *     codes and boolexprs to be the responsibilty of
    *     one resource and not a thousand.
    *
    *   Notes:
    *   ------
    *
    *       - You must never use EnqueueCode/EnqueueCondition without
    *         calling NewCodeQueue/NewConditionQueue.
    *       - Firing a Queue destroys it.
    *       - Using the Struct API allows you to create static queues.
    *       - You can never use TriggerSleepAction except while using FireCode.
    *       - The Jass API must only be used when in need of dynamic
    *         code/boolexpr executions.
    *
    *   API:
    *   ----
    *
    *       - struct ConditionQueue extends array
    *           - static method create takes nothing returns thistype
    *               - Creates a static ConditionQueue
    *           - method enqueue takes boolexpr b returns triggercondition
    *               - Enqueues a boolexpr to the ConditionQueue and returns it.
    *           - method dequeue takes triggercondition b returns nothing
    *               - Dequeues a boolexpr from the ConditionQueue
    *           - method evaluate takes nothing returns boolean
    *               - Executes all the boolexprs enqueued in the ConditionQueue
    *           - method destroy takes nothing returns nothing
    *               - Destroys a ConditionQueue
    *
    *       - function FireCode takes code c returns nothing
    *           - Executes a code.
    *       - function NewCodeQueue takes nothing returns nothing
    *           - Creates a very dynamic code queue that gets destroyed after firing it.
    *       - function EnqueueCode takes code c returns nothing
    *           - Enqueues a code.
    *       - function FireCodeQueue takes nothing returns nothing
    *           - Fires all enqueued codes and destroys the dynamic queue.
    *       - function FireCondition takes boolexpr b returns boolean
    *           - Fires a boolexpr.
    *       - function NewConditionQueue takes nothing returns nothing
    *           - Creates a very dynamic boolexpr queue that gets destroyed after firing it.
    *       - function EnqueueCondition takes boolexpr b returns nothing
    *           - Enqueues a boolexpr.
    *       - function FireConditionQueue takes nothing returns boolean
    *           - Fires all enqueued boolexprs and destroys the dynamic queue.
    *
    ***********************************************/

    library FireCode

        globals
            public trigger array btQ
            public trigger array ctQ
            public integer bi = 0
            public integer ci = 0
            public trigger t = CreateTrigger()
        endglobals
       
        struct ConditionQueue extends array
            private static integer stack = 1
            private static trigger array triggers
           
            // Removal stack
            private static timer stackClearer = CreateTimer()
            private static triggercondition array conditionStack
            private static trigger array triggerStack
            private static integer stackIndex = 0
           
            static method create takes nothing returns thistype
                local thistype this = stack
                set stack = stack + 1
                if triggers[this] == null then
                    set triggers[this] = CreateTrigger()
                endif
                return this
            endmethod
           
            method enqueue takes boolexpr b returns triggercondition
                return TriggerAddCondition(triggers[this], b)
            endmethod
           
            private static method remove takes nothing returns nothing
                loop
                    exitwhen stackIndex == 0
                    call TriggerRemoveCondition(triggerStack[stackIndex], conditionStack[stackIndex])
                    set triggerStack[stackIndex] = null
                    set conditionStack[stackIndex] = null
                    set stackIndex = stackIndex - 1
                endloop
            endmethod
           
            method dequeue takes triggercondition b returns nothing
                set stackIndex = stackIndex + 1
                set conditionStack[stackIndex] = b
                set triggerStack[stackIndex] = triggers[this]
                if stackIndex == 1 then
                    call TimerStart(stackClearer, 0, false, function thistype.remove)
                endif
            endmethod
           
            method evaluate takes nothing returns boolean
                return TriggerEvaluate(triggers[this])
            endmethod
           
            method destroy takes nothing returns nothing
                set stack = stack - 1
                set triggers[this] = triggers[stack]
                call TriggerClearConditions(triggers[this])
            endmethod
        endstruct
       
        function FireCode takes code c returns nothing
            call ForForce(bj_FORCE_PLAYER[0], c)
        endfunction
       
        function NewCodeQueue takes nothing returns nothing
            set ci = ci + 1
            if ctQ[ci] == null then
                set ctQ[ci] = CreateTrigger()
            endif
        endfunction
       
        function EnqueueCode takes code c returns nothing
            call TriggerAddCondition(ctQ[ci], Filter(c))
        endfunction
       
        function FireCodeQueue takes nothing returns nothing
            call TriggerEvaluate(ctQ[ci])
            call TriggerClearConditions(ctQ[ci])
            set ci = ci - 1
        endfunction
       
        function FireCondition takes boolexpr b returns nothing
            // Do not change the order of these.
            // That would kill recursion-safety.
            call TriggerClearConditions(t)
            call TriggerAddCondition(t, b)
            call TriggerEvaluate(t)
        endfunction
       
        function NewConditionQueue takes nothing returns nothing
            set bi = bi + 1
            if btQ[bi] == null then
                set btQ[bi] = CreateTrigger()
            endif
        endfunction
       
        function EnqueueCondition takes boolexpr b returns nothing
            call TriggerAddCondition(btQ[bi], b)
        endfunction
       
        function FireConditionQueue takes nothing returns nothing
            call TriggerEvaluate(btQ[bi])
            call TriggerClearConditions(btQ[bi])
            set bi = bi - 1
        endfunction
       
    endlibrary


    Feel free to comment.
     
    Last edited: Feb 26, 2012
  2. Troll-Brain

    Troll-Brain

    Joined:
    Apr 27, 2008
    Messages:
    2,412
    Resources:
    1
    JASS:
    1
    Resources:
    1
    Do you know that you can import an empty blizzard.j inside your map ?
     
  3. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    5,542
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    I see what you did there ^.^

    I guess the "IsOnTopic" Criterion should be modified :O
    Maybe we should change it from "Jass talk in Jass thread" to "Coherent Jass talk in Jass thread" ^_^
     
  4. Troll-Brain

    Troll-Brain

    Joined:
    Apr 27, 2008
    Messages:
    2,412
    Resources:
    1
    JASS:
    1
    Resources:
    1
    That wasn't my point.

    You use bj_FORCE_PLAYER[0] to save one handle, right ?

    Now, do you realize that if you import an empty blizzard.j you will save many more handles ?

    Not to mention that one handle less or more really really really really really really really (did i already mention "really" ?) doesn't matter.
     
  5. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    5,542
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    blizzard.j is pretty nifty.
    There are some good functions and globals but a lot of useless ones. I'm might write a version of blizzard.j that only includes the useful globals and functions ^-^
     
  6. Troll-Brain

    Troll-Brain

    Joined:
    Apr 27, 2008
    Messages:
    2,412
    Resources:
    1
    JASS:
    1
    Resources:
    1
    I see that we don't have the same definition for "nifty" :p
     
  7. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    5,542
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    I think we need to agree on a list of globals and functions inside Blizzard.j that we need to hang on to.

    I think InitBlizzard() and all those other 'Init' functions should be changed to functions that simply initialize bj_FORCE_PLAYER and other useful handles like bj_lastCreatedGroup.

    Those 'Stock Update' functions seem stupid.
    The DayNightSound functions could be simplified.

    Everything else except for
    IntegerTertiaryOp
    , the Math BJs, GetDyingDestructable and TriggerRegisterPlayerUnitEvent must go.
     
  8. Troll-Brain

    Troll-Brain

    Joined:
    Apr 27, 2008
    Messages:
    2,412
    Resources:
    1
    JASS:
    1
    Resources:
    1
    Man, i was just trying to say that using a new force just for a resource isn't that bad.
    At least i prefer that, instead of some "random" bj variable.

    I was never suggesting using this together with a custom blizzard.j ...
     
  9. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    5,542
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    I know ^.^
    I was talking about writing a custom blizzard.j for vJass-ers to use ^_^

    Is it really that bad? :/
     
  10. Troll-Brain

    Troll-Brain

    Joined:
    Apr 27, 2008
    Messages:
    2,412
    Resources:
    1
    JASS:
    1
    Resources:
    1
    I'm not an anti-bj dude, but jass is already enough tricky to add more silliness.
    Really, using this bj or CreateForce is just the same, except that the latest makes more sense.
    This way, you even don't need anymore an initializer (or using CreateForce in a global definition crashes wc3, i haven't tested that).

    But i know that you won't change your mind about this, at least i've tried.
     
  11. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,212
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    I think I am convinced on this. While I love to save handles it is just one handle and it makes sense. A user who doesn't use GUI will probably benefit from a custom blizzard.j file that doesn't initialize that force, anyway.

    I am too lazy to benchmark but I think something like "call GroupEnumUnitsOfType(g, "custom_n000", boolexpr)" should actually be faster than TCC/TAC/TE. I don't think it matters to store the return value either. I don't think a trigger evaluation queue is a good idea because it isn't recursion friendly (think of one of the callbacks wanting to use the queue too)
     
    Last edited: Dec 12, 2011
  12. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    5,542
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    You're right.
    I should make a trigger array and use a stack. I should also add new functions like "NewCodeQueue" and "NewConditionQueue" that you should call at the beginning of functions where you're going to use QueueCondition/QueueCode.

    The reason I want to do a Queue so badly is because ModeManager needs to run multiple boolexprs and only using FireCondition would be really bad :O

    Thanks for the suggestion ^.^
    Will do. (only for FireCondition)

    edit

    I'm not sure about GroupEnumUnitsOfType.
    It could run 0 or multiple times if you're not careful ;/

    edit

    Update. Fixed Recursion problems.

    NOTE: I don't know if it compiles :O

    edit
    Removed signature.
     
    Last edited: Dec 12, 2011
  13. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    5,542
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Updated.
    Fixed a bug, and made FireCondition faster.
    If you think ForceEnumPlayersCount(f, b, 1) can execute the boolexpr multiple times, show me proof.

    edit
    Updated again to fix the terminology usage.
    It's Enqueue code, not Queue code.
     
    Last edited: Dec 26, 2011
  14. Troll-Brain

    Troll-Brain

    Joined:
    Apr 27, 2008
    Messages:
    2,412
    Resources:
    1
    JASS:
    1
    Resources:
    1
    Well, i can't host, but i could bet my ass than ForceEnum...Count is (forever) Not Yet Implanted, just as the other Enum...Count functions.
    I mean the integer argument has no effect.

    But seriously you're the one which is submitting a resource using it, it's not to the others to prove that your code works properly.
     
  15. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,212
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    force2 could be set to bj_FORCE_PLAYER[1].
     
  16. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    5,542
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Wouldn't that affect the force bj_FORCE_PLAYER[1]?
    One sec, going to test it out and debug it.

    edit
    Updated.
    You were right.
    For FireCondition, the return value can be anything :)
    I tested out by executing 3 functions (one that returns nothing, one that returns false and another that returns true)
    They all executed perfectly and recursively well ^.^

    edit

    Unsatisfied with my results, I found that setting f2 to bj_FORCE_PLAYER and returning nothing or false won't affect recursion, but it WILL affect the force.
    Returning nothing/false -> bj_FORCE_PLAYER[1] will have no players
    Returning true -> bj_FORCE_PLAYER[1] will have player 1 in it :< (not player 2)

    I guess using CreateForce for f2 is the only way to go to avoid this.

    edit
    Update: Reverted.
     
    Last edited: Dec 26, 2011
  17. watermelon_1234

    watermelon_1234

    Joined:
    Nov 18, 2007
    Messages:
    1,063
    Resources:
    10
    Spells:
    9
    JASS:
    1
    Resources:
    10
    FireCondition is broken. It fires the same amount of times as the number of players that are playing the map.

    Test Map

    Code (vJASS):
    // Test Code:
    scope Test initializer Init
        private function hey takes nothing returns nothing
            call BJDebugMsg("HEY") // Correctly displays once
        endfunction
       
        private function hi takes nothing returns boolean
            call BJDebugMsg("HI") // Displays three times due to the extra players
            return false
        endfunction
       
        private function Test takes nothing returns nothing
            call FireCode(function hey)
            call FireCondition(Filter(function hi))
        endfunction
       
        private function Init takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterPlayerEventEndCinematic(t, Player(0))
            call TriggerAddAction(t, function Test)
        endfunction
    endscope
     
     
  18. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,212
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Guess the only alternative to triggers then would be the GroupEnumUnitsOfType trick with only one unit on that map which has the specified name.
     
  19. Troll-Brain

    Troll-Brain

    Joined:
    Apr 27, 2008
    Messages:
    2,412
    Resources:
    1
    JASS:
    1
    Resources:
    1
    Mag has a good excuse, it's not like someone has warning him multiple times about the Enum...Counted function.

    Using a unit just for that is a terrible practice.
     
  20. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    5,542
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Well, I never saw tangible evidence :c

    I'll browse common.j and look for an alternative.
    GroupEnumUnitsOfType will be my last resort for now :/