• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Do you need to destroy local structs

Status
Not open for further replies.
Level 11
Joined
Jun 30, 2008
Messages
580
Hello Hive!

Quick question here; When you declare a local struct (look below for example) do you need to destroy it at the end of the function/method?

JASS:
method ActivateHUD takes unit u returns nothing
            local UNITDATA udat = LoadInteger(UnitHash, GetHandleId(u), 1)
            local multiboarditem mitem = null
            
            set .pHUD = CreateMultiboard()
                
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//  
            // Set Col and .Rows
            set .Rows = 0
            call MultiboardSetColumnCount(.pHUD, COLUMNS)
            call MultiboardSetRowCount(.pHUD, .Rows)
            
            call .CreateBlock(udat.Unit, 0)
            
            if (GetOwningPlayer(udat.Unit) == GetLocalPlayer()) then
                call MultiboardDisplay(.pHUD, true)
            endif
            
            //call udat.destroy()
        endmethod

If you do, and I uncomment that line, why does it give the error "Double Free of Type: UNITDATA"?
 
The LoadInteger is to retrieve the stored struct from the hashtable, how else would I do it?

I know that the Caps is wrong just haven't gone through all the code to fix it
The code you posted makes absolutely no sense.
It's a non-static method, so you already got the struct, you just need to get it by using the 'this' keyword.

Also post the rest of the struct stub if you want us to help you. Showing a weird method out of context doesn't help.

Also, you didn't even use the multiboarditem, so you can just remove it.


You basicly use your method like a function, which means your method has to be static in order to work.


Read a tutorial about structs, especially about the difference between static and non-static structs and you should be able to fix your problem.
 
Level 11
Joined
Jun 30, 2008
Messages
580
The code you posted makes absolutely no sense.
It's a non-static method, so you already got the struct, you just need to get it by using the 'this' keyword.

Also post the rest of the struct stub if you want us to help you. Showing a weird method out of context doesn't help.

Also, you didn't even use the multiboarditem, so you can just remove it.


You basicly use your method like a function, which means your method has to be static in order to work.


Read a tutorial about structs, especially about the difference between static and non-static structs and you should be able to fix your problem.

Sorry about the confusion. The LoadInteger is used to retrieve the data that is stored for the Unit. Perhaps the structs will help explain:


JASS:
// RealTimeData of Units in Game
library UnitData requires UnitProperties

    globals
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// 
        // Hashtable Variables
        hashtable UnitHash = InitHashtable()
        //
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// 
        
//**************************************************************//
//                          Constants                           //
//**************************************************************//

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//  
        // Unit States
        constant integer HOSTILE_UNIT_STATE     = 1
        constant integer PASSIVE_UNIT_STATE     = 2
        constant integer NEUTRAL_UNIT_STATE     = 3
        //
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// 
        
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//              
        // Stat IDs
        
        // Set STAT_ARRAY to the number of total stats
        constant integer STAT_ARRAY     = 14

        constant integer ATTACK_MIN     = 1 
        constant integer ATTACK_MAX     = 2
        constant integer ARMOR          = 3
        
        constant integer HEALTH_MAX     = 4
        constant integer ENERGY_RATE    = 5
        
        constant integer CRIT_CHANCE    = 6
        constant integer EVAS_CHANCE    = 7
        constant integer STUN_CHANCE    = 8
        constant integer BLOCK_CHANCE   = 9
        constant integer CLEV_CHANCE    = 10
        constant integer PARRY_CHANCE   = 11
        
        constant integer VITALITY       = 12
        constant integer DEXTERITY      = 13
        constant integer FOCUS          = 14
        //
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// 

    endglobals
    
//**************************************************************//

    struct UnitData
        
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//                                                                     
        // Input Variables  - Basic characteristics                                                           
        unit Unit
        string Name
        real Size
        real NameHeight
        //
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//  
        
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// 
        // System Variables
        real array Stat[STAT_ARRAY]
        integer array UnitState[MAX_PLAYERS]
        // Target Variables
        unit Target
        // HUD Variables
        MultibarHelper uH
        MultibarHelper uE
        //
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// 
        
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//  
        // Stat Functions, Use the stat IDs above
        method modifyStat takes integer statid, real value returns nothing
            set .Stat[statid] = .Stat[statid] + value
        endmethod
        //
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//  
        
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//  
        // create method
        static method create takes unit u returns UnitData
            local UnitData t= UnitData.allocate()
                
                set t.Unit          = u
                call SaveInteger(UnitHash, GetHandleId(u), 1, t)
                
            return t
        endmethod
        //
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// 
    endstruct
    
endlibrary


This struct is used to track realtime data of units ingame. Each instance is stored into a hashtable by the unit's handle id.

The next struct (PlayerHUD) takes the data stored to create the bars for the unit you are selecting.

JASS:
ibrary PlayerHUD

    globals
        private constant integer COLUMNS            = 14
        
        private constant real CLEAR_ITEM_WIDTH      = 0.0001
        private constant real ICON_WIDTH            = 0.01
        private constant real NAME_SPACE            = 0.01
        private constant real NAME_WIDTH            = 0.12
        
        private constant string CHAR_ICON           = ""
    endglobals
    
    
    
    struct PlayerHUD
        multiboard pHUD
        integer Rows
        unit PrevSelection
        
        private method formatBlock takes integer row returns nothing
            local integer colloop       = 0
            local integer rowloop       = row
            local multiboarditem mitem  = null
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            // Clear Rows and Cols for the new block
                    
            loop
            exitwhen colloop > COLUMNS
                            
                loop
                exitwhen rowloop > row+3
                                
                    set mitem = MultiboardGetItem(.pHUD, rowloop, colloop)
                    call MultiboardSetItemStyle(mitem, false, false)
                    call MultiboardSetItemWidth(mitem, CLEAR_ITEM_WIDTH) // Sets Cell Width
                    call MultiboardReleaseItem(mitem) // Clears multiboarditem mitem
                            
                set rowloop = rowloop+1
                endloop
            set rowloop = row
                            
            set colloop = colloop+1
            endloop
            set colloop = 0
                
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            // Row 2
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            // Bar Setup
            set rowloop = row+1
                
            loop // Loops through col to set Icon only
            exitwhen colloop > 11
                    
                loop
                exitwhen rowloop > row+2
                        
                    set mitem = MultiboardGetItem(.pHUD, rowloop, colloop)
                    call MultiboardSetItemStyle(mitem, false, true)
                    call MultiboardReleaseItem(mitem)
                        
                set rowloop = rowloop+1
                endloop
                set rowloop = row+1
                        
            set colloop = colloop+1
            endloop
            set colloop = 0
        endmethod
        
        method createBlock takes unit u, integer row returns nothing
            local UnitData udat = LoadInteger(UnitHash, GetHandleId(u), 1)
            local multiboarditem mitem = null
            
            set .PrevSelection = u
            
            set .Rows = .Rows+4
            call MultiboardSetRowCount(.pHUD, .Rows)
            
            call .formatBlock(row)
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            // Unit Icon
            set mitem = MultiboardGetItem(.pHUD, row, 0)
            call MultiboardSetItemStyle(mitem, false, true) // Only Icon
            call MultiboardSetItemWidth(mitem, ICON_WIDTH) // Sets Cell Width
            call MultiboardReleaseItem(mitem) // Clears multiboarditem mitem
            //
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            // Unit Name Space
            set mitem = MultiboardGetItem(.pHUD, row, 1)
            call MultiboardSetItemStyle(mitem, false, false)
            call MultiboardSetItemWidth(mitem, NAME_SPACE) // Sets Cell Width
            call MultiboardReleaseItem(mitem) // Clears multiboarditem mitem
            //
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            // Unit Name
            set mitem = MultiboardGetItem(.pHUD, row, 2)
            call MultiboardSetItemStyle(mitem, true, false) // Only Text
            call MultiboardSetItemValue(mitem, udat.Name)
            call MultiboardSetItemWidth(mitem, NAME_WIDTH) // Sets Cell Width
            call MultiboardReleaseItem(mitem) // Clears multiboarditem mitem
            //
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            // Health Bar Space
            set mitem = MultiboardGetItem(.pHUD, row+1, 0)
            call MultiboardSetItemStyle(mitem, false, false)
            call MultiboardSetItemWidth(mitem, 0.01) // Sets Cell Width
            call MultiboardReleaseItem(mitem) // Clears multiboarditem mitem
            // Creates the Health Bar that displays on the Multiboard
            set udat.uH = MultibarHelper.create(udat.Unit, .pHUD, 1, row+1, 12, MULTIBAR_TYPE_HEALTH, MULTIBAR_HELPER_HEALTH)
            //
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            // Energy Bar Space
            set mitem = MultiboardGetItem(.pHUD, row+2, 0)
            call MultiboardSetItemStyle(mitem, false, false)
            call MultiboardSetItemWidth(mitem, 0.01) // Sets Cell Width
            call MultiboardReleaseItem(mitem) // Clears multiboarditem mitem
            // Creates the Energy Bar that displays on the Multiboard
            set udat.uE = MultibarHelper.create(udat.Unit, .pHUD, 1, row+2, 12, MULTIBAR_TYPE_MANA, MULTIBAR_HELPER_MANA)
            //
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
            
            call udat.destroy()
        endmethod
        
        method removeBlock takes unit u returns nothing
            local UnitData udat = LoadInteger(UnitHash, GetHandleId(u), 1)
            
            call udat.uH.destroy()
            call udat.uE.destroy()
            
            set .Rows = .Rows-4
            
            call udat.destroy()
        endmethod
        
        method activateHUD takes unit u returns nothing
            local UnitData udat = LoadInteger(UnitHash, GetHandleId(u), 1)
            
            set .pHUD = CreateMultiboard()
                
            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//  
            // Set Col and .Rows
            set .Rows = 0
            call MultiboardSetColumnCount(.pHUD, COLUMNS)
            call MultiboardSetRowCount(.pHUD, .Rows)
            
            call .createBlock(udat.Unit, 0)
            
            if (GetOwningPlayer(udat.Unit) == GetLocalPlayer()) then
                call MultiboardDisplay(.pHUD, true)
            endif
            
            call udat.destroy()
        endmethod
        
    endstruct
    
endlibrary

This PlayerHUD is stored for each player in this struct (CharData) which contains UnitData and the PlayerHUD and any other data that needs to be stored for each character


JASS:
// Data used by the players character in the game.
library CharacterData requires ThirdPersonCam

    globals
        hashtable CharacterHash = InitHashtable()
        
        constant string CHARACTER_CHAT_NAME_COLOR   = "|cffdaa520"
//**************************************************************//
//                          Constants                           //
//**************************************************************//
        
        
    endglobals
    
    struct CharData
        UnitData uData
        PlayerHUD mHUD
        
        string Title
        
        static method create takes player p returns CharData
            local CharData c = CharData.allocate()
                call SaveInteger(CharacterHash, GetPlayerId(p), 1, c) 
            return c
        endmethod
        
        method activateCharacter takes nothing returns nothing
            // Cam
            set .uData = UnitData.create(CreateUnit(GetTriggerPlayer(), 'CHAR', GetRectCenterX(gg_rct_Start), GetRectCenterY(gg_rct_Start), 0))
            //call UnitData.create(gg_unit_CHAR_0007 ) For Testing
            call EnableThirdPersonCam(GetOwningPlayer(.uData.Unit), .uData.Unit, 0.0)
            
            // Character Setup
            set .uData.Name = .Title + CHARACTER_CHAT_NAME_COLOR+GetPlayerName(GetOwningPlayer(.uData.Unit))+"|r"
            call SetPlayerName(GetOwningPlayer(.uData.Unit), .uData.Name)
            
            // Player HUD
            set .mHUD = PlayerHUD.create()
            call .mHUD.activateHUD(.uData.Unit)
            
            // Character Stats
            set .uData.Stat[VITALITY]     = 5
            set .uData.Stat[DEXTERITY]    = 5
            set .uData.Stat[FOCUS]        = 5
            
        endmethod
    endstruct
    
endlibrary


I'm starting to feel this might not be the best way to do this D:
 
The general logic of your coding is messed up and its unneccessarily complicated.

You need only *number of players* instances of playerHUD and *number of units* instances of UnitData. CharacterData and playerHUD should be merged as they share the same instances (they are both bound to players).

Store playerHUD in an array of 12 for all players and UnitData in a UnitData array indexed by a unit indexer (Your hashtable approach is fine aswell, but it's a better style of programming to use an array if you do not need the two dimensions of tables).


And to go back to your initial question:
Destroying UnitData is not neccessary (actually, it will bug your system, so remove it), as UnitData is bound to units. UnitData structs should only be created or destroyed when the unit is indexed or deindexed (created or destroyed).

Some other stuff I noticed:
There's no need to have more than one hashtable. Simply use a global public hashtable for all of the structs. But I recommend using a unit indexer and a UnitData array instead.
Actually, in your case you could just use a CharData array with size 12, as you index your CharData structs with GetPlayerIds anyway.
 
Status
Not open for further replies.
Top