HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Hashtables

11-08-2009, 02:01 PM#1
Kino
I noticed there arent any hastable tutorials on this site.
I also noticed that JNGP doesnt have the function to set Hastable Handles in GUI unlike the standard editor.

Is there something about hastables that makes them unsupported?
11-08-2009, 02:12 PM#2
Alevice
Well, thing with hashtables is that they bare syntactically similar to game cache. If already were using GC to store data for stuff that's not intended to travels across maps (the popular handle attachments), you pretty much know already how to use it. It's not a new concept, only a much cleaner way to.

As for JNGP not showing it up, I believe it is because the trigger/GUI condition/action/etc definition files used for the UMSWE addon haven't been updated to include them.
11-08-2009, 02:23 PM#3
Kino
Well I do understand hwo to use hastables and are currently implementing them into my map.

In just curious if Hastables have hidden bugs or any reasons why not to use them
11-09-2009, 01:11 PM#4
Alevice
Well, none thatn I know of. I believe many scripts here have adopted them indirectly by using Table itself.
11-09-2009, 01:48 PM#5
Rising_Dusk
Quote:
Originally Posted by Kinorhynkar
In just curious if Hastables have hidden bugs or any reasons why not to use them
Nope. They're also incredibly easy to use. Think of them like a native 2-dimensional array.

Moved to the proper forum.
11-09-2009, 02:10 PM#6
Anachron
Argh nvm.

Still one question through:
How is it possible that saving works when I check it instantly after saving, but not the next time?
I do not flush my table.
11-09-2009, 02:27 PM#7
Rising_Dusk
Quote:
Originally Posted by Anachron
How is it possible that saving works when I check it instantly after saving, but not the next time? I do not flush my table.
You are probably using a different hashtable or the wrong keys.
Collapse JASS:
call SaveInteger(ht, 0, 10, 500)
if HaveSavedInteger(ht, 0, 10) then
    //This runs
    call BJDebugMsg("test1")
endif
//Do a lot of stuff and wait a lot of time
if HaveSavedInteger(ht, 0, 10) then
    //This still runs
    call BJDebugMsg("test2")
endif
11-09-2009, 02:44 PM#8
Anachron
Nope. I am using this textmacro:
Collapse JASS:
//! textmacro ADVANCEDABILITY_intoTable takes TNAME, KEY, KTYPE
    public method save takes nothing returns nothing
        set $TNAME$[$KEY$] = $KEY$
    endmethod
    
    public method kill takes nothing returns nothing
        call $TNAME$.flush(integer(this))
    endmethod
    
    public static method load takes $KTYPE$ id returns thistype
        return thistype($TNAME$[id])
    endmethod
    //! endtextmacro
    //==-=-=-=-=-=-=-

struct AdvancedAbility
    private integer ID = 0

    // Constructor. Sets the ID.

    //! runtextmacro ADVANCEDABILITY_intoTable("AdvancedAbilityT",  ".ID", "integer")
endstruct

And the load integer is the same as .ID. But when I load, I get an object, but with empty data.
11-09-2009, 03:21 PM#9
Rising_Dusk
I mean, you are not actually showing how you handle the hashtable (which is important). I know you are doing it wrong, because hashtables work and I have personally verified them, even in the case you propose.
11-09-2009, 04:52 PM#10
Anachron
Here it is:

The description library.
Collapse JASS:
library AbilityDesc initializer init requires Table

    globals
        public             Table         AbilityDescT    = 0
        
        private constant string     AD_DEFAULT_CASTTIME        = "0. (+ 0.)"
        private constant string     AD_DEFAULT_COOLDOWN        = "0. (+ 0.)"
        private constant string     AD_DEFAULT_CRITICAL        = "0. (+ 0.)"
        private constant string     AD_DEFAULT_DESCRIPTION    = "Default description."
        private constant string     AD_DEFAULT_ICON            = "ReplaceableTextures\\CommandButtons\\BTNReplenishMana.blp"
        private constant string     AD_DEFAULT_MANACOST        = "0. (+ 0.)"
        private constant string     AD_DEFAULT_NAME            = "Default"
        private constant string     AD_DEFAULT_SPELLTYPE    = "0. (+ 0.)"
        private constant string     AD_DEFAULT_TARGETS        = "None"
        
        private constant string        COLOR                     = "|cffFFCC00"
        private constant string        COLOR_END                = "|r\n"
        private constant string        CONNECTER                = "\n"
        private constant string     PRE_CASTTIME             = "Casttime: "
        private constant string     PRE_COOLDOWN             = "Cooldown: "
        private constant string     PRE_CRITICAL             = "Critical: "
        private constant string     PRE_DESCRIPTION            = "Description: "
        private constant string     PRE_ICON                = "Icon: "
        private constant string     PRE_MANACOST            = "Manacost: "
        private constant string     PRE_NAME                = "Name: "
        private constant string     PRE_SPELLTYPE            = "Spelltype: "
        private constant string     PRE_TARGETS                = "Targets: "
    endglobals

    //==-=-=-=-=-=-=-
    //: Textmacros
    //==-=-=-=-=-=-=-
    //! textmacro ABILITY_DESCRIPTION_changeMember takes FUNCTION, MEMBER, TYPE, BONUS
    method operator $FUNCTION$ takes nothing returns $TYPE$
        return .$MEMBER$
    endmethod
    
    method operator $FUNCTION$= takes $TYPE$ val returns nothing
        set .$MEMBER$ = val
        $BONUS$
    endmethod
    //! endtextmacro
    
    //! textmacro ABILITY_DESCRIPTION_getString takes MEMBER, CONSTANT
    public method get$MEMBER$ takes nothing returns string
        return COLOR + PRE_$CONSTANT$ + COLOR_END + .$MEMBER$
    endmethod
    //! endtextmacro
    
    //! textmacro ABILITY_DESCRIPTION_intoTable takes TNAME, KEY, KTYPE
    public method save takes nothing returns nothing
        set $TNAME$[$KEY$] = integer(this)
    endmethod
    
    public method kill takes nothing returns nothing
        call $TNAME$.flush($KEY$)
    endmethod
    
    public static method load takes $KTYPE$ id returns thistype
        return thistype($TNAME$[id])
    endmethod
    //! endtextmacro
    //==-=-=-=-=-=-=-
    
    struct AbilityDesc
        private integer    ID                 = 0
        private string     Casttime        = AD_DEFAULT_CASTTIME
        private string     Cooldown        = AD_DEFAULT_COOLDOWN
        private string     Critical        = AD_DEFAULT_CRITICAL
        private string     Description        = AD_DEFAULT_DESCRIPTION
        private string     Icon            = AD_DEFAULT_ICON
        private string     Manacost        = AD_DEFAULT_MANACOST
        private string    Name            = AD_DEFAULT_NAME
        private string     Spelltype        = AD_DEFAULT_SPELLTYPE
        private string     Targets            = AD_DEFAULT_TARGETS
    
        public static method create takes integer id returns thistype
            local thistype this = thistype.allocate()
            
            set .ID = id
            call .save()
            
            return this
        endmethod
        
        //! runtextmacro ABILITY_DESCRIPTION_changeMember("spelltype", 		"Spelltype", 	"string", "")
        //! runtextmacro ABILITY_DESCRIPTION_changeMember("targets", 		"Targets", 		"string", "")
        //! runtextmacro ABILITY_DESCRIPTION_changeMember("cooldown", 		"Cooldown", 	"string", "")
        //! runtextmacro ABILITY_DESCRIPTION_changeMember("critical", 		"Critical", 	"string", "")
        //! runtextmacro ABILITY_DESCRIPTION_changeMember("icon", 			"Icon",		 	"string", "")
        //! runtextmacro ABILITY_DESCRIPTION_changeMember("manacost", 		"Manacost", 	"string", "")
        //! runtextmacro ABILITY_DESCRIPTION_changeMember("name", 			"Name", 		"string", "")
        //! runtextmacro ABILITY_DESCRIPTION_changeMember("casttime", 		"Casttime", 	"string", "")
        //! runtextmacro ABILITY_DESCRIPTION_changeMember("description", 	"Description", 	"string", "")
        
        //! runtextmacro ABILITY_DESCRIPTION_getString("Spelltype", 	"SPELLTYPE")
        //! runtextmacro ABILITY_DESCRIPTION_getString("Targets", 		"TARGETS")
        //! runtextmacro ABILITY_DESCRIPTION_getString("Critical", 		"CRITICAL")
        //! runtextmacro ABILITY_DESCRIPTION_getString("Cooldown", 		"COOLDOWN")
        //! runtextmacro ABILITY_DESCRIPTION_getString("Icon", 			"ICON")
        //! runtextmacro ABILITY_DESCRIPTION_getString("Manacost", 		"MANACOST")
        //! runtextmacro ABILITY_DESCRIPTION_getString("Name", 			"NAME")
        //! runtextmacro ABILITY_DESCRIPTION_getString("Casttime", 		"CASTTIME")
        //! runtextmacro ABILITY_DESCRIPTION_getString("Description", 	"DESCRIPTION")
        
        //! runtextmacro ABILITY_DESCRIPTION_intoTable("AbilityDescT", ".ID", "integer")
        
        public method getStrings takes integer i returns string
            local string s = ""
            local integer c = 128
            
            //: 128
            if i >= c then
                set i = i - c
                set c = c / 2
                set s = s + .getName() + CONNECTER
            endif
            
            //: 64
            if i >= c then
                set i = i - c
                set c = c / 2
                set s = s + .getSpelltype() + CONNECTER
            endif
            
            //: 32
            if i >= c then
                set i = i - c
                set c = c / 2
                set s = s + .getTargets() + CONNECTER
            endif
            
            //: 16
            if i >= c then
                set i = i - c
                set c = c / 2
                set s = s + .getCooldown() + CONNECTER
            endif
                
            //: 8
            if i >= c then
                set i = i - c
                set c = c / 2
                set s = s + .getManacost() + CONNECTER
            endif
                
            //: 4
            if i >= c then
                set i = i - c
                set c = c / 2    
                set s = s + .getCasttime() + CONNECTER
            endif
            
            //: 2
            if i >= c then
                set i = i - c
                set c = c / 2
                set s = s + .getCritical() + CONNECTER
            endif
                
            //: 1
            if i >= c then
                set i = i - c
                set c = c / 2
                set s = s + .getDescription() + CONNECTER
            endif
            
            return s
        endmethod
    endstruct

    private function init takes nothing returns nothing
        set AbilityDescT = Table.create()
    endfunction
    
endlibrary

Advanced Ability.
Collapse JASS:
library AdvancedAbility initializer init requires Ability, AbilityDesc, Cache, Table

    globals
        private Table AdvancedAbilityT = 0
    endglobals
    
    //! textmacro ADVANCED_ABILITY_changeMember takes FUNCTION, MEMBER, TYPE
    method operator $FUNCTION$ takes nothing returns $TYPE$
        return .$MEMBER$
    endmethod
    
    method operator $FUNCTION$= takes $TYPE$ val returns nothing
        set .$MEMBER$ = val
    endmethod
    //! endtextmacro

    //! textmacro ADVANCED_ABILITY_intoTable takes TNAME, KEY, KTYPE
    public method save takes nothing returns nothing
        set $TNAME$[$KEY$] = $KEY$
    endmethod
    
    public method kill takes nothing returns nothing
        call $TNAME$.flush($KEY$)
    endmethod
    
    public static method load takes $KTYPE$ id returns thistype
        return thistype($TNAME$[id])
    endmethod
    //! endtextmacro

    struct AdvancedAbility
        private integer        ID                = 0
        private boolean        AddToTarget        = false
        private    boolean        ShowAtTarget    = false
        private Ability        HandleObject    = 0
        private AbilityDesc Description        = 0
        
        public static method create takes integer id, boolean a, boolean s returns thistype
            local thistype this = thistype.allocate()
            
            set .AddToTarget     = a
            set .ShowAtTarget     = s
            set .ID             = id
            
            set .HandleObject     = Ability.load(id)
            set .Description    = AbilityDesc.load(id)
            
            call .save()
            
            return this
        endmethod
        
        public method add takes nothing returns nothing
            if .AddToTarget then
                call .HandleObject.unitAdd()
            endif
            
            if .ShowAtTarget then
                set tmp.Boolean = true
                call .HandleObject.show()
                set tmp.Boolean = false
            endif
        endmethod
        
        public method remove takes nothing returns nothing    
            if .AddToTarget then
                call .HandleObject.unitRem()
            endif
            
            if .ShowAtTarget then
                set tmp.Boolean = false
                call .HandleObject.show()
            endif
        endmethod
        
        //! runtextmacro ADVANCED_ABILITY_changeMember("handleObject", "HandleObject", "Ability")
        //! runtextmacro ADVANCED_ABILITY_changeMember("description", "Description", "AbilityDesc")
        //! runtextmacro ADVANCED_ABILITY_intoTable("AbilityT", ".ID", "integer")
    endstruct
    
    private function init takes nothing returns nothing
        set AdvancedAbilityT = Table.create()
    endfunction

endlibrary

The test.
Collapse JASS:
scope AbilityInit initializer init

    public function spellCast takes nothing returns nothing
        local integer id = GetSpellAbilityId()
        local AdvancedAbility aa = AdvancedAbility.load(id)
        
        call BJDebugMsg("===============")
        call BJDebugMsg("Spellcast")
        call BJDebugMsg(I2S(integer(aa)))
        call BJDebugMsg(aa.description.getName())
        call BJDebugMsg("---------------")
        call BJDebugMsg(aa.description.getStrings(255))
        call BJDebugMsg("===============")
    endfunction
    
    private function initAbilities takes nothing returns nothing
        local Ability ab = 0
        local AbilityDesc ad = 0
        local AdvancedAbility aa = 0
        
        //==-=----------------------------
        set ab = Ability.create('AHds')
        
        set ad = AbilityDesc.create('AHds')
        set ad.name = "Gottesschild"
        
        set aa = AdvancedAbility.create('AHds', false, true)
        call BJDebugMsg(AdvancedAbility.load('AHds').description.load('AHds').getName())
        //==-=----------------------------
        
    endfunction

    private function init takes nothing returns nothing
        local trigger t = CreateTrigger()
        
        call initAbilities()
        
        call TriggerAddAction(t, function spellCast)
        call TriggerRegisterPlayerUnitEvent(t, Player(0), EVENT_PLAYER_UNIT_SPELL_CAST, null)
    endfunction

endscope

It does show the name: etc stuff, but it doesn't show the value. (Its not loaded correctly)
11-09-2009, 05:05 PM#11
Rising_Dusk
But you aren't using any of the hashtable natives in that whole script you posted. If you suspect the problem is with the hashtable, then post the code that contains the usage of the hashtable. It very well may be that the problem is somewhere in the handling of the value than in the hashtable itself, just by looking at the mass of code you posted above.

Proper debugging procedure dictates that you should follow the value throughout its entire route and see where exactly it gets lost. From there, you can discern if it is in-fact the hashtable calls or something else.
11-09-2009, 05:08 PM#12
Anachron
Nope, but Table uses Hashtable and that stuff.

Do you find the mistake why I don't get the AdvancedAbility saved?

Btw, that wall of code is nothing, I have about 12 more librarys with a lot more code. Its all for my new inventory system.

Sorry for confusing you with my massive code blocks.
11-09-2009, 05:18 PM#13
Rising_Dusk
Oh, you use Table, I see. I hadn't seen that at first glance. Trust me when I say that if you're using Table, it works. It's one of the most widely used libraries on this website and sees the most testing. As long as you're not using the two-key syntax with ambiguous string keys, you will not see collisions. You also have to be using it correctly.

Some suspicious things in your code:
Collapse JASS:
    //! textmacro ADVANCED_ABILITY_intoTable takes TNAME, KEY, KTYPE
    public method save takes nothing returns nothing
        set $TNAME$[$KEY$] = $KEY$
    endmethod
    
    public method kill takes nothing returns nothing
        call $TNAME$.flush($KEY$)
    endmethod
    
    public static method load takes $KTYPE$ id returns thistype
        return thistype($TNAME$[id])
    endmethod
    //! endtextmacro
Note the $TNAME$ argument to that textmacro.
Collapse JASS:
    globals
        private Table AdvancedAbilityT = 0
    endglobals
Note the name of your Table.
Collapse JASS:
        //! runtextmacro ADVANCED_ABILITY_intoTable("AbilityT", ".ID", "integer")
Now note the first argument in the runtextmacro call.

Also, why do you even pass the table's name as an argument to the textmacro? It is a Table that never changes, so you don't need that argument.
11-09-2009, 05:23 PM#14
Anachron
Quote:
Also, why do you even pass the table's name as an argument to the textmacro? It is a Table that never changes, so you don't need that argument.
Because I wanted to use the textmacro everywhere and I will add it to a library that will be added as requirement for every table needing library.

even with AdvancedAbilityT as parameter it still not works. But thanks anyway!

Edit:
Basically what doesn't work is:
Collapse JASS:
set .HandleObject     = Ability.load(id)
set .Description    = AbilityDesc.load(id)
(Its in AdvancedAbility - Create Method)
11-09-2009, 05:31 PM#15
Rising_Dusk
It sounds like what you're doing is a lot of work and abstracting that probably isn't necessary.
Quote:
Originally Posted by Anachron
Because I wanted to use the textmacro everywhere and I will add it to a library that will be added as requirement for every table needing library.
Why? Textmacros do not take any compiled code space if they are not used, so you can define the same textmacro in multiple libraries at no cost whatsoever (give them different names). It is much cleaner (and easier to follow) to have your textmacros limited to the scope/library they are in.
Quote:
Originally Posted by Anachron
(Its in AdvancedAbility - Create Method)
But you haven't posted the "Ability" library, which is where the handleObject is being manipulated. (You said the description worked, but the object itself did not)