I Need help with attaching a PUI struct

CaptDeath

New Member
Reaction score
103
I just want to know how to attach it


My functions
Azlier told me this to create but i didn't understand it

JASS:
function Lol takes nothing returns nothing
    local Mage m = Mage.create()
    set Mage[whichUnit] = m
    //Blaargh, more actions!
endfunction

is it like this?
someunit being a chosen unit
JASS:
function createIT takes nothing returns nothing
    local Mage m = Mage.create()
    set Mage(someunit) = m
    //am i right or what?
endfunction


My struct
JASS:
struct Mage 
//! runtextmacro PUI()
    string class
    real Exp = 0
    string Loc
    integer Level
    item array Back_Pack[6]
		method create takes nothing returns Mage
			local Mage m = Mage.allocate()
			set m.class = "nill"
			set m.Exp = 0
			set m.Loc = "Home"
			set m.ID = GetId()
			set m.Level = 1
			return m
		endmethod
endstruct


JASS:
//==============================================================================
//  PUI -- Perfect Unit Indexing by Cohadar -- v5.1
//==============================================================================
//
//  PURPOUSE:
//       * Extending UnitUserData()
//       * This is basically perfect hashing algorithm for units
//
//  HOW TO USE:
//       * You have only one function at your disposal GetUnitIndex(unit)
//         It will return a unique index for each unit in range 1..8190
//
//       * What you will do with that index is all up to you
//         Of course using global arrays is the most obvious choice
//         Advanced jassers will think of a couple of more clever ones ofc.
//
//       * There are also 2 textmacros available at the end of library code
//         They can be used for easier attaching to units
//         PUI for structs 
//         PUI_PROPERTY for unit, integer, real, boolean and string variables
//
//  PROS: 
//       * You can use any number of systems that previously could not work together
//         because they all required exclusive access of UnitUserData()
//
//       * You can also use this to attach spell data structs to casters
//
//       * There are no SetUnitIndex() or ClearUnitIndex() functions here
//         Each unit gets assigned one index that cannot be changed
//         That index will be automatically recycled when unit is removed from the game.
//
//  CONS:
//       * This system uses UnitUserData() itself
//         That means that if you want to use PUI you must recode 
//         any other system that uses UnitUserData() to use GetUnitIndex() instead
//
//       * If you use UnitIndex for arrays of non-native types (timers, effects and similar)
//         you must check if timer on that index already exists before you create a new one.
//         This can happen if GetUnitIndex() assigns a recycled index (index of some dead and removed unit)
//         to the newly created unit for which you intended to use timer for
//
//       * All in all this is not a sys for newbies, it gives great power,
//         but it requires knowledge and carefull handling
//
//  DETAILS:
//       * System is using unit array to keep track of all units with an index.
//         Array is periodically checked for removed units,
//         when removed unit is found, index is recycled.
//         Indexes have "decay time" to prevent bugs
//         caused by attaching to "Can't Raise, Does not decay" type units,
//         or by using RemoveUnit() function
//
//  SYSTEM COMMANDS: (debug mode only, red player only)
//
//       * type -pui to display indexes of currently selected units
//       * type -puistats to display some stats
//
//  THANKS TO:
//       * Vexorian - for his help with PUI textmacro
//
//  HOW TO IMPORT:
//       * Just create a trigger named PUI
//       * convert it to text and replace the whole trigger text with this one
//
//==============================================================================


library PUI initializer Init

//==============================================================================
globals    
    //-----------------------------------------------
    private constant real INDEX_DECAY_TIME = 5.  // seconds
    
    //-----------------------------------------------    
    private constant real PERIOD = 0.03125   // 32 fps
        
    //-----------------------------------------------
    private constant integer DECAY_TICKS = R2I(INDEX_DECAY_TIME/PERIOD)
    
    //-----------------------------------------------
    private integer array Indexz
    private unit    array Unitz
    private integer array Decayz
    private integer array Tickz

    private integer maxindex = 0
    private integer topindex = 0
    private integer decayindex = 0
    private integer checker  = 0
    private integer decayer  = 0
    private integer tick = 0
endglobals


//==============================================================================
private function PeriodicRecycler takes nothing returns boolean
    local integer temp
    
    set tick = tick + 1
    
    if topindex > decayindex then
        set checker = checker + 1
        if checker > topindex then
            set checker = decayindex + 1
        endif
        if (GetUnitUserData(Unitz[checker])==0) then
            set decayindex = decayindex + 1
            set Unitz[checker] = Unitz[decayindex]
            
            // swap(checker, decayindex)
            set temp = Indexz[checker]
            set Indexz[checker] = Indexz[decayindex]
            set Indexz[decayindex] = temp
            
            set Decayz[decayindex] = DECAY_TICKS
            set Tickz[decayindex] = tick
        endif
    endif

    if decayindex > 0 then
        set decayer = decayer + 1
        if decayer > decayindex then
            set decayer = 1
        endif
        set Decayz[decayer] = Decayz[decayer] - (tick-Tickz[decayer])
        if Decayz[decayer] > 0 then
            set Tickz[decayer] = tick
        else
            // swap(decayer, decayindex)
            set temp = Indexz[decayer]
            set Indexz[decayer] = Indexz[decayindex]
            set Indexz[decayindex] = temp
            
            set Unitz[decayindex] = Unitz[topindex]
            
            // swap(decayindex, topindex)
            set temp = Indexz[decayindex]
            set Indexz[decayindex] = Indexz[topindex]
            set Indexz[topindex] = temp
            
            set decayindex = decayindex - 1
            set topindex = topindex - 1
        endif    
    endif
    
    return false
endfunction

//==============================================================================
//  Main and only function exported by this library
//==============================================================================
function GetUnitIndex takes unit whichUnit returns integer
    local integer index
    
    debug if whichUnit == null then
    debug   call BJDebugMsg("|c00FF0000ERROR: PUI - Index requested for null unit")
    debug   return 0
    debug endif
    
    set index = GetUnitUserData(whichUnit)

    if index == 0 then
        set topindex = topindex + 1
        if topindex > maxindex then
            set maxindex = topindex
            set Indexz[topindex] = topindex
        endif
        set index = Indexz[topindex]
        set Unitz[topindex] = whichUnit
       
        call SetUnitUserData(whichUnit, index)
        set index = GetUnitUserData(whichUnit)
       
        // this happens when requesting unit index for removed unit
        debug if index == 0 then
        debug     call BJDebugMsg("|c00FFCC00WARNING: PUI - Bad unit handle")
        debug endif
        
        //debug call BJDebugMsg("|c00FFCC00PUI: Index assigned #" + I2S(index))
    endif
    
    return index
endfunction

//==============================================================================
private function DisplayStats takes nothing returns nothing
    call BJDebugMsg("=============================================")    
    call BJDebugMsg("Biggest index ever = " + I2S(maxindex))    
    call BJDebugMsg("Indexes in use = " + I2S(topindex-decayindex))
    call BJDebugMsg("Decaying indexes = " + I2S(decayindex))
    call BJDebugMsg("Released indexes = " + I2S(maxindex-topindex))
    call BJDebugMsg("=============================================")    
endfunction

//===========================================================================
private function DisplaySelectedEnum takes nothing returns nothing
    call BJDebugMsg( "PUI(" + ( GetUnitName(GetEnumUnit()) + ( ") = " + I2S(GetUnitUserData(GetEnumUnit())) ) ) )
endfunction

//===========================================================================
private function DisplaySelected takes nothing returns nothing
    local group g = CreateGroup()
    call SyncSelections()
    call GroupEnumUnitsSelected(g, Player(0), null)
    call ForGroup(g, function DisplaySelectedEnum)
    call DestroyGroup(g)
    set  g = null
endfunction

//==============================================================================
private function Init takes nothing returns nothing
    local trigger trig 
    
    set trig = CreateTrigger()
    call TriggerRegisterTimerEvent( trig, PERIOD, true )
    call TriggerAddCondition( trig, Condition(function PeriodicRecycler) )

    debug set trig = CreateTrigger()
    debug call TriggerRegisterPlayerChatEvent( trig, Player(0), "-pui", true )
    debug call TriggerAddAction( trig, function DisplaySelected )      
    
    debug set trig = CreateTrigger()
    debug call TriggerRegisterPlayerChatEvent( trig, Player(0), "-puistats", true )
    debug call TriggerAddAction( trig, function DisplayStats )
endfunction

endlibrary


//===========================================================================
//  Allowed PUI_PROPERTY TYPES are: unit, integer, real, boolean, string
//  Do NOT put handles that need to be destroyed here (timer, trigger, ...)
//  Instead put them in a struct and use PUI textmacro
//===========================================================================
//! textmacro PUI_PROPERTY takes VISIBILITY, TYPE, NAME, DEFAULT
$VISIBILITY$ struct $NAME$
    private static unit   array pui_unit
    private static $TYPE$ array pui_data
    
    //-----------------------------------------------------------------------
    //  Returns default value when first time used
    //-----------------------------------------------------------------------
    static method operator[] takes unit whichUnit returns $TYPE$
        local integer pui = GetUnitIndex(whichUnit)
        if .pui_unit[pui] != whichUnit then
            set .pui_unit[pui] = whichUnit
            set .pui_data[pui] = $DEFAULT$
        endif
        return .pui_data[pui]
    endmethod
    
    //-----------------------------------------------------------------------
    static method operator[]= takes unit whichUnit, $TYPE$ whichData returns nothing
        local integer pui = GetUnitIndex(whichUnit)
        set .pui_unit[pui] = whichUnit
        set .pui_data[pui] = whichData
    endmethod
endstruct
//! endtextmacro

//===========================================================================
//  Never destroy PUI structs directly.
//  Use .release() instead, will call .destroy()
//===========================================================================
//! textmacro PUI
    private static unit    array pui_unit
    private static integer array pui_data
    private static integer array pui_id
    
    //-----------------------------------------------------------------------
    //  Returns zero if no struct is attached to unit
    //-----------------------------------------------------------------------
    static method operator[] takes unit whichUnit returns integer
        local integer pui = GetUnitIndex(whichUnit)
        if .pui_data[pui] != 0 then
            if .pui_unit[pui] != whichUnit then
                // recycled handle detected
                call .destroy(.pui_data[pui])
                set .pui_unit[pui] = null
                set .pui_data[pui] = 0            
            endif
        endif
        return .pui_data[pui]
    endmethod
    
    //-----------------------------------------------------------------------
    //  This will overwrite already attached struct if any
    //-----------------------------------------------------------------------
    static method operator[]= takes unit whichUnit, integer whichData returns nothing
        local integer pui = GetUnitIndex(whichUnit)
        if .pui_data[pui] != 0 then
            call .destroy(.pui_data[pui])
        endif
        set .pui_unit[pui] = whichUnit
        set .pui_data[pui] = whichData
        set .pui_id[whichData] = pui
    endmethod

    //-----------------------------------------------------------------------
    //  If you do not call release struct will be destroyed when unit handle gets recycled
    //-----------------------------------------------------------------------
    method release takes nothing returns nothing
        local integer pui= .pui_id[integer(this)]
        call .destroy()
        set .pui_unit[pui] = null
        set .pui_data[pui] = 0
    endmethod
//! endtextmacro
 

Romek

Super Moderator
Reaction score
963
The first is correct.
Again.. How about testing it yourself? =|

How can you 'not understand' that?

Edit: The second would be used for typecasting. So assuming someunit is an integer (I hope not), then it's fine. Else, it isn't.
Then again, you wouldn't be able to use 'set' in that way if you were typecasting.
 

Tom Jones

N/A
Reaction score
437
I would like to point out that when you post system question, you should also post the system, as I'm not familiar with the above system and can't be bothered looking up the system to see how it works. I'm sure other members feel the same way.
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
PUI adds operators to the struct, so that you can use a unit as an array index. In reality, the system is actually looking up the unit's user data, making sure information is correct about the unit, and using the unit's user data as the array index.

The first one is correct, so I hope I explained why it works that way.
 

CaptDeath

New Member
Reaction score
103
@romek cause this way debuging tkaes all of 5 secs instead of 45(opening and closeing wc3 and testing in game)

@tomjones Posted PUI

@darthfett so something like?
so how do i "target" a unit with the first one?
JASS:
function Lol takes nothing returns nothing
    local Mage m = Mage.create()
    set Mage[whichUnit] = m
    //Blaargh, more actions!
endfunction
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
@darthfett so something like?
so how do i "target" a unit with the first one?
JASS:
function Lol takes nothing returns nothing
    local Mage m = Mage.create()
    set Mage[whichUnit] = m
    //Blaargh, more actions!
endfunction

Yes, this code is correct to attach the struct to the unit. What exactly are trying to 'target' and for what purpose?
 

CaptDeath

New Member
Reaction score
103
the unit that will recieve the data in the stuct the "target"
cause this will be applied to serveral heros and the data will be modified on certain events

so how do i "target" a unit?
 

Romek

Super Moderator
Reaction score
963
> romek cause this way debuging tkaes all of 5 secs instead of 45(opening and closeing wc3 and testing in game)
No it doesn't. The latter takes like 45 seconds nomatter what.
'This way' takes over a minute. Writing the post takes about 0.01 seconds. (I assume you just mash the keyboard and get lucky). But the replies take over a minute. We have to notice the thread, then read it, then reply.
 

CaptDeath

New Member
Reaction score
103
first off i don't mash the keyboard :(
second of all this way i can multitask
third why do you even reply when it seems to me that you just want to argue with me?
 

Azlier

Old World Ghost
Reaction score
461
Hmm. I assumed you could figure out the rest yourself.

First, figure out which unit you want to 'target'. I assume you are spawning a mage at some point.

JASS:
local unit u = CreateUnit(...blah blah...)//This is your mage.
local Mage m = Mage.create()//This is your struct.
set Mage<u> = m //The struct is now attached.</u>


To retrieve...
JASS:
//Get your mage. I&#039;m assuming it&#039;s Triggering Unit here.
local unit u = GetTriggerUnit()
local Mage m = Mage[GetUnitIndex(u)]
//Simple enough?
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Hmm. I assumed you could figure out the rest yourself.

First, figure out which unit you want to 'target'. I assume you are spawning a mage at some point.

JASS:
local unit u = CreateUnit(...blah blah...)//This is your mage.
local Mage m = Mage.create()//This is your struct.
set Mage<u> = m //The struct is now attached.</u>


To retrieve...
JASS:
//Get your mage. I&#039;m assuming it&#039;s Triggering Unit here.
local unit u = GetTriggerUnit()
local Mage m = Mage[GetUnitIndex(u)]
//Simple enough?


Actually, PUI's BJ-like operator function does have a purpose, and doesn't only return the unit's index. So the 'get' function would be like this:

JASS:
//Get your mage. I&#039;m assuming it&#039;s Triggering Unit here.
local unit u = GetTriggerUnit()
local Mage m = Mage<u>
//Simple enough?</u>


@romek cause this way debuging tkaes all of 5 secs instead of 45(opening and closeing wc3 and testing in game)

You are incorrect, as it means that you are wasting other peoples time as well as your own. Instead of saving and running a quick test, it means we have to decipher your question, and answer it. From the post times, it looks as if its taken a full 5 hours rather than the minute it would have taken you to test it, or the 15 minutes it would have taken you to read the PUI Tutorial. We're not fighting with you, we're simply trying to teach you a better method to get your answers.

If you had tried it, and THEN it hadn't worked, you could have posted the question with a "this isn't working" rather than a "I dunno if this will work". The second question requires people to try to figure out what exactly you're trying to do (since they assume your question is asking for something more complicated than that), while the first only requires debugging.
 

Azlier

Old World Ghost
Reaction score
461
Huh. I supplied an integer to the [] operator? Oops. Wasn't thinking clearly.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top