[Log in / Register]
| News | Chat | Pastebin | Donations | Tutorials | Rules | Forums |
| Maps | Skins | Icons | Models | Spells | Tools | Jass | Packs | Hosted Projects | Starcraft II Modding | Starcraft II Resources | Galaxy Wiki |
(Keeps Hive Alive)
Go Back   The Hive Workshop > Warcraft III Modding > JASS Resources > Submissions > "Graveyard"


"Graveyard" Resources which were not approved are moved to this section.

 
 
Thread Tools
Old 10-27-2011, 08:23 AM   #1 (permalink)
Forum Moderator Bribe
Keep it simple
 
Bribe's Avatar
Spells, Help Zones & JASS Moderator
 
Join Date: Sep 2009
Posts: 5,581
Bribe has much of which to be proud (1209)Bribe has much of which to be proud (1209)
PayPal Donor: This user has donated to The Hive. 
[System] MissileRecycler

Recycles missile dummy units while considering their facing angle.

Warning: this uses an ObjectMerger statement to create a dummy unit with the rawcode 'dumi'. I haven't written a Nestharus-style safe Lua script nor prepared a test map at this stage. That is on my to-do list still.

Jass:
library MissileRecycler initializer Init requires optional UnitIndexer /*

    MissileRecycler v 1.2.0.4
    =========================================================================
    Credits:
    -------------------------------------------------------------------------
    Written by Bribe
    Vexorian, Anitarf and iNfraNe for the dummy.mdx model file
    Nestharus for the Queue data structure and for finding that paused units
        consume very few CPU resources.

    =========================================================================
    Requirements:
    -------------------------------------------------------------------------
    -   Updated JassHelper by Cohadar

    =========================================================================
    Introduction:
    -------------------------------------------------------------------------
    Recycling dummy units is important because the CreateUnit call is one of,
    if not the, most processor-intensive native in the entire game. Creating
    just a couple dozen dummy units in a single thread causes a visible frame
    glitch for that instant. The overhead is even higher if you are using a
    Unit Indexing library in the map which causes some extra evaluations per
    new unit.

    There are also reports of removed units leaving a little trail of RAM
    surplus in their wake. I have not been able to reproduce this so I don't
    know if this is still a factor in 1.26.

    I was motivated to create this system because removed units might be un-
    safe in very large numbers and CreateUnit is a very heavy process.

    The thing that makes this system different than others is the fact that
    it considers the facing angle of the dummies being recycled, which I have
    never seen another system even attempt. Considering the facing angle is
    important because it takes almost 1 second for the unit to turn around,
    which looks especially weird if you are creating a unit-trail or if you
    are shooting arrow-shaped objects as projectiles. For fireball effects or
    effects that generally don't depend on facing angle, this system would be
    a bit wasteful.

    Worst case scenario, it will take 0.09 seconds for the projectile to turn
    to the angle you need. This is 1/8 of the normal worst case scenario if
    you weren't recycling dummies considering facing. On average, it takes
    roughly 0.045 seconds to turn to the angle you need (which is not even
    noticable). However, I have made this completely configurable and you are
    able to change the values to whatever needs you have.

    =========================================================================
    Calibration Guide:
    -------------------------------------------------------------------------
    The thing that surprised me the most about this system was, no matter how
    complex it turned out, it became very configurable. So I should let you
    know what the constants do so you know if/how much you want to modify.

    constant integer ANG_N = 8

    -   How many different angles are recognized by the system. You can't do
    360 different angles because then you're going to have thousands of dummy
    units stored and that's ridiculous, the game lags enough at 1000 units.
    Increasing ANG_N increases realism but decreases the chance that a dummy
    unit will be available to be recycled. I don't recommend making this any
    lower, though the max I'd recommend would be 16.

    constant integer ANG_STORAGE_MAX = 12

    -   How many dummy units are stored per angle. This limit is important
    because you might have a spike at one point in the game where many units
    are created, which could lead to many of those dummy units never being
    used again.
        In general, I advise that the factor of ANG_N x ANG_STORAGE_MAX does
    not exceed 100. More than that is too much in my opinion.
        Preloads ANG_N x ANG_STORAGE_MAX dummy units. Preloading dummies is
    useful as it dumps a lot of CreateUnit calls in initialization where you
    won't see a frame glitch.

    =========================================================================
    API Guide:
    -------------------------------------------------------------------------
    You obviously need some functions so you can get a recycled dummy unit or
    recycle it. Therefore I provide these:

    function GetRecycledMissile
        takes real x, real y, real z, real facing
            returns unit

        Returns a new dummy unit that acts as a projectile missile. The args
        are simply the last three arguments you'd use for a CreateUnit call,
        with the addition of a z parameter to represent the flying height -
        it isn't the absolute z but relative to the ground because it uses
        SetUnitFlyHeight on that value directly.

    function RecycleMissile
        takes unit u
            returns nothing

        When you are done with that dummy unit, recycle it via this function.
        This function is pretty intelligent and resets that unit's animation
        and its facing angle so you don't have to.
*/

    //=======================================================================
    // Save the map, then delete the exclaimation mark in the following line.
    // Make sure that you don't have an object in your map with the rawcode
    // 'dumi' and also configure the model path (war3mapImported\dummy.mdl)
    // to the dummy.mdx model created by Vexorian.
    //! external ObjectMerger w3u ewsp dumi unam "Missile Dummy" ubui "" uhom 1 ucol 0.01 umvt "None" umvr 1.00 utar "" uspa "" umdl "war3mapImported\dummy.mdl" umxr 0.00 umxp 0.00 ushr 0 uerd 0.00 udtm 0.00 ucbs 0.00 uble 0.00 uabi "Aloc,Amrf"

    //Thanks to Vexorian that Optimizer 5.0 no longer kills natives
    native UnitAlive takes unit id returns boolean

    globals
        //-------------------------------------------------------------------
        // You must configure the dummy unit with the one created from the
        // ObjectMerger statement above.
        //
        private constant integer DUMMY_ID = 'dumi'      //The rawcode of the dummy unit.
        private          player  OWNER    = Player(15)  //The owner of the dummy unit.

        private constant integer ANG_N = 8              //# of indexed angles. Higher value increases realism but decreases recycle frequency.
        private constant integer ANG_STORAGE_MAX = 12   //Max dummies per indexed angle. I recommend lowering this if you increase ANG_N.

        private constant real DEATH_TIME = 2. //Allow the special effect on
        //the unit to complete its "death" animation in this timeframe. Must
        //be higher than 0.74 seconds to allow the unit time to turn. This
        //number should not be lower than the maximum death-animation time of
        //your missile-units' effect attachments, just to be safe.
    endglobals

    globals
        private constant integer ANG_VAL = 360 / ANG_N //Generate angle value from ANG_N.
        private constant integer ANG_MID = ANG_VAL / 2 //The middle value of angle value.

        //Misc vars
        private unit array stack       //Recycled dummy units.
        private integer array stackN   //How many units are in the stack?
        private real array timeStamp   //Prevents early recycling of units.
        private integer array queueNext
        private integer array queueLast
        private integer recycle = 0
        private timer gameTime  = CreateTimer() //Used for visual continuity.
        private group protect   = CreateGroup() //Used to prevent double frees.
    endglobals

    static if DEBUG_MODE then
        private function Print takes string s returns nothing
            //Un-comment this next line if you want to know how the system works:
            //call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 999, "[MissileRecycler] " + s)
        endfunction
    endif

    //=======================================================================
    // Get a recycled dummy missile unit. If there are no recycled dummies
    // that are already facing the angle you need, it creates a new dummy for
    // you.
    //
    function GetRecycledMissile takes real x, real y, real z, real facing returns unit
        local integer i = ModuloInteger(R2I(facing), 360) / ANG_VAL
        local integer this = queueNext[i]
        local unit u
        if this != 0 and TimerGetElapsed(gameTime) >= timeStamp[this] then
            //Dequeue this
            set queueNext[i] = queueNext[this]
            if queueNext[i] == 0 then
                set queueLast[i] = i
            endif
            set stackN[i] = stackN[i] - 1
            //Recycle this index
            set queueLast[this] = recycle
            set recycle = this
            //Old unit will return as new
            set u = stack[this]
            call SetUnitFacing(u, facing)
            call GroupRemoveUnit(protect, u)
            debug call Print("Recycling")
        else
            debug call Print("Creating new")
            static if LIBRARY_UnitIndexer then
                set UnitIndexer.enabled = false
            endif
            set u = CreateUnit(OWNER, DUMMY_ID, x, y, facing)
            static if LIBRARY_UnitIndexer then
                set UnitIndexer.enabled = true
            endif
            call PauseUnit(u, true)
        endif
        call SetUnitX(u, x)
        call SetUnitY(u, y)
        call SetUnitFlyHeight(u, z, 0)
        set bj_lastCreatedUnit = u
        set u = null
        return bj_lastCreatedUnit
    endfunction

    //=======================================================================
    // You should recycle the dummy missile unit when its job is done.
    //
    function RecycleMissile takes unit u returns nothing
        local integer i
        local integer this = recycle
        if GetUnitTypeId(u) == DUMMY_ID and UnitAlive(u) and not IsUnitInGroup(u, protect) then
            if this == 0 then
                debug call Print("Stack is full - removing surplus unit")
                call RemoveUnit(u)
                return
            endif
            //Recycle this
            set recycle = queueLast[this]
            //Index the dummy unit to an available facing angle.
            set i = R2I(GetUnitFacing(u)) / ANG_VAL
            if stackN[i] < ANG_STORAGE_MAX then
                set i = ANG_N
                loop
                    set i = i - 1
                    exitwhen stackN[i] < ANG_STORAGE_MAX
                endloop
            endif
            //Enqueue this
            set queueNext[queueLast[i]] = this
            set queueLast[i] = this
            set queueNext[this] = 0
            set stackN[i] = stackN[i] + 1
            //Allow a time barrier for the effect to destroy/turn to complete.
            set timeStamp[this] = TimerGetElapsed(gameTime) + DEATH_TIME
            set stack[this] = u
            //Prevent double-free of this unit.
            call GroupAddUnit(protect, u)
            //Reset the dummy's properties.
            call SetUnitFacing(u, i * ANG_VAL + ANG_MID)
            call SetUnitVertexColor(u, 255, 255, 255, 255)
            call SetUnitAnimationByIndex(u, 90)
            call SetUnitScale(u, 1, 0, 0)
            //call PauseUnit(u, false) -- you can disable "resets" that you don't need to worry about.
        debug else
            debug call BJDebugMsg("[MissileRecycler] Error: Attempt to recycle invalid unit.")
        endif
    endfunction

    //=======================================================================
    // Map the dummy units to their facing angles (map below is if ANG_N is
    // 4 and ANG_STORAGE_MAX is 3).
    //
    // angle[0] (0)   -  [4] [5] [6]
    // angle[1] (90)  -  [7] [8] [9]
    // angle[2] (180) - [10][11][12]
    // angle[3] (270) - [13][14][15]
    //
    private function Init takes nothing returns nothing
        local integer end
        local integer i = ANG_N
        local integer n = i
        local integer angle
        local real x = GetRectMaxX(bj_mapInitialPlayableArea)
        local real y = GetRectMaxY(bj_mapInitialPlayableArea)
        static if LIBRARY_UnitIndexer then
            set UnitIndexer.enabled = false
        endif
        loop
            set i = i - 1
            set stackN[i] = ANG_STORAGE_MAX
            set queueNext[i] = n
            set angle = i * ANG_VAL + ANG_MID
            set end = n + ANG_STORAGE_MAX
            set queueLast[i] = end - 1
            loop
                set queueNext[n] = n + 1
                set stack[n] = CreateUnit(OWNER, DUMMY_ID, x, y, angle)
                call PauseUnit(stack[n], true)
                set n = n + 1
                exitwhen n == end
            endloop
            set queueNext[n - 1] = 0
            exitwhen i == 0
        endloop
        static if LIBRARY_UnitIndexer then
            set UnitIndexer.enabled = true
        endif
        call TimerStart(gameTime, 1000000., false, null)
    endfunction

endlibrary

Last edited by Bribe; 03-29-2012 at 07:17 AM. Reason: Changed to 1.2.0.4
Bribe is offline  
Old 10-27-2011, 11:08 AM   #2 (permalink)
Forum Moderator Bribe
Keep it simple
 
Bribe's Avatar
Spells, Help Zones & JASS Moderator
 
Join Date: Sep 2009
Posts: 5,581
Bribe has much of which to be proud (1209)Bribe has much of which to be proud (1209)
PayPal Donor: This user has donated to The Hive. 
Made an update to address unit-type safety and removed the useless Show/Hide unit features.
__________________
How to post your triggers on the Hive Workshop.
JPAG - Bettering the cause of readable source code.

Bribe is offline  
Old 10-27-2011, 01:56 PM   #3 (permalink)
Forum Moderator Magtheridon96
JESUS MAN
 
Magtheridon96's Avatar
Resource Moderator
 
Join Date: Dec 2008
Posts: 5,692
Magtheridon96 has a brilliant future (1805)
Merit Badge - Level 0: This user has proven to be extremely valuable to the Warcraft III Modding Community. 
Going to do a full-revision of this:

Jass:
        //Misc vars
        private unit newUnit = null    //Returning a local unit leaks the handle index.
        private unit array stack       //Used as a 2-D array of dummy units.
        private integer array stackN   //Used to track multiple indices for the 2-D array.
        private code expireCode = null //Prevents trigger evaluations or cloned functions.
    endglobals

If you'd remove the  = null at the end, you'd be increasing efficiency and have no effect on the code.
newUnit isn't used anywhere (except in one function, but you're setting it before that, so it shouldn't cause any thread crashes)

call SetUnitFlyHeight(newUnit, z, 0)
I'm not really sure about this. Maybe you should mention that the given Z should be the distance from the ground and not from the 0-height base of the map.

Other than that, GetRecycledMissile is an excellent function.

IAbsBJ
D:
I know inlining it won't make much of a difference, but the red color is evil :3

local integer this = recycle[0]

You just gave me an idea. ;D

BJDebugMsg
More evil red color D:

Jass:
            local real x = GetRectMaxX(bj_mapInitialPlayableArea)
            local real y = GetRectMaxY(bj_mapInitialPlayableArea)

You can add static ifs and make WorldBounds an optional requirement.

Jass:
if GetUnitTypeId(u) == DUMMY_ID then
            //Reset the dummy's properties
            call SetUnitVertexColor(u, 255, 255, 255, 255)
            call SetUnitAnimationByIndex(u, 90)
            call SetUnitScale(u, 1, 0, 0)
            call Recycle(u, GetAngleIndex(GetUnitFacing(u)))
        debug else
            debug call BJDebugMsg("[MissileRecycler] Error: Attempt to recycle invalid unit-type.")
        endif

You can make that comparison debug-only to ameliorate that function's speed :P (I got a 100/100 on my vocabulary test today ;D)

One final comment:
You should ask the user to modify the object merger line so that the model would have a correct path.

edit
Other than that, this is a pretty good library.
I'm looking forward to implement this into a map and use it for a projectile
system and claim that I'm the sole writer of this system and whatever Bribe says is a lie. xD
__________________
Magtheridon96 is offline  
Old 10-27-2011, 02:33 PM   #4 (permalink)
Forum Moderator Bribe
Keep it simple
 
Bribe's Avatar
Spells, Help Zones & JASS Moderator
 
Join Date: Sep 2009
Posts: 5,581
Bribe has much of which to be proud (1209)Bribe has much of which to be proud (1209)
PayPal Donor: This user has donated to The Hive. 
The code is more readable keeping the BJ's. Inlining IAbsBJ is a waste of map size and if you care about efficiency in DEBUG_MODE you're doing something wrong.

Debug mode should also have the same code results, its only addition should be displaying error messages. Safety is important and most people don't even know what debug mode is.

If you want the speed you have to manually edit the resource to remove the safety, but because it's a public resource the safety should be "on" by default.

However, I have removed the = null parts because they were in fact very useless.

I have updated the documentation that says the flying height is not absolute but relative to the ground.

Also, world bounds is completely unnecessary. locust units can't be enumerated and I could even create the units at 0,0 but I felt it in better interest to create them off at a corner.
__________________
How to post your triggers on the Hive Workshop.
JPAG - Bettering the cause of readable source code.

Bribe is offline  
Old 10-27-2011, 02:37 PM   #5 (permalink)
Forum Moderator Magtheridon96
JESUS MAN
 
Magtheridon96's Avatar
Resource Moderator
 
Join Date: Dec 2008
Posts: 5,692
Magtheridon96 has a brilliant future (1805)
Merit Badge - Level 0: This user has proven to be extremely valuable to the Warcraft III Modding Community. 
You're right ;P
I always edit people's systems and optimize them anyways xD
__________________
Magtheridon96 is offline  
Old 10-28-2011, 07:36 AM   #6 (permalink)
Forum Moderator Bribe
Keep it simple
 
Bribe's Avatar
Spells, Help Zones & JASS Moderator
 
Join Date: Sep 2009
Posts: 5,581
Bribe has much of which to be proud (1209)Bribe has much of which to be proud (1209)
PayPal Donor: This user has donated to The Hive. 
I have updated this to fix a couple issues with the angle the dummies were supposed to be already facing. When I was testing I found that the dummies were definitely taking longer than 0.09 seconds to turn and I knew something was amiss, so I have fixed it now.
__________________
How to post your triggers on the Hive Workshop.
JPAG - Bettering the cause of readable source code.

Bribe is offline  
Old 10-28-2011, 03:11 PM   #7 (permalink)
Registered User Axarion
Pimp Warwick is not amuse
 
Axarion's Avatar
 
Join Date: Sep 2009
Posts: 728
Axarion is a jewel in the rough (200)Axarion is a jewel in the rough (200)
PayPal Donor: This user has donated to The Hive. 
Quote:
Originally Posted by Bribe View Post
I haven't written a Nestharus-style safe Lua script
Thanks.

Well this looks really nice and was really needed to be done. Keep the good work up!
__________________
"Hivers are predators, they kill the weak. Be strong and learn from what's been said, or get eaten." - Ap0calypse
Axarion is offline  
Old 10-31-2011, 09:00 AM   #8 (permalink)
Forum Moderator Bribe
Keep it simple
 
Bribe's Avatar
Spells, Help Zones & JASS Moderator
 
Join Date: Sep 2009
Posts: 5,581
Bribe has much of which to be proud (1209)Bribe has much of which to be proud (1209)
PayPal Donor: This user has donated to The Hive. 
Updated to use normal TimerUtils interface while Vexorian is updating.
__________________
How to post your triggers on the Hive Workshop.
JPAG - Bettering the cause of readable source code.

Bribe is offline  
Old 11-29-2011, 09:57 AM   #9 (permalink)
Forum Moderator Bribe
Keep it simple
 
Bribe's Avatar
Spells, Help Zones & JASS Moderator
 
Join Date: Sep 2009
Posts: 5,581
Bribe has much of which to be proud (1209)Bribe has much of which to be proud (1209)
PayPal Donor: This user has donated to The Hive. 
Approved.

If you disagree, please reply with your argument.
__________________
How to post your triggers on the Hive Workshop.
JPAG - Bettering the cause of readable source code.

Bribe is offline  
Old 11-29-2011, 10:34 AM   #10 (permalink)
Registered User Dirac
Beware the Ides of March
 
Dirac's Avatar
 
Join Date: Jun 2011
Posts: 248
Dirac is on a distinguished road (84)Dirac is on a distinguished road (84)
The facing real should take radians instead of degrees
The speed gain is barely noticeable.
Recycling missiles that had special effects attached to them cause this to malfunction (the destruction of the effect is visible)
__________________
Check out my TD

Originally Posted by GetTriggerUnit-
"There should be a section in World Editor designated to Nestharus."
Dirac is offline  
Old 11-29-2011, 10:36 AM   #11 (permalink)
Forum Moderator Bribe
Keep it simple
 
Bribe's Avatar
Spells, Help Zones & JASS Moderator
 
Join Date: Sep 2009
Posts: 5,581
Bribe has much of which to be proud (1209)Bribe has much of which to be proud (1209)
PayPal Donor: This user has donated to The Hive. 
Have you tested this with the proper object merger dummy? It works 100% for me.
__________________
How to post your triggers on the Hive Workshop.
JPAG - Bettering the cause of readable source code.

Bribe is offline  
Old 11-29-2011, 10:39 AM   #12 (permalink)
Registered User Dirac
Beware the Ides of March
 
Dirac's Avatar
 
Join Date: Jun 2011
Posts: 248
Dirac is on a distinguished road (84)Dirac is on a distinguished road (84)
I edited the post, i messed up something
__________________
Check out my TD

Originally Posted by GetTriggerUnit-
"There should be a section in World Editor designated to Nestharus."
Dirac is offline  
Old 11-29-2011, 11:03 AM   #13 (permalink)
Forum Moderator Bribe
Keep it simple
 
Bribe's Avatar
Spells, Help Zones & JASS Moderator
 
Join Date: Sep 2009
Posts: 5,581
Bribe has much of which to be proud (1209)Bribe has much of which to be proud (1209)
PayPal Donor: This user has donated to The Hive. 
Typically I've wanted to show the exploding effect of the missile anyway. A projectile system should wait for the effect to complete before recycling the unit as it is, or if he wanted to use both he could hide the unit during that time and then recycle it (so the next unit won't show that effect).

ShowUnit is apparently a very heavy operation as well, which is why I omitted it from the system.

The speed difference is pretty strong. Check Anitarf's benchmarks on wc3c (he benchmarked this very resource against createunit/removeunit). IIRC it is at least 100% faster (most overhead due to the timer).

Taking degrees is faster for performance because I index by degrees. I could make a wrapper function that takes radians though.
__________________
How to post your triggers on the Hive Workshop.
JPAG - Bettering the cause of readable source code.

Bribe is offline  
Old 11-29-2011, 11:12 AM   #14 (permalink)
Registered User Dirac
Beware the Ides of March
 
Dirac's Avatar
 
Join Date: Jun 2011
Posts: 248
Dirac is on a distinguished road (84)Dirac is on a distinguished road (84)
I benchmarked this with my Missile system creating a new missile every 0.005 while another missile dies as well, there wasn't a speed difference but it did created conflicts with the effect attached to the missile (new missiles displayed the previous effect's destroy animation)
And since JASS users always work with radians this should take them and convert them on it's own, it has nothing to do with speed performance, after all, the user has to convert it to degrees before giving it to this function
__________________
Check out my TD

Originally Posted by GetTriggerUnit-
"There should be a section in World Editor designated to Nestharus."
Dirac is offline  
Old 11-29-2011, 11:17 AM   #15 (permalink)
Forum Moderator Bribe
Keep it simple
 
Bribe's Avatar
Spells, Help Zones & JASS Moderator
 
Join Date: Sep 2009
Posts: 5,581
Bribe has much of which to be proud (1209)Bribe has much of which to be proud (1209)
PayPal Donor: This user has donated to The Hive. 
Unless the user was already working with degrees, for one reason or another. It'd be a wrapper that converts it for people who are working with degrees. I seriously will not make it radians-only.

You would need to provide benchmarks if you want to show anything. The benchmarks which have been posted onto wc3c.net already prove what yours doesn't.
__________________
How to post your triggers on the Hive Workshop.
JPAG - Bettering the cause of readable source code.

Bribe is offline  
 

Bookmarks

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off


All times are GMT. The time now is 01:31 PM.





Powered by vBulletin
Copyright 2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.5.1 PL2
Copyright © Ralle