HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

UnitUtils... Comments & Suggestions

02-28-2009, 02:04 AM#1
moyack
Hi...

Due to this comments, I was thinking in how we can do a script which allows an easy way to attach multiple data to one unit. I tinkered this option and I'd like to know if I'm wasting my time or if it could work more efficient than Table.

I based several parts of the code in CSData, so for this part I consider it safer.

Collapse JASS:
library UnitUtils

globals
    private constant integer MAX_UNIT_ID_COUNT = 408000 //
    private constant integer ARRAY_SIZE        = 10 // Sets the maximum number of values that a unit can have stored
endglobals

private struct data [MAX_UNIT_ID_COUNT]
    static constant integer MIN_UNIT_ID = 0x100000
    static          group   G           = CreateGroup()
    static          integer index       = 0
    integer array d [ARRAY_SIZE]
endstruct

private function U2I takes unit u returns integer
    return u
    return 0
endfunction

function GetUnitIndex takes unit u returns integer 
    debug if(U2I(u) - data.MIN_UNIT_ID >= MAX_UNIT_ID_COUNT) then
    debug     call BJDebugMsg(SCOPE_PREFIX + ": Unit id too big, increase the MAX_UNIT_ID_COUNT constant or use gamecache instead")
    debug endif
    if not IsUnitInGroup(u, data.G) then
        call GroupAddUnit(data.G, u)
        debug call DisplayTimedTextFromPlayer(Player(0), 0,0,2, I2S(U2I(u) - data.MIN_UNIT_ID))
        set data(U2I(u) - data.MIN_UNIT_ID).d[0] = data.index
        set data.index = data.index + 1
        return data.index
    endif
    return data(U2I(u) - data.MIN_UNIT_ID).d[0]
endfunction

function GetUnitData takes unit u, integer id returns integer 
    if id <= ARRAY_SIZE then
        return data(GetUnitIndex(u)).d[id]
    endif
    return 0
endfunction

function SetUnitData takes unit u, integer id, integer value returns nothing 
    if id <= ARRAY_SIZE then
        set data(GetUnitIndex(u)).d[id] = value
    endif
endfunction

endlibrary

As you can see, by setting the ARRAY_SIZE constant, we can allow to each unit in a game to store a struct which can relate a bunch of other data.

You know the drill: comments, suggestions, improvements, benchmarks, kisses are welcome.
02-28-2009, 02:19 AM#2
akolyt0r
i dont like that .id / array stuff ..its not useful ..really.. ..and it doesnt favor Modularity at all...
- Or -
Use string-keys as function parameters (pretty similar to gamecache-stuff)
SetUnitData(u,"mySpellXY) ...but i dont know if that is possible without having ...O(n) stuff..
02-28-2009, 02:39 AM#3
Vexorian
That id stuff is not going to work, 10 is an absolutely low amount, and increasing it will decrease robustness. You'll need a different method, one that I am not knowledgeable off. Or to just remove that id thing.


Quote:
Use string-keys as function parameters (pretty similar to gamecache-stuff)
SetUnitData(u,"mySpellXY) ...but i dont know if that is possible without having ...O(n) stuff..
It isn't, it simply isn't - without gamecache, but that would be the same as 4 years ago.


Quote:
..and it doesnt favor Modularity at all...
Uh not really.
02-28-2009, 02:40 AM#4
moyack
Quote:
Originally Posted by akolyt0r
i dont like that .id / array stuff ..its not useful ..really.. ..and it doesnt favor Modularity at all...
- Or -
Use string-keys as function parameters (pretty similar to gamecache-stuff)
SetUnitData(u,"mySpellXY) ...but i dont know if that is possible without having ...O(n) stuff..
Me neither... but adding a string as parameter would make Table more suitable than this code.

Quote:
Originally Posted by Vex
That id stuff is not going to work, 10 is an absolutely low amount, and increasing it will decrease robustness. You'll need a different method, one that I am not knowledgeable off. Or to just remove that id thing.
10 is just for testing... I know it's very low but for my testings is enough to play with it.

EDIT: Code updated a little bit:

Collapse JASS:
library UnitUtils

globals
    private constant integer MAX_UNIT_ID_COUNT = 408000
    private constant integer ARRAY_SIZE        = 10 // Sets the maximum number of values that a unit can have stored
endglobals

private struct data [MAX_UNIT_ID_COUNT]
    static constant integer MIN_UNIT_ID = 0x100000
    static          group   G           = CreateGroup()
    static          integer index       = 0
    integer id
    integer array d [ARRAY_SIZE]
endstruct

private function U2I takes unit u returns integer
    return u
    return 0
endfunction

function GetUnitIndex takes unit u returns integer 
    debug if(U2I(u) - data.MIN_UNIT_ID >= MAX_UNIT_ID_COUNT) then
    debug     call BJDebugMsg(SCOPE_PREFIX + ": Unit id too big, increase the MAX_UNIT_ID_COUNT constant or use gamecache instead")
    debug endif
    if not IsUnitInGroup(u, data.G) then
        call GroupAddUnit(data.G, u)
        set data(U2I(u) - data.MIN_UNIT_ID).id = data.index
        set data.index = data.index + 1
        return data.index
    endif
    return data(U2I(u) - data.MIN_UNIT_ID).id
endfunction

function GetUnitData takes unit u, integer id returns integer 
    if id <= ARRAY_SIZE then
        return data(GetUnitIndex(u)).d[id]
    endif
    return 0
endfunction

function SetUnitData takes unit u, integer id, integer value returns nothing 
    if id <= ARRAY_SIZE then
        set data(GetUnitIndex(u)).d[id] = value
    endif
endfunction

endlibrary
02-28-2009, 02:57 AM#5
Vexorian
Quote:
10 is just for testing... I know it's very low but for my testings is enough to play with it.
A bigger values is just plain inviable, also you would need some strange way to reserve the id, or are you doing this so you must manually tweak the id for each system? Not good.

There's a reason they use indexing/gamecache for units this sort of thing doesn't work too well when just using arrays.

You should though take a look at PUI 's textmacro for structs if you really want to add something table-like but keeping the speed.
02-28-2009, 02:57 AM#6
moyack
Oh, I see... I'm just doing my tests to get something as more inlined as possible.

Collapse JASS:
library UnitUtils

globals
    private constant integer MAX_UNIT_ID_COUNT = 408000
    private constant integer ARRAY_SIZE        = 10 // Sets the maximum number of values that a unit can have stored
endglobals

private struct data [MAX_UNIT_ID_COUNT]
    static constant integer MIN_UNIT_ID = 0x100000
    integer id
    integer array d [ARRAY_SIZE]
endstruct

private function U2I takes unit u returns integer
    return u
    return 0
endfunction

function GetUnitIndex takes unit u returns integer 
    debug if U2I(u) - data.MIN_UNIT_ID >= MAX_UNIT_ID_COUNT then
    debug     call BJDebugMsg(SCOPE_PREFIX + ": Unit id too big, increase the MAX_UNIT_ID_COUNT constant or use gamecache instead")
    debug endif
    return U2I(u) - data.MIN_UNIT_ID
endfunction

function GetUnitData takes unit u, integer id returns integer 
    if id <= ARRAY_SIZE then
        return data(GetUnitIndex(u)).d[id]
    endif
    return 0
endfunction

function SetUnitData takes unit u, integer id, integer value returns nothing 
    if id <= ARRAY_SIZE then
        set data(GetUnitIndex(u)).d[id] = value
    endif
endfunction

endlibrary

right now it's overwriting the ids... bad thing :(

I'll work on it tomorrow, I can't keep me awake more time.
02-28-2009, 03:05 AM#7
Vexorian
You know GetUnitIndex won't replace all those indexing stuff? they will have to add [MAX_UNIT_ID_COUNT]
02-28-2009, 03:21 AM#8
Strilanc
If multiple things try to use this at the same time they will trip over each other.
02-28-2009, 03:26 AM#9
Vexorian
You should probably look at this: http://www.wc3c.net/showthread.php?t=101440
02-28-2009, 03:32 AM#10
FriendlyPsycho
In my opinion, I don't think this would be more viable than UnitIndexingUtils/PUI/whatever.

The bigger the size you give "d", the less struct instances will be available. While if you use an indexing library like UnitIndexingUtils or PUI, you can attach stuff to a unit with an infinite amount but it would require you to declare a global array for each data(MYGLOBALARRAY[UNITINDEX]). I'd say that's a good tradeoff.

Just sharing my two cents.
02-28-2009, 03:53 AM#11
moyack
Check this total variation:

Collapse JASS:
library UnitUtils initializer init

globals
    private constant integer ARRAY_SIZE        = 10 // Sets the maximum number of values that a unit can have stored
endglobals

private struct data
    static integer index = 0
    integer array d [ARRAY_SIZE]
    
    static method Set takes unit u returns integer
        local data D = data.allocate()
        call SetUnitUserData(u, integer(D))
        set data.index = data.index + 1
        return data.index
    endmethod
endstruct

function GetUnitIndex takes unit u returns integer 
    if GetUnitUserData(u) < 1 then
        return data.Set(u)
    endif
    return GetUnitUserData(u)
endfunction

function GetUnitData takes unit u, integer id returns integer 
    if id <= ARRAY_SIZE then
        return data(GetUnitIndex(u)).d[id]
    endif
    return 0
endfunction

function SetUnitData takes unit u, integer id, integer value returns nothing 
    if id <= ARRAY_SIZE then
        set data(GetUnitIndex(u)).d[id] = value
    endif
endfunction

private function clean takes nothing returns nothing
    call data(GetUnitIndex(GetTriggerUnit())).destroy()
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddAction(t, function clean)
    set t = null
endfunction

endlibrary

Works perfectly, now each unit can store ARRAY_SIZE values. should I add a custom destroy method to clean the values from the array?
02-28-2009, 04:01 AM#12
Vexorian
Quote:
Works perfectly
Again, You have to manually provide this id thing, and there's a limit of 10, which already is enough ,but the limit of units that can coexist in your map became 8190/ARRAY_SIZE or 800. If we increase the ARRAY_SIZE to a more realistic size like 20, the limit becomes 400 which is already too tight...
02-28-2009, 12:01 PM#13
moyack
Quote:
Originally Posted by me
Works non perfectly
Fixed. (when you wake up and see what you've done sleepy, you can get horrified :P)

Well, it worked with few units, but with 1200 units this code would do funny things :(

One question Vex... if I do this:

Collapse JASS:
globals
    private constant integer ARRAY_SIZE        = 10 // Sets the maximum number of values that a unit can have stored
    private constant integer AMPLIFIER = ARRAY_SIZE * 8190
endglobals

private struct data [AMPLIFIER]
    //...
endstruct
would work?? because as far as I remember, extended arrays are now part of JassHelper, or it's definitely not recommended??
02-28-2009, 12:49 PM#14
akolyt0r
it would slow down the system obviously...
02-28-2009, 01:40 PM#15
moyack
Quote:
Originally Posted by akolyt0r
it would slow down the system obviously...
yes... but enough to prefer Table?