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

Memory Leaks Checker v1.6

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
  • Like
Reactions: elm0
Introduction
Sometimes, you make a spell in GUI, when it done, you check leak(s), and check check check until you make sure leakless inside that spell/map, but what happening to you if know very little about Jass/vjass, well when you save map, all trigger converted into jass (most in GUI is JASS/BJs Function).
=> Leaks occur without your knowledge.
Here the solution about that:
System Name
**M E M O R Y L E A K S C H E C K E R**
How it work

This system will check and capturing all leak(s) of your spell/map and return results, or show you where's the leak(s) in your code.
JASS:
"JASS: GetOrderPointLoc/GUI: Target point of issued order"
"JASS: GetSpellTargetLoc/Target point of ability being cast"
"JASS: GroupPickRandomUnit\GUI: Random unit from (Random 4 units from (Units in (Playable map area)))"
"JASS: CreateGroup()/GUI: Automaticaly Create Group)"
"JASS: GetRandomSubGroup(group g)/GUI: (Random 4 units from (Units in (Playable map area)))"
"JASS: CountUnitInGroup(group g)/GUI: (Number of units in (Units in (Playable map area)))"
"JASS: GetRectCenter(rect r)/GUI: Center of (Playable map area)"
"JASS: Location(real x,real y)/GUI: Point(0.00, 0.00))"
"JASS: GetUnitLoc(unit u)/GUI: Position of (Triggering unit)"
"JASS: GetDestructableLoc(destructable d)/GUI: Position of (Last created destructible)"
"JASS: GetItemLoc(item t)/GUI: Position of (Last created item)"
"JASS: GetPlayerStartLocationLoc(player p)/GUI: Player 1 (Red) start location)"
"JASS: ForGroupBJ(group g, code func)/GUI: Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)Loop - Actions"
"JASS: ForGroup(group g, code func)/GUI: None"
"JASS: AddSpecialEffectLocBJ(string m,location loc)/GUI: Special Effect - Create a special effect at (Center of (Playable map area)) using --"
"JASS: AddSpecialEffectLoc(string m,location loc)/GUI: None"
"JASS: AddSpecialEffect(string m,real x,real y)/GUI: None"
"JASS: AddSpecialEffectTargetUnitBJ(string m,real x,real y)/GUI: Special Effect - Create a special effect attached to the overhead of (Triggering unit) using --" 
"JASS: AddSpecialEffectTarget(string m,real x,real y)/GUI: None"
"JASS: ForForce(force f, code func)/GUI: UPlayer Group - Pick every player in (All players) and do (Actions)Loop - Actions"[/HIDDEN]

System test and Screen shot

Map test
untitl63.png

  • Untitled Trigger 001
    • Events
      • Time - Every 0.01 seconds of game time
    • Conditions
    • Actions
      • Set p = (Position of Siege Engine 0022 <gen>)
      • Special Effect - Create a special effect at p using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
      • Special Effect - Destroy (Last created special effect)
      • Unit - Create 1 Footman for Player 1 (Red) at p facing Default building facing degrees
      • Set g = (Units in (Playable map area))
      • Unit Group - Pick every unit in g and do (Actions)
        • Loop - Actions
          • Unit - Kill (Picked unit)
      • Custom script: call DestroyGroup(udg_g)
      • -------- --Improper DestroyGroup-- --------
      • Custom script: call DestroyGroup(udg_g)
      • Custom script: call RemoveLocation(udg_p)
      • -------- --Improper RemoveLocation-- --------
      • Custom script: call RemoveLocation(udg_p)
      • -------- --Improper DestroyForce-- --------
      • Custom script: call DestroyForce(udg_f)
  • [/HIDDEN]
How to remove leak(s)
untit270.jpg


  • Ex Remove Location
    • Events
    • Conditions
    • Actions
      • -------- Follow those steps ;) (Just an example) --------
      • -------- Save a location into variable --------
      • Set p = (Position of (Triggering unit))
      • -------- Use it via this variable --------
      • Unit - Move (Triggering unit) instantly to p
      • -------- After used, remove it, in GUI, you must place udg_ in fronf of the variable (For my example: It's p) --------
      • Custom script: call RemoveLocation(udg_p)
      • -------- Done! --------
  • Ex Destroy Group
    • Events
    • Conditions
    • Actions
      • -------- Follow those steps ;) (Just an example) --------
      • -------- Save a group into variable --------
      • Set g = (Units in (Playable map area))
      • -------- Use it via this variable --------
      • -------- You can use thi line to destroy a group (But unsafer than DestroyGroup tag) --------
      • Custom script: set bj_wantDestroyGroup = true
      • -------- ---------------------------------- --------
      • Unit Group - Pick every unit in g and do (Actions)
        • Loop - Actions
          • Unit - Hide (Picked unit)
      • -------- Or this --------
      • -------- You can use thi line to destroy a group (But unsafer than DestroyGroup tag) --------
      • Custom script: set bj_wantDestroyGroup = true
      • -------- ---------------------------------- --------
      • Unit Group - Pick every unit in g and do (Unit - Hide (Picked unit))
      • -------- After used, destroy it, in GUI, you must place udg_ in fronf of the variable (For my example: It's g) --------
      • -------- If you use: bj_wantDestroyGroup = true tag, you don't need to use DestroyGroup tag --------
      • Custom script: call DestroyGroup(udg_g)
      • -------- Done! --------
  • Ex Destroy Effect
    • Events
    • Conditions
    • Actions
      • -------- Follow those steps ;) (Just an example) --------
      • -------- Create an effect --------
      • Special Effect - Create a special effect attached to the origin of (Triggering unit) using Abilities\Spells\Other\TalkToMe\TalkToMe.mdl
      • -------- Save this effect into variable --------
      • Set e = (Last created special effect)
      • -------- After used, destroy it, in GUI, you must place udg_ in fronf of the variable (For my example: It's e) --------
      • Custom script: call DestroyEffect(udg_e)
      • -------- Or maybe this --------
      • Special Effect - Destroy e
      • -------- Done! --------
  • Ex Destroy Force
    • Events
    • Conditions
    • Actions
      • -------- Follow those steps ;) (Just an example) --------
      • -------- Save a force into variable --------
      • Set f = (All players)
      • -------- Use it via this variable --------
      • Player Group - Pick every player in f and do (Actions)
        • Loop - Actions
          • Player - Set (Picked player) Current gold to 750
      • -------- Or --------
      • Player Group - Pick every player in f and do (Player - Set (Picked player) Current gold to 750)
      • -------- After used, destroy it, in GUI, you must place udg_ in fronf of the variable (For my example: It's f) --------
      • Custom script: call DestroyForce(udg_f)
      • -------- Done! --------
  • Ex Used and Destroy All
    • Events
    • Conditions
    • Actions
      • -------- Follow those steps ;) (Just an example) --------
      • -------- Combine those think at the same time ;) --------
      • -------- Save a location into variable --------
      • Set p = (Position of (Triggering unit))
      • -------- Save a group into variable --------
      • -------- Create a group g, use location p --------
      • Set g = (Units within 500.00 of p)
      • -------- Use group g --------
      • Unit Group - Pick every unit in g and do (Actions)
        • Loop - Actions
          • -------- Create an effect --------
          • Special Effect - Create a special effect attached to the origin of (Picked unit) using Abilities\Spells\Human\Thunderclap\ThunderClapCaster.mdl
          • -------- Destroy it after used --------
          • Special Effect - Destroy (Last created special effect)
          • -------- Save a force into variable --------
          • Set f = (All allies of (Picked player))
          • -------- Use this force f --------
          • Player Group - Pick every player in f and do (Actions)
            • Loop - Actions
              • Player - Add 1000 to (Picked player) Current gold
          • -------- Destroy it after used --------
          • Custom script: call DestroyForce(udg_f)
      • -------- Destroy Group g after used --------
      • Custom script: call DestroyGroup(udg_g)
      • -------- Remove location p after used --------
      • Custom script: call RemoveLocation(udg_p)
      • -------- Done! --------
Leak(s) code founder - Well, Let's do an example about this:

  • Leak Ex
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Unit - Move Siege Engine 0022 <gen> instantly to (Center of (Playable map area))
So this is a location leak (Center of (Playable map area)

Let's check the result:

=>

untitl61.png


Well, this system have captured this leak location.

Let's check it via keyword -lf

=>

untitl65.png


Cool hah? ^^!



--
How to import:
- Just copy this trigger Leaks Checker into your map and change the keyword or leave it alone.

How to use:
- Very easy, just -lc, -lf or -fl :D
JASS:
//*********************************************************************************************************************************
//*********************************************************************************************************************************
//*********************************************************************************************************************************
//          L E A K S    C H E C K E R   S Y S T E M
//                                       Version: 1.6
//          Noticed:
//                  - Please read this before using this system -
//                  - This system used for check the leaks of your spells/maps, so, It will capture and saving your data
//                    locations, groups, forces, effects each times functions is called. It will cause laggy on your map if you keep using it for play game.
//                  -----------------------------------------------------------------------------
//                  - REMOVE THIS SYSTEM TO YOUR MAP AFTER USING
//
//          Requires: Jass New Gen Pack
//          System Type: vjass
//          Using for: Check leak(s)/For GUI Users
//
//          By:
//                  - Elphis
//          Keyword:
//                  -lc: When you chat this keyword, system will return all leak(s) that it captured.
//                  -lf: When you chat this keyword, system will show you where's the leak(s) in your code.
//                  -fl: When you chat this keyword, system will show you how to remove leak(s).
//          How it work:
//                      - This system will check and capturing all leak(s) of your spell/map and return results, or show you where's the leak(s) in your code.
//---------------------------------------------------------------------------------------------------------------------------------
//          How to import:
//                        - Just copy this trigger Leaks Checker into your map and change keyword or leave it alone.
//
//*********************************************************************************************************************************
//*********************************************************************************************************************************
//*********************************************************************************************************************************
library LeaksChecker initializer Init
    //
    globals
            //***********************************************SYSTEM CONFIGURATION***********************************************//
        //*********************************************************************************************************************************
        //Use indexing version, if this boolean = true, this system will use indexing to check the leak location
        //if = false, this system will use hashtable to check the leak location
        private             constant                boolean             INDEXING_VERSION                =           true
        //Keyword to run system
        private             constant                string              KEYWORD_LEAKS_CHECKER           =           "-lc"
        //Keyword to check where the leak(s) is
        private             constant                string              KEYWORD_LEAKS_FOUNDER           =           "-lf"
        //Keyword to show how to remove leak(s)
        private             constant                string              KEYWORD_LEAKS_FIX               =           "-fl"
        //Allow reset data when use
        private             constant                boolean             RESET_DATA                      =           false
        //Leaks display period
        private             constant                real                DISPLAY_PERIODIC                =           0.5
        //Player you want to display leak(s)
        private             constant                player              PLAYER_DISPLAY                  =           Player(0)
            //***********************************************NON - CONFIGURATION***********************************************//
        //*********************************************************************************************************************************
        //*********************************************************************************************************************************
        //
        private                                     integer             LocationTotalLeaks              =           0
        //
        private                                     integer             LocationLeaksRemaining          =           0
        //
        private                                     integer             LocationTotalFree               =           0
        //
        private                                     integer             LocatioTotalRemove              =           0
        //
        private                                     integer             UnidentifiedLocation            =           0
        //*********************************************************************************************************************************
        //*********************************************************************************************************************************
        //
        private                                     integer             GroupTotalLeaks                 =           0
        //
        private                                     integer             GroupLeaksRemaining             =           0
        //
        private                                     integer             GroupTotalFree                  =           0
        //
        private                                     integer             GroupTotalRemove                =           0
        //
        //*********************************************************************************************************************************
        //*********************************************************************************************************************************
        private                                     integer             EffectTotalLeaks                =           0
        //
        private                                     integer             Effect_Leaks_Remaining          =           0
        //
        private                                     integer             EffectTotalFree                 =           0
        //
        private                                     integer             EffectTotalRemove               =           0
        //*********************************************************************************************************************************
        //*********************************************************************************************************************************
        private                                     integer             ForceTotalLeaks                 =           0
        //
        private                                     integer             ForceLeaksRemaining             =           0
        //
        private                                     integer             ForceTotalFree                  =           0
        //
        private                                     integer             ForceTotalRemove                =           0
        //*********************************************************************************************************************************
        //*********************************************************************************************************************************
                //***********************************************STRING SYSTEM EDITOR***********************************************//
        //
        private             constant                string              LEAKS_GROUP_UNKNOWN             =           "Total leaks unknown group results: "
        //
        private             constant                string              LEAKS_GROUP_RESULTS             =           "Total leaks group results: "
        //
        private             constant                string              LEAKS_EFFECT_RESULTS            =           "Total leaks effect results: "
        //
        private             constant                string              LEAKS_LOCATION_RESULTS          =           "Total leaks location results: "
        //
        private             constant                string              LEAKS_LOCATION_UNIDENTIFIED     =           "Unidentified location (null handler): "
        //
        private             constant                string              LEAKS_FORCE_RESULTS             =           "Total leaks force results: "
        //*********************************************************************************************************************************
        //*********************************************************************************************************************************
        private             constant                string              LEAKS_GROUP_REMAINING           =           "Total leaks group remaining: "
        //
        private             constant                string              LEAKS_EFFECT_REMAINING          =           "Total leaks effect remaining: "
        //
        private             constant                string              LEAKS_LOCATION_REMAINING        =           "Total leaks location remaining: "
        //
        private             constant                string              LEAKS_FORCE_REMAINING           =           "Total leaks force remaining: "
        //*********************************************************************************************************************************
        //*********************************************************************************************************************************
        private             constant                string              LEAKS_GROUP_CLEANED             =           "Total leaks group cleaned: "
        //
        private             constant                string              LEAKS_EFFECT_CLEANED            =           "Total leaks effect cleaned: "
        //
        private             constant                string              LEAKS_LOCATION_CLEANED          =           "Total leaks location cleaned: "
        //
        private             constant                string              LEAKS_FORCE_CLEANED             =           "Total leaks force cleaned: "
        //*********************************************************************************************************************************
        //*********************************************************************************************************************************
        private             constant                string              LEAKS_GROUP_ERROR               =           "Total leaks group clean improper: "
        //
        private             constant                string              LEAKS_EFFECT_ERROR              =           "Total leaks effect clean improper: "
        //
        private             constant                string              LEAKS_LOCATION_ERROR            =           "Total leaks location clean improper: "
        //
        private             constant                string              LEAKS_FORCE_ERROR               =           "Total leaks force clean improper: "
        //**********************************************************************************************************************************
        private                                     integer             TotalWantDestroy                =           0
        private                                     group      array    GroupCount
        private                                     integer             TotalGroup                      =           0
        //
        private                                     force      array    ForceCount                    
        private                                     integer             TotalForce                      =           0
        //
        private                                     effect      array   EffectCount                    
        private                                     integer             TotalEffect                     =           0
        //
        private             constant                timer               TIMER                           =           CreateTimer()
        private                                     integer             LeaksCounter
        private                                     integer             LeaksDataCounter                =           0
        private                                     integer             TotalLeaksData                  =           0
        private                                     string      array   LeaksFounderAdd
        private                                     string      array   LeaksData[14]
        //
        endglobals
        //
        //***Can't use static if inside globals***
        static if INDEXING_VERSION then
        //
        globals
        //
        private                                     real       array    LocationCount
        private                                     integer             TotalLocation                   =           0
        private                                     integer    array    LocationTag
        //
        endglobals
        //
        else
        //
        globals
        //
        private                                     hashtable           HASH                            =           InitHashtable()
        //
        endglobals
        //
        endif
         //*********************************************************************************************************************************
    //
        //***********************************************Don't touch anything below***********************************************//
    //
    private function RemoveData takes string s returns nothing
        local integer i = 1
        //
        loop
            exitwhen i > LeaksDataCounter
            if LeaksFounderAdd[i] == s then
                set LeaksFounderAdd[i] = LeaksFounderAdd[LeaksDataCounter]
                set LeaksFounderAdd[LeaksDataCounter] = null
                set LeaksDataCounter = LeaksDataCounter - 1
            endif
            set i = i + 1
        endloop
        //
    endfunction
    //
    private function GetUnitLocDetector takes unit u returns nothing
        static if not INDEXING_VERSION then
            local integer w
        endif
        if u == null then
            set UnidentifiedLocation = UnidentifiedLocation + 1
        else
            set LeaksDataCounter =LeaksDataCounter + 1
            set LeaksFounderAdd[LeaksDataCounter] = LeaksData[6]
            set LocationTotalLeaks = LocationTotalLeaks + 1
            set LocationLeaksRemaining = LocationLeaksRemaining + 1
            static if INDEXING_VERSION then
            set LocationCount[TotalLocation] = GetWidgetX(u)
            set LocationTag[TotalLocation] = 6
            set TotalLocation = TotalLocation + 1
            else
            set w = R2I(GetWidgetX(u))
            call SaveBoolean(HASH,1,w,true)
            call SaveInteger(HASH,2,w,6)
            endif
        endif
    endfunction
    //
    hook GetUnitLoc GetUnitLocDetector
    //
    private function RemoveLocationDetector takes location loc returns nothing
        local boolean c = false
        static if INDEXING_VERSION then
        local real r = GetLocationX(loc)
        local integer i = TotalLocation
        local integer tag
        else
        local integer w
        endif
        static if INDEXING_VERSION then
        loop
            exitwhen i < 0
            if r == LocationCount[i] and LocationCount[i] != 0. then
                set c = true
                set tag = LocationTag[i]
                set LocationCount[i] = LocationCount[TotalLocation]
                set LocationCount[TotalLocation] = -1.
                set TotalLocation = TotalLocation - 1
                exitwhen true
            endif
            set i = i - 1
        endloop
        else
        set w = R2I(GetLocationX(loc)
        if LoadBoolean(HASH,1,w) then
            set c = true
            call RemoveSavedHandle(HASH,1,w)
            call RemoveData(LoadInteger(HASH,2,w)
            call RemoveSavedHandle(HASH,2,w)
        endif
        endif
        if loc == null or not c then
            set LocationTotalFree = LocationTotalFree + 1
        elseif c then
            call RemoveData(LeaksData[tag])
            set LocationLeaksRemaining = LocationLeaksRemaining - 1
            set LocatioTotalRemove = LocatioTotalRemove + 1
        endif
    endfunction
    //
    hook RemoveLocation RemoveLocationDetector
    //
    private function GetOrderPointLocDetector takes nothing returns nothing
        static if not INDEXING_VERSION then
            local integer w
        endif
        set LocationTotalLeaks = LocationTotalLeaks + 1
        set LocationLeaksRemaining = LocationLeaksRemaining + 1
        set LeaksDataCounter =LeaksDataCounter + 1
        set LeaksFounderAdd[LeaksDataCounter] = LeaksData[14]
        static if INDEXING_VERSION then
        set LocationCount[TotalLocation] = GetOrderPointX()
        set LocationTag[TotalLocation] = 14
        set TotalLocation = TotalLocation + 1
        else
        set w = R2I(GetOrderPointX())
        call SaveBoolean(HASH,1,w,true)
        call SaveInteger(HASH,2,w,14)
        endif
    endfunction
    //
    hook GetOrderPointLoc GetOrderPointLocDetector
    //
    private function GetSpellTargetLocDetector takes nothing returns nothing
        static if not INDEXING_VERSION then
            local integer w
        endif
        set LocationTotalLeaks = LocationTotalLeaks + 1
        set LocationLeaksRemaining = LocationLeaksRemaining + 1
        set LeaksDataCounter =LeaksDataCounter + 1
        set LeaksFounderAdd[LeaksDataCounter] = LeaksData[13]
        static if INDEXING_VERSION then
        set LocationCount[TotalLocation] = GetSpellTargetX()
        set LocationTag[TotalLocation] = 13
        set TotalLocation = TotalLocation + 1
        else
        set w = R2I(GetSpellTargetX())
        call SaveBoolean(HASH,1,w,true)
        call SaveInteger(HASH,2,w,13)
        endif
    endfunction
    //
    hook GetSpellTargetLoc GetSpellTargetLocDetector
    //
    private function LocationDetector takes real x,real y returns nothing
        static if not INDEXING_VERSION then
            local integer w
        endif
        set LocationTotalLeaks = LocationTotalLeaks + 1
        set LocationLeaksRemaining = LocationLeaksRemaining + 1
        set LeaksDataCounter =LeaksDataCounter + 1
        set LeaksFounderAdd[LeaksDataCounter] = LeaksData[5]
        static if INDEXING_VERSION then
        set LocationCount[TotalLocation] = x
        set LocationTag[TotalLocation] = 5
        set TotalLocation = TotalLocation + 1
        else
        set w = R2I(x)
        call SaveBoolean(HASH,1,w,true)
        call SaveInteger(HASH,2,w,5)
        endif
    endfunction
    //
    hook Location LocationDetector
    //
    private function GetRectCenterDetector takes rect r returns nothing
        static if not INDEXING_VERSION then
            local integer w
        endif
        if r == null then
            set UnidentifiedLocation = UnidentifiedLocation + 1
        else
            set LocationTotalLeaks = LocationTotalLeaks + 1
            set LocationLeaksRemaining = LocationLeaksRemaining + 1
            set LeaksDataCounter =LeaksDataCounter + 1
            set LeaksFounderAdd[LeaksDataCounter] = LeaksData[4]
            static if INDEXING_VERSION then
            set LocationCount[TotalLocation] = GetRectCenterX(r)
            set LocationTag[TotalLocation] = 4
            set TotalLocation = TotalLocation + 1
            else
            set w = R2I(GetRectCenterX(r))
            call SaveBoolean(HASH,1,w,true)
            call SaveInteger(HASH,2,w,4)
            endif
        endif
    endfunction
    //
    hook GetRectCenter GetRectCenterDetector
    //
    private function GetDestructableLocDetector takes destructable d returns nothing
        static if not INDEXING_VERSION then
            local integer w
        endif
        if d == null then
            set UnidentifiedLocation = UnidentifiedLocation + 1
        else
            set LocationTotalLeaks = LocationTotalLeaks + 1
            set LocationLeaksRemaining = LocationLeaksRemaining + 1
            set LeaksDataCounter =LeaksDataCounter + 1
            set LeaksFounderAdd[LeaksDataCounter] = LeaksData[7]
            static if INDEXING_VERSION then
            set LocationCount[TotalLocation] = GetWidgetX(d)
            set LocationTag[TotalLocation] = 7
            set TotalLocation = TotalLocation + 1
            else
            set w = R2I(GetWidgetX(d))
            call SaveBoolean(HASH,1,w,true)
            call SaveInteger(HASH,2,w,7)
            endif
        endif
    endfunction
    //
    hook GetDestructableLoc GetDestructableLocDetector
    //
    private function GetItemLocDetector takes item t returns nothing
        static if not INDEXING_VERSION then
            local integer w
        endif
        if t == null then
            set UnidentifiedLocation = UnidentifiedLocation + 1
        else
            set LocationTotalLeaks = LocationTotalLeaks + 1
            set LocationLeaksRemaining = LocationLeaksRemaining + 1
            set LeaksDataCounter =LeaksDataCounter + 1
            set LeaksFounderAdd[LeaksDataCounter] = LeaksData[8]
            static if INDEXING_VERSION then
            set LocationCount[TotalLocation] = GetWidgetX(t)
            set LocationTag[TotalLocation] = 8
            set TotalLocation = TotalLocation + 1
            else
            set w = R2I(GetWidgetX(t))
            call SaveBoolean(HASH,1,w,true)
            call SaveInteger(HASH,2,w,8)
            endif
        endif
    endfunction
    //
    hook GetItemLoc GetItemLocDetector
    //
    private function GetPlayerStartLocationLocDetector takes player p returns nothing
        static if not INDEXING_VERSION then
            local integer w
        endif
        if p == null then
            set UnidentifiedLocation = UnidentifiedLocation + 1
        else
            set LocationTotalLeaks = LocationTotalLeaks + 1
            set LocationLeaksRemaining = LocationLeaksRemaining + 1
            set LeaksDataCounter =LeaksDataCounter + 1
            set LeaksFounderAdd[LeaksDataCounter] = LeaksData[9]
            static if INDEXING_VERSION then
            set LocationCount[TotalLocation] = GetStartLocationX(GetPlayerId(p))
            set LocationTag[TotalLocation] = 9
            set TotalLocation = TotalLocation + 1
            else
            set w = R2I(GetStartLocationX(GetPlayerId(p)))
            call SaveBoolean(HASH,1,w,true)
            call SaveInteger(HASH,2,w,9)
            endif
        endif
    endfunction
    //
    hook GetPlayerStartLocationLoc GetPlayerStartLocationLocDetector
    //
    private function GroupPickRandomUnitDetector takes group g returns nothing
        set LeaksDataCounter =LeaksDataCounter + 1
        set LeaksFounderAdd[LeaksDataCounter] = LeaksData[1]
        set GroupTotalLeaks = GroupTotalLeaks + 1
        set GroupLeaksRemaining = GroupLeaksRemaining + 1
        set GroupCount[TotalGroup] = g
        set TotalGroup = TotalGroup + 1
    endfunction
    //
    hook GroupPickRandomUnit GroupPickRandomUnitDetector
    //
    private function GetRandomSubGroupDetector takes integer i, group g returns nothing
        set LeaksDataCounter =LeaksDataCounter + 1
            set LeaksFounderAdd[LeaksDataCounter] = LeaksData[2]
        set GroupTotalLeaks = GroupTotalLeaks + 1
        set GroupLeaksRemaining = GroupLeaksRemaining + 1
        set GroupCount[TotalGroup] = g
        set TotalGroup = TotalGroup + 1
    endfunction
    //
    hook GetRandomSubGroup GetRandomSubGroupDetector
    //
    private function ForGroupDetector takes group g, code func returns nothing
        set LeaksDataCounter =LeaksDataCounter + 1
        set LeaksFounderAdd[LeaksDataCounter] = LeaksData[10]
        set GroupCount[TotalGroup] = g
        set TotalGroup = TotalGroup + 1
        set GroupLeaksRemaining = GroupLeaksRemaining + 1
        set GroupTotalLeaks = GroupTotalLeaks + 1
        //
        if bj_wantDestroyGroup then
            set TotalWantDestroy = TotalWantDestroy + 1
        endif
        //
    endfunction
    //
    hook ForGroup ForGroupDetector
    hook ForGroupBJ ForGroupDetector
    //
    private function CountUnitsInGroupDetector takes group g returns nothing
        set TotalGroup = TotalGroup - 1
        set GroupLeaksRemaining = GroupLeaksRemaining - 1
    endfunction
    //
    hook CountUnitsInGroup CountUnitsInGroupDetector
    //
    private function DestroyGroupDetector takes group g returns nothing
        local integer i = TotalGroup
        local boolean c = false
        loop
            exitwhen i < 0
            if g == GroupCount[i] and GroupCount[i] != null then
                set c = true
                set GroupCount[i] = GroupCount[TotalGroup]
                set GroupCount[TotalGroup] = null
                set TotalGroup = TotalGroup - 1
                exitwhen true
            endif
            set i = i - 1
        endloop
        if g == null or not c then
            set GroupTotalFree = GroupTotalFree + 1
        elseif c then
            call RemoveData(LeaksData[10])
            set GroupTotalRemove = GroupTotalRemove + 1
            set GroupLeaksRemaining = GroupLeaksRemaining - 1
        endif
    endfunction
    //
    hook DestroyGroup DestroyGroupDetector
    //
    private function AddSpecialEffectLocBJDetector takes location loc, string path returns nothing
        set LeaksDataCounter =LeaksDataCounter + 1
        set LeaksFounderAdd[LeaksDataCounter] = LeaksData[11]
        set EffectTotalLeaks = EffectTotalLeaks + 1
        set Effect_Leaks_Remaining = Effect_Leaks_Remaining + 1
    endfunction
    //
    hook AddSpecialEffectLocBJ AddSpecialEffectLocBJDetector
    //
    private function AddSpecialEffectLocDetector takes string path, location loc returns nothing
        set EffectTotalLeaks = EffectTotalLeaks + 1
        set Effect_Leaks_Remaining = Effect_Leaks_Remaining + 1
    endfunction
    //
    hook AddSpecialEffectLoc AddSpecialEffectLocDetector
    //
    private function AddSpecialEffectDetector takes string path, real x, real y returns nothing
        set EffectTotalLeaks = EffectTotalLeaks + 1
        set Effect_Leaks_Remaining = Effect_Leaks_Remaining + 1
    endfunction
    //
    hook AddSpecialEffect AddSpecialEffectDetector
    //
    private function AddSpecialEffectTargetDetector takes string path, widget Widget, string attachment returns nothing
        set EffectTotalLeaks = EffectTotalLeaks + 1
        set Effect_Leaks_Remaining = Effect_Leaks_Remaining + 1
    endfunction
    //
    hook AddSpecialEffectTarget AddSpecialEffectTargetDetector
    //
    private function AddSpecialEffectTargetUnitBJDetector takes string path, widget Widget, string attachment returns nothing
        set LeaksDataCounter =LeaksDataCounter + 1
        set EffectTotalLeaks = EffectTotalLeaks + 1
        set Effect_Leaks_Remaining = Effect_Leaks_Remaining + 1
    endfunction
    //
    hook AddSpecialEffectTargetUnitBJ AddSpecialEffectTargetUnitBJDetector
    //
    private function DestroyEffectBJDetector takes effect e returns nothing
        local integer i = 0
        
        loop
            exitwhen i > TotalEffect
            
            if EffectCount[i] == e then
                set EffectTotalFree = EffectTotalFree + 1
                return
            endif
            
            set i = i + 1
        endloop
        
        if e != null then
            call RemoveData(LeaksData[11])
            set Effect_Leaks_Remaining = Effect_Leaks_Remaining - 1
            set EffectTotalRemove = EffectTotalRemove + 1
            set EffectCount[TotalEffect] = e
            set TotalEffect = TotalEffect + 1
        else
            set EffectTotalFree = EffectTotalFree + 1
        endif
        
    endfunction
    //
    hook DestroyEffectBJ DestroyEffectBJDetector
    hook DestroyEffect DestroyEffectBJDetector
    //
    private function DestroyForceDetector takes force f returns nothing
        local integer i = TotalForce
        local boolean c = false
        loop
            exitwhen i < 0
            if f == ForceCount[i] and ForceCount[i] != null then
                set c = true
                set ForceCount[i] = ForceCount[TotalForce]
                set ForceCount[TotalForce] = null
                set TotalForce = TotalForce - 1
                exitwhen true
            endif
            set i = i - 1
        endloop
        if f == null or not c then
            set ForceTotalFree = ForceTotalFree + 1
        elseif c then
            call RemoveData(LeaksData[12])
            set ForceLeaksRemaining = ForceLeaksRemaining - 1
            set ForceTotalRemove = ForceTotalRemove + 1
        endif
    endfunction
    //
    hook DestroyForce DestroyForceDetector
    //
    private function ForForceDetector takes force f,code func returns nothing
        set LeaksDataCounter =LeaksDataCounter + 1
        set LeaksFounderAdd[LeaksDataCounter] = LeaksData[12]
        set ForceTotalLeaks = ForceTotalLeaks + 1
        set ForceLeaksRemaining = ForceLeaksRemaining + 1
        set ForceCount[TotalForce] = f
        set TotalForce = TotalForce + 1
    endfunction
    //
    hook ForForce ForForceDetector
    //This function display total leaks in your Spell/Map
    private function Leaks_Checker_Action takes nothing returns boolean
        local player p = GetTriggerPlayer()
        //
        call DisplayTextToPlayer(p,0,0,LEAKS_GROUP_RESULTS+I2S(GroupTotalLeaks))
        call DisplayTextToPlayer(p,0,0,LEAKS_EFFECT_RESULTS+I2S(EffectTotalLeaks))
        call DisplayTextToPlayer(p,0,0,LEAKS_FORCE_RESULTS+I2S(ForceTotalLeaks))
        call DisplayTextToPlayer(p,0,0,LEAKS_LOCATION_RESULTS+I2S(LocationTotalLeaks)+"/"+LEAKS_LOCATION_UNIDENTIFIED+I2S(UnidentifiedLocation))
        //
        call DisplayTextToPlayer(p,0,0,LEAKS_FORCE_REMAINING+I2S(ForceLeaksRemaining))
        call DisplayTextToPlayer(p,0,0,LEAKS_GROUP_REMAINING+I2S(GroupLeaksRemaining))
        call DisplayTextToPlayer(p,0,0,LEAKS_EFFECT_REMAINING+I2S(Effect_Leaks_Remaining))
        call DisplayTextToPlayer(p,0,0,LEAKS_LOCATION_REMAINING+I2S(LocationLeaksRemaining))
        //
        call DisplayTextToPlayer(p,0,0,LEAKS_FORCE_CLEANED+I2S(ForceTotalRemove))
        call DisplayTextToPlayer(p,0,0,LEAKS_GROUP_CLEANED+I2S(GroupTotalRemove)+"/bj_wantDestroyGroup used: "+I2S(TotalWantDestroy))
        call DisplayTextToPlayer(p,0,0,LEAKS_EFFECT_CLEANED+I2S(EffectTotalRemove))
        call DisplayTextToPlayer(p,0,0,LEAKS_LOCATION_CLEANED+I2S(LocatioTotalRemove))
        //
        call DisplayTextToPlayer(p,0,0,LEAKS_FORCE_ERROR+I2S(ForceTotalFree))
        call DisplayTextToPlayer(p,0,0,LEAKS_GROUP_ERROR+I2S(GroupTotalFree))
        call DisplayTextToPlayer(p,0,0,LEAKS_EFFECT_ERROR+I2S(EffectTotalFree))
        call DisplayTextToPlayer(p,0,0,LEAKS_LOCATION_ERROR+I2S(LocationTotalFree))
        //
        static if RESET_DATA then
            //Reset data to default
            static if not INDEXING_VERSION then
                call FlushChildHashtable(HASH,1)
            endif
            set UnidentifiedLocation = 0
            set TotalWantDestroy = 0
            set TotalForce = 0
            set TotalGroup = 0
            set GroupTotalLeaks = 0
            set EffectTotalLeaks = 0
            set ForceTotalLeaks = 0
            set LocationTotalLeaks = 0
            set ForceTotalFree = 0
            set EffectTotalFree = 0
            set LocationTotalFree = 0
            set GroupTotalFree = 0
            set LocatioTotalRemove = 0
            set EffectTotalRemove = 0
            set GroupTotalRemove = 0
            set ForceTotalRemove = 0
            set Effect_Leaks_Remaining = 0
            set GroupLeaksRemaining = 0
            set ForceLeaksRemaining = 0
            set LocationLeaksRemaining = 0
        endif
        //
        set p = null
        //
        return false
    endfunction
    //
    private function LeaksDisplay takes nothing returns nothing
        local integer i = 0
        local integer counter = 0
        
        if LeaksCounter < TotalLeaksData then
            set LeaksCounter = LeaksCounter + 1
            
            loop
                exitwhen i > LeaksDataCounter
                if LeaksFounderAdd[i] == LeaksData[LeaksCounter] then
                    set counter = counter + 1
                endif
                set i = i + 1
            endloop
            
            if counter > 0 then
                call DisplayTextToPlayer(PLAYER_DISPLAY,0.,0.,"Leak(s) tag found: "+LeaksData[LeaksCounter]+" - Leak(s) tag count: |cffFFFF00"+I2S(counter)+"|r")
            endif
        else
            call PauseTimer(TIMER)
        endif
    endfunction
    //
    private function Leaks_Founder_Action takes nothing returns boolean
        set LeaksCounter = 0
        if GetLocalPlayer() == PLAYER_DISPLAY then
            call ClearTextMessages()
        endif
        if LeaksDataCounter > 0 then
            call DisplayTextToPlayer(PLAYER_DISPLAY,0.,0.,"Check leak(s) list below :), you might know where's the leak(s) in your spell/map (|cffCC0000GUI Tags Only|r)")
            call TimerStart(TIMER,DISPLAY_PERIODIC,true,function LeaksDisplay)
        else
            call DisplayTextToPlayer(PLAYER_DISPLAY,0.,0.,"Leakless in this time !!")
        endif
        return false
    endfunction
    //
    private function Leaks_Fix_Action takes nothing returns boolean
        local player p = GetTriggerPlayer()
        if GetLocalPlayer() == p then
            call ClearTextMessages()
        endif
        call DisplayTextToPlayer(p,0.,0.,"For Leak(s) location: \n To remove it: Use |cffFF33FFRemoveLocation(|cffFFFF66whichLocation|r|cffFF33FF)|r tag.")
        call DisplayTextToPlayer(p,0.,0.,"For Leak(s) group: \n To remove it: Use |cffFF33FFDestroyGroup(|cffFFFF66whichGroup|r|cffFF33FF)|r tag.")
        call DisplayTextToPlayer(p,0.,0.,"For Leak(s) effect: \n To remove it: Use |cffFF33FFDestroyEffect(|cffFFFF66whichEffect|r|cffFF33FF)|r tag.")
        call DisplayTextToPlayer(p,0.,0.,"For Leak(s) force: \n To remove it: Use |cffFF33FFDestroyForce(|cffFFFF66whichForce|r|cffFF33FF)|r tag.")
        call DisplayTextToPlayer(p,0.,0.,"|cff00CC66You can see example about those things in the |cffFFFF00Leaks Destroy Ex|r folder (Open this map in the world editor)")
        return false
    endfunction
    //
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local trigger lf = CreateTrigger()
        local trigger fl = CreateTrigger()
        local integer i = bj_MAX_PLAYERS
        //
        loop
            exitwhen i < 0
            call TriggerRegisterPlayerChatEvent(t,Player(i),KEYWORD_LEAKS_CHECKER,true)
            call TriggerRegisterPlayerChatEvent(lf,Player(i),KEYWORD_LEAKS_FOUNDER,true)
            call TriggerRegisterPlayerChatEvent(fl,Player(i),KEYWORD_LEAKS_FIX,true)
            set i = i - 1
        endloop
        //
        call TriggerAddCondition(t,function Leaks_Checker_Action)
        call TriggerAddCondition(lf,function Leaks_Founder_Action)
        call TriggerAddCondition(fl,function Leaks_Fix_Action)
        //
        set i = 1
        //1
        set LeaksData[i] = "Jass: GroupPickRandomUnit/GUI: Random unit from (Random <|cffFFFF00?|r> units from (Units in <|cffFFFF00Rect|r>))"
        set i = i + 1
        //2
        set LeaksData[i] = "Jass: GetRandomSubGroup/GUI: (Random <|cffFFFF00?|r> units from (Units in Rect|r>)))"
        set i = i + 1
        //3
        set LeaksData[i] = "Jass: CountUnitInGroup/GUI: (Number of units in (Units in <|cffFFFF00Rect|r>))"
        set i = i + 1
        //4
        set LeaksData[i] = "Jass: GetRectCenter/GUI: Center of <|cffFFFF00Rect|r>"
        set i = i + 1
        //5
        set LeaksData[i] = "Jass: Location/GUI: Point(<|cffFFFF00Real|r>, <|cffFFFF00Real|r>))"
        set i = i + 1
        //6
        set LeaksData[i] = "Jass: GetUnitLoc/GUI: Position of <|cffFFFF00Unit|r>)"
        set i = i + 1
        //7
        set LeaksData[i] = "Jass: GetDestructableLoc/GUI: Position of <|cffFFFF00Destructable|r>)"
        set i = i + 1
        //8
        set LeaksData[i] = "Jass: GetItemLoc/GUI: Position of <|cffFFFF00Item|r>"
        set i = i + 1
        //9
        set LeaksData[i] = "Jass: GetPlayerStartLocationLoc/GUI: <|cffFFFF00Player|r> (<|cffFFFF00Color|r>) start location)"
        set i = i + 1
        //10
        set LeaksData[i] = "Jass: ForGroupBJ/GUI: Unit Group - Pick every unit in (Units in <|cffFFFF00Rect|r>) and do (Actions)Loop - Actions"
        set i = i + 1
        //11
        set LeaksData[i] = "Jass: AddSpecialEffectLocBJ/GUI: Special Effect - Create a special effect at (<|cff33CC33Location|r>) using --"
        set i = i + 1
        //12
        set LeaksData[i] = "Jass: ForForce/GUI: UPlayer Group - Pick every player in (<|cffFFFF00Force|r>) and do (Actions)Loop - Actions"
        set i = i + 1
        //13
        set LeaksData[i] = "Jass: GetSpellTargetLoc/GUI: Target point of ability being cast"
        set i = i + 1
        //14
        set LeaksData[i] = "Jass: GetOrderPointLoc/GUI: Target point of issued order"
        //
        set TotalLeaksData = i
        //
        set t = null
    endfunction
    //
endlibrary
v1.0: First release version.
v1.0: First release version.
v1.1: Adding some code.
v1.2: Fixed some bugs, and add new code.
v1.3: Lagg fixed.
v1.4: Add hashtable version to location leaks.
v1.5: v1.5: Bugs fixed, effects checker updated, add GroupPickRandomUnit in capture list.
v.15b: Minor bugs fixed.
v1.6: Bugs fixed, now you can know where's the leak(s) in your code, add "How to remove leak(s)" with some example, minor changes.


Keywords:
memory,leak,checker,capture
Contents

Memory leaks checker (Map)

Reviews
KILLCIDE
Due to many reports of this system reporting incorrect leaks, I've decided to move this submission to Substandard. I recommend people learn how to find leaks themselves using many of the useful tutorials in the website (Memory Leaks).
Level 37
Joined
Mar 6, 2006
Messages
9,240
Why does it tell me this leaks a location, that it is improper?
  • Untitled Trigger 002
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Set p = (Position of (Random unit from (Units owned by Player 1 (Red))))
      • Custom script: call RemoveLocation(udg_p)
      • Custom script: set udg_p = null
 
System updated with more cooler :p

v1.6: Bugs fixed, now you can know where's the leak(s) in your code, add "How to remove leak(s)" with some example, minor changes.

Why does it tell me this leaks a location, that it is improper?
  • Untitled Trigger 002
    • Events
      • Player - Player 1 (Red) skips a cinematic sequence
    • Conditions
    • Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Set p = (Position of (Random unit from (Units owned by Player 1 (Red))))
      • Custom script: call RemoveLocation(udg_p)
      • Custom script: set udg_p = null

I've added it into special case.
 
I know this system is several years old, but still i wanted to point out something:

It appears that when you call a ForLoop() on a global group variable, it counts it as a leak every time you call it. I was really puzzled by this when i tested the map, but when i analyzed the code of this system i found that it never actually compares if the group has already been registered as a leak before, it only compares it when it is destroyed. It makes no sense that the same group could leak twice! And in this case, it is not even a leak but a global. Still a very useful system.
 
I know this system is several years old, but still i wanted to point out something:

It appears that when you call a ForLoop() on a global group variable, it counts it as a leak every time you call it. I was really puzzled by this when i tested the map, but when i analyzed the code of this system i found that it never actually compares if the group has already been registered as a leak before, it only compares it when it is destroyed. It makes no sense that the same group could leak twice! And in this case, it is not even a leak but a global. Still a very useful system.

Hello there and thank you for help me to point out this issue, can you give me an example ? Sorry but I dont touch this system about "several years old" ^^!. I dont know how to fix it if I dont know what to fix to. Thanks again.
 
How to reproduce the issue (in JASS): Create a global group variable and call ForGroup on it multiple times. Each time you call it, your system will register it as a leak.

How to fix it: I noticed that you keep a list of all "leaked" group handles in your system. Every time the hook function runs, loop through the list and see if the group handle used in the function call matches any of those in the list. If not, add it to the list and count it as a leak. Otherwise, proceed.
 
Top