• 🏆 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!

[Snippet] RegisterEvent pack

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
A non-trigger registering for native event types.
Instead of creating multiple small threads I've decided to upload this as a pack. This resource is also available on github.

Back in time when Maggy released RPUE I've written few additional, small snippets to provide similar functionality for other, main native event types. Main event types include: playerunitevent, playerevent, unitevent and gameevent.

Still, after all those years RPUE could use an update, mainly because of awkward unsychronized trigger handles for "any" and "target (player)" cases. Whatmore, you can not retrieve trigger handle which was created for specific player and it creates unnesseccary amount of triggers instead of sticking to rule: one trigger per event per player/index.

Thats why, before implementing other "RegisterEvents" I've created small lib to solve mentioned issues. Notice that there is only one unique trigger array instead of one per event type.

RegisterNativeEvent:
JASS:
/*****************************************************************************
*
*    RegisterNativeEvent v1.1.1.5
*       by Bannar
*
*    Storage of trigger handles for native events.
*
******************************************************************************
*
*    Optional requirements:
*
*       Table by Bribe
*          hiveworkshop.com/threads/snippet-new-table.188084/
*
******************************************************************************
*
*    Important:
*
*       Avoid using TriggerSleepAction within functions registered.
*       Destroy native event trigger on your own responsibility.
*
******************************************************************************
*
*    Core:
*
*       function IsNativeEventRegistered takes integer whichIndex, integer whichEvent returns boolean
*          Whether index whichIndex has already been attached to event whichEvent.
*
*       function RegisterNativeEventTrigger takes integer whichIndex, integer eventId returns boolean
*          Registers whichIndex within whichEvent scope and assigns new trigger handle for it.
*
*       function GetIndexNativeEventTrigger takes integer whichIndex, integer whichEvent returns trigger
*          Retrieves trigger handle for event whichEvent specific to provided index whichIndex.
*
*       function GetNativeEventTrigger takes integer whichEvent returns trigger
*          Retrieves trigger handle for event whichEvent.
*
*
*    Custom events:
*
*       function CreateNativeEvent takes nothing returns integer
*          Returns unique id for new event and registers it with RegisterNativeEvent.
*
*       function RegisterIndexNativeEvent takes integer whichIndex, integer whichEvent, code func returns triggercondition
*          Registers new event handler func for event whichEvent specific to index whichIndex.
*
*       function RegisterNativeEvent takes integer whichEvent, code func returns triggercondition
*          Registers new event handler func for specified event whichEvent.
*
*       function UnregisterNativeEventHandler takes integer whichEvent, triggercondition handler returns nothing
*          Unregisters specified event handler for event whichEvent. Requires Warcraft 1.30.4+.
*
*****************************************************************************/
library RegisterNativeEvent uses optional Table

globals
    private integer eventIndex = 500 // 0-499 reserved for Blizzard native events
endglobals

private module NativeEventInit
    private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
        set table = TableArray[0x2000]
endif
    endmethod
endmodule

private struct NativeEvent extends array
static if LIBRARY_Table then
    static TableArray table
else
    static hashtable table = InitHashtable()
endif
    implement NativeEventInit
endstruct

function IsNativeEventRegistered takes integer whichIndex, integer whichEvent returns boolean
static if LIBRARY_Table then
    return NativeEvent.table[whichEvent].trigger.has(whichIndex)
else
    return HaveSavedHandle(NativeEvent.table, whichEvent, whichIndex)
endif
endfunction

function RegisterNativeEventTrigger takes integer whichIndex, integer whichEvent returns boolean
    if not IsNativeEventRegistered(whichIndex, whichEvent) then
static if LIBRARY_Table then
        set NativeEvent.table[whichEvent].trigger[whichIndex] = CreateTrigger()
else
        call SaveTriggerHandle(NativeEvent.table, whichEvent, whichIndex, CreateTrigger())
endif
        return true
    endif
    return false
endfunction

function GetIndexNativeEventTrigger takes integer whichIndex, integer whichEvent returns trigger
static if LIBRARY_Table then
    return NativeEvent.table[whichEvent].trigger[whichIndex]
else
    return LoadTriggerHandle(NativeEvent.table, whichEvent, whichIndex)
endif
endfunction

function GetNativeEventTrigger takes integer whichEvent returns trigger
    return GetIndexNativeEventTrigger(bj_MAX_PLAYER_SLOTS, whichEvent)
endfunction

function CreateNativeEvent takes nothing returns integer
    local integer eventId = eventIndex
    call RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId)
    set eventIndex = eventIndex + 1
    return eventId
endfunction

function RegisterIndexNativeEvent takes integer whichIndex, integer whichEvent, code func returns triggercondition
    call RegisterNativeEventTrigger(whichIndex, whichEvent)
    return TriggerAddCondition(GetIndexNativeEventTrigger(whichIndex, whichEvent), Condition(func))
endfunction

function RegisterNativeEvent takes integer whichEvent, code func returns triggercondition
    return RegisterIndexNativeEvent(bj_MAX_PLAYER_SLOTS, whichEvent, func)
endfunction

function UnregisterNativeEventHandler takes integer whichEvent, triggercondition handler returns nothing
    call TriggerRemoveCondition(GetNativeEventTrigger(whichEvent), handler)
endfunction

endlibrary

And now, the functionality for player, game, unit and playerunit native event types.

RegisterPlayerUnitEvent:
JASS:
/*****************************************************************************
*
*    RegisterPlayerUnitEvent v1.0.3.2
*       by Bannar
*
*    Register version of TriggerRegisterPlayerUnitEvent.
*
*    Special thanks to Magtheridon96, Bribe, azlier and BBQ for the original library version.
*
******************************************************************************
*
*    Requirements:
*
*       RegisterNativeEvent by Bannar
*          hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*
******************************************************************************
*
*    Functions:
*
*       function GetAnyPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
*          Retrieves trigger handle for playerunitevent whichEvent.
*
*       function GetPlayerUnitEventTrigger takes player whichPlayer, playerunitevent whichEvent returns trigger
*          Retrieves trigger handle for playerunitevent whichEvent specific to player whichPlayer.
*
*       function RegisterAnyPlayerUnitEvent takes playerunitevent whichEvent, code func returns nothing
*          Registers generic playerunitevent whichEvent adding code func as callback.
*
*       function RegisterPlayerUnitEvent takes player whichPlayer, playerunitevent whichEvent, code func returns nothing
*          Registers playerunitevent whichEvent for player whichPlayer adding code func as callback.
*
*****************************************************************************/
library RegisterPlayerUnitEvent requires RegisterNativeEvent

function GetAnyPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
    return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction

function GetPlayerUnitEventTrigger takes player whichPlayer, playerunitevent whichEvent returns trigger
    return GetIndexNativeEventTrigger(GetPlayerId(whichPlayer), GetHandleId(whichEvent))
endfunction

function RegisterAnyPlayerUnitEvent takes playerunitevent whichEvent, code func returns nothing
    local integer eventId = GetHandleId(whichEvent)
    local integer index = 0
    local trigger t = null

    if RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId) then
        set t = GetNativeEventTrigger(eventId)
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(index), whichEvent, null)
            set index = index + 1
            exitwhen index == bj_MAX_PLAYER_SLOTS
        endloop
        set t = null
    endif

    call RegisterNativeEvent(eventId, func)
endfunction

function RegisterPlayerUnitEvent takes player whichPlayer, playerunitevent whichEvent, code func returns nothing
    local integer playerId = GetPlayerId(whichPlayer)
    local integer eventId = GetHandleId(whichEvent)

    if RegisterNativeEventTrigger(playerId, eventId) then
        call TriggerRegisterPlayerUnitEvent(GetIndexNativeEventTrigger(playerId, eventId), whichPlayer, whichEvent, null)
    endif

    call RegisterIndexNativeEvent(playerId, eventId, func)
endfunction

endlibrary

JASS:
/*****************************************************************************
*
*    RegisterPlayerEvent v1.0.2.2
*       by Bannar
*
*    Register version of TriggerRegisterPlayerEvent.
*
******************************************************************************
*
*    Requirements:
*
*       RegisterNativeEvent by Bannar
*          hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*
******************************************************************************
*
*    Functions:
*
*       function GetAnyPlayerEventTrigger takes playerevent whichEvent returns trigger
*          Retrieves trigger handle for playerevent whichEvent.
*
*       function GetPlayerEventTrigger takes player whichPlayer, playerevent whichEvent returns trigger
*          Retrieves trigger handle for playerevent whichEvent specific to player whichPlayer.
*
*       function RegisterAnyPlayerEvent takes playerevent whichEvent, code func returns nothing
*          Registers generic playerevent whichEvent adding code func as callback.
*
*       function RegisterPlayerEvent takes player whichPlayer, playerevent whichEvent, code func returns nothing
*          Registers playerevent whichEvent for player whichPlayer adding code func as callback.
*
*****************************************************************************/
library RegisterPlayerEvent requires RegisterNativeEvent

function GetAnyPlayerEventTrigger takes playerevent whichEvent returns trigger
    return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction

function GetPlayerEventTrigger takes player whichPlayer, playerevent whichEvent returns trigger
    return GetIndexNativeEventTrigger(GetPlayerId(whichPlayer), GetHandleId(whichEvent))
endfunction

function RegisterAnyPlayerEvent takes playerevent whichEvent, code func returns nothing
    local integer eventId = GetHandleId(whichEvent)
    local integer index = 0
    local trigger t = null

    if RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId) then
        set t = GetNativeEventTrigger(eventId)
        loop
            call TriggerRegisterPlayerEvent(t, Player(index), whichEvent)
            set index = index + 1
            exitwhen index == bj_MAX_PLAYER_SLOTS
        endloop
        set t = null
    endif

    call RegisterNativeEvent(eventId, func)
endfunction

function RegisterPlayerEvent takes player whichPlayer, playerevent whichEvent, code func returns nothing
    local integer playerId = GetPlayerId(whichPlayer)
    local integer eventId = GetHandleId(whichEvent)

    if RegisterNativeEventTrigger(playerId, eventId) then
        call TriggerRegisterPlayerEvent(GetIndexNativeEventTrigger(playerId, eventId), whichPlayer, whichEvent)
    endif

    call RegisterIndexNativeEvent(playerId, eventId, func)
endfunction

endlibrary

JASS:
/*****************************************************************************
*
*    RegisterGameEvent v1.0.0.6
*       by Bannar
*
*    Register version of TriggerRegisterGameEvent.
*
******************************************************************************
*
*    Requirements:
*
*       RegisterNativeEvent by Bannar
*          hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*
******************************************************************************
*
*    Functions:
*
*       function GetGameEventTrigger takes gameevent whichEvent returns trigger
*          Retrieves trigger handle for gameevent whichEvent.
*
*       function RegisterGameEvent takes gameevent whichEvent, code func returns nothing
*          Registers generic gameevent whichEvent adding code func as callback.
*
*****************************************************************************/
library RegisterGameEvent requires RegisterNativeEvent

function GetGameEventTrigger takes gameevent whichEvent returns trigger
    return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction

function RegisterGameEvent takes gameevent whichEvent, code func returns nothing
    local integer eventId = GetHandleId(whichEvent)

    if RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId) then
        call TriggerRegisterGameEvent(GetNativeEventTrigger(eventId), whichEvent)
    endif

    call RegisterNativeEvent(eventId, func)
endfunction

endlibrary

JASS:
/*****************************************************************************
*
*    RegisterUnitEvent v1.0.1.2
*       by Bannar
*
*    Register version of TriggerRegisterUnitEvent.
*
******************************************************************************
*
*    Requirements:
*
*       RegisterNativeEvent by Bannar
*          hiveworkshop.com/threads/snippet-registerevent-pack.250266/
*
******************************************************************************
*
*    Functions:
*
*       function GetUnitEventTrigger takes unitevent whichEvent returns trigger
*          Retrieves trigger handle for unitevent whichEvent.
*
*       function RegisterUnitEvent takes unit whichUnit, unitevent whichEvent, code func returns nothing
*          Registers unitevent whichEvent for unit whichUnit adding code func as callback.
*
*****************************************************************************/
library RegisterUnitEvent requires RegisterNativeEvent

function GetUnitEventTrigger takes unitevent whichEvent returns trigger
    return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction

function RegisterUnitEvent takes unit whichUnit, unitevent whichEvent, code func returns nothing
    local integer unitId = GetHandleId(whichUnit)
    local integer eventId = GetHandleId(whichEvent)

    if RegisterNativeEventTrigger(unitId, eventId) then
        call TriggerRegisterUnitEvent(GetIndexNativeEventTrigger(unitId, eventId), whichUnit, whichEvent)
    endif

    call RegisterIndexNativeEvent(unitId, eventId, func)
endfunction

endlibrary
Reference event-id values for RegisterNativeEvent:
JASS:
globals
    /**
     *  For use with RegisterGameEvent
     */
    constant integer gameevent_VICTORY         = 0
    constant integer gameevent_END_LEVEL       = 1
    constant integer gameevent_VARIABLE_LIMIT  = 2
    constant integer gameevent_STATE_LIMIT     = 3
    constant integer gameevent_TIMER_EXPIRED   = 4
    constant integer gameevent_ENTER_REGION    = 5
    constant integer gameevent_LEAVE_REGION    = 6
    constant integer gameevent_TRACKABLE_HIT   = 7
    constant integer gameevent_TRACKABLE_TRACK = 8
    constant integer gameevent_SHOW_SKILL      = 9
    constant integer gameevent_BUILD_SUBMENU   = 10
    /**
     *  For use with RegisterPlayerEvent
     */
    constant integer playerevent_STATE_LIMIT      = 11
    constant integer playerevent_ALLIANCE_CHANGED = 12
    constant integer playerevent_DEFEAT           = 13
    constant integer playerevent_VICTORY          = 14
    constant integer playerevent_LEAVE            = 15
    constant integer playerevent_CHAT             = 16
    constant integer playerevent_END_CINEMATIC    = 17
    /**
     *  For use with RegisterPlayerUnitEvent
     */
    constant integer playerunitevent_ATTACKED            = 18
    constant integer playerunitevent_RESCUED             = 19
    constant integer playerunitevent_DEATH               = 20
    constant integer playerunitevent_DECAY               = 21
    constant integer playerunitevent_DETECTED            = 22
    constant integer playerunitevent_HIDDEN              = 23
    constant integer playerunitevent_SELECTED            = 24
    constant integer playerunitevent_DESELECTED          = 25
    constant integer playerunitevent_CONSTRUCT_START     = 26
    constant integer playerunitevent_CONSTRUCT_CANCEL    = 27
    constant integer playerunitevent_CONSTRUCT_FINISH    = 28
    constant integer playerunitevent_UPGRADE_START       = 29
    constant integer playerunitevent_UPGRADE_CANCEL      = 30
    constant integer playerunitevent_UPGRADE_FINISH      = 31
    constant integer playerunitevent_TRAIN_START         = 32
    constant integer playerunitevent_TRAIN_CANCEL        = 33
    constant integer playerunitevent_TRAIN_FINISH        = 34
    constant integer playerunitevent_RESEARCH_START      = 35
    constant integer playerunitevent_RESEARCH_CANCEL     = 36
    constant integer playerunitevent_RESEARCH_FINISH     = 37
    constant integer playerunitevent_ISSUED_ORDER        = 38
    constant integer playerunitevent_ISSUED_POINT_ORDER  = 39
    constant integer playerunitevent_ISSUED_TARGET_ORDER = 40
    constant integer playerunitevent_ISSUED_UNIT_ORDER   = 40 // for compat
    constant integer playerunitevent_HERO_LEVEL          = 41
    constant integer playerunitevent_HERO_SKILL          = 42
    constant integer playerunitevent_HERO_REVIVABLE      = 43
    constant integer playerunitevent_HERO_REVIVE_START   = 44
    constant integer playerunitevent_HERO_REVIVE_CANCEL  = 45
    constant integer playerunitevent_HERO_REVIVE_FINISH  = 46
    constant integer playerunitevent_SUMMON              = 47
    constant integer playerunitevent_DROP_ITEM           = 48
    constant integer playerunitevent_PICKUP_ITEM         = 49
    constant integer playerunitevent_USE_ITEM            = 50
    constant integer playerunitevent_LOADED              = 51
    /**
     *  For use with RegisterUnitEvent
     */
    constant integer unitevent_DAMAGED             = 52
    constant integer unitevent_DEATH               = 53
    constant integer unitevent_DECAY               = 54
    constant integer unitevent_DETECTED            = 55
    constant integer unitevent_HIDDEN              = 56
    constant integer unitevent_SELECTED            = 57
    constant integer unitevent_DESELECTED          = 58
    constant integer unitevent_STATE_LIMIT         = 59
    constant integer unitevent_ACQUIRED_TARGET     = 60
    constant integer unitevent_TARGET_IN_RANGE     = 61
    constant integer unitevent_ATTACKED            = 62
    constant integer unitevent_RESCUED             = 63
    constant integer unitevent_CONSTRUCT_CANCEL    = 64
    constant integer unitevent_CONSTRUCT_FINISH    = 65
    constant integer unitevent_UPGRADE_START       = 66
    constant integer unitevent_UPGRADE_CANCEL      = 67
    constant integer unitevent_UPGRADE_FINISH      = 68
    constant integer unitevent_TRAIN_START         = 69
    constant integer unitevent_TRAIN_CANCEL        = 70
    constant integer unitevent_TRAIN_FINISH        = 71
    constant integer unitevent_RESEARCH_START      = 72
    constant integer unitevent_RESEARCH_CANCEL     = 73
    constant integer unitevent_RESEARCH_FINISH     = 74
    constant integer unitevent_ISSUED_ORDER        = 75
    constant integer unitevent_ISSUED_POINT_ORDER  = 76
    constant integer unitevent_ISSUED_TARGET_ORDER = 77
    constant integer unitevent_HERO_LEVEL          = 78
    constant integer unitevent_HERO_SKILL          = 79
    constant integer unitevent_HERO_REVIVABLE      = 80
    constant integer unitevent_HERO_REVIVE_START   = 81
    constant integer unitevent_HERO_REVIVE_CANCEL  = 82
    constant integer unitevent_HERO_REVIVE_FINISH  = 83
    constant integer unitevent_SUMMON              = 84
    constant integer unitevent_DROP_ITEM           = 85
    constant integer unitevent_PICKUP_ITEM         = 86
    constant integer unitevent_USE_ITEM            = 87
    constant integer unitevent_LOADED              = 88
    /**
     *  For use with RegisterGameEvent
     */
    constant integer gameevent_LOADED                 = 256
    constant integer gameevent_TOURNAMENT_FINISH_SOON = 257
    constant integer gameevent_TOURNAMENT_FINISH_NOW  = 258
    constant integer gameevent_SAVE                   = 259
    /**
     *  For use with RegisterPlayerEvent
     */
    constant integer playerevent_ARROW_LEFT_DOWN  = 261
    constant integer playerevent_ARROW_LEFT_UP    = 262
    constant integer playerevent_ARROW_RIGHT_DOWN = 263
    constant integer playerevent_ARROW_RIGHT_UP   = 264
    constant integer playerevent_ARROW_DOWN_DOWN  = 265
    constant integer playerevent_ARROW_DOWN_UP    = 266
    constant integer playerevent_ARROW_UP_DOWN    = 267
    constant integer playerevent_ARROW_UP_UP      = 268
    constant integer playerevent_MOUSE_DOWN       = 269
    constant integer playerevent_MOUSE_UP         = 270
    constant integer playerevent_MOUSE_MOVE       = 271
    /**
     * For use with RegisterPlayerUnitEvent
     */
    constant integer playerunitevent_SELL          = 272
    constant integer playerunitevent_CHANGE_OWNER  = 273
    constant integer playerunitevent_SELL_ITEM     = 274
    constant integer playerunitevent_SPELL_CHANNEL = 275
    constant integer playerunitevent_SPELL_CAST    = 276
    constant integer playerunitevent_SPELL_EFFECT  = 277
    constant integer playerunitevent_SPELL_FINISH  = 278
    constant integer playerunitevent_SPELL_ENDCAST = 279
    constant integer playerunitevent_PAWN_ITEM     = 280
    /**
     *  For use with RegisterUnitEvent
     */
    constant integer unitevent_SELL          = 289
    constant integer unitevent_CHANGE_OWNER  = 290
    constant integer unitevent_SELL_ITEM     = 291
    constant integer unitevent_SPELL_CHANNEL = 292
    constant integer unitevent_SPELL_CAST    = 293
    constant integer unitevent_SPELL_EFFECT  = 294
    constant integer unitevent_SPELL_FINISH  = 295
    constant integer unitevent_SPELL_ENDCAST = 296
    constant integer unitevent_PAWN_ITEM     = 297
endglobals

RegisterPlayerUnitEvent:
JASS:
/*****************************************************************************
*
*    RegisterPlayerUnitEvent v1.0.2.1
*       by Bannar
*
*    Register version of TriggerRegisterPlayerUnitEvent.
*
*    Special thanks to Magtheridon96, Bribe, azlier and BBQ for the original library version.
*
******************************************************************************
*
*    Requirements:
*
*       RegisterNativeEvent by Bannar
*          hiveworkshop.com/forums/submissions-414/snippet-registerevent-pack-250266/
*
******************************************************************************
*
*    constant boolean RPUE_VERSION_NEW
*       Defines API style. Choose between compatibility with standard RPUE or Blizzard alike interface
*
*
*    Functions:
*
*       function Register(Any)PlayerUnitEvent takes playerunitevent whichEvent, code cb returns nothing
*          registers generic playerunitevent whichEvent adding code cb as callback
*
*       function RegisterPlayerUnitEvent(ForPlayer) takes player whichPlayer, playerunitevent whichEvent, code cb returns nothing
*          registers playerunitevent whichEvent for player whichPlayer adding code cb as callback
*
*       function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
*          retrieves trigger handle for playerunitevent whichEvent
*
*       function GetPlayerUnitEventTriggerForPlayer takes player whichPlayer, playerunitevent whichEvent returns trigger
*          retrieves trigger handle for playerunitevent whichEvent specific to player whichPlayer
*
*****************************************************************************/
library RegisterPlayerUnitEvent requires RegisterNativeEvent

globals
    constant boolean RPUE_VERSION_NEW = false
endglobals

//! textmacro_once DEFINE_REGISTER_PLAYER_UNIT_EVENT takes GENERIC, SPECIFIC
function Register$GENERIC$PlayerUnitEvent takes playerunitevent whichEvent, code cb returns nothing
    local integer eventId = GetHandleId(whichEvent)
    local integer index = 0
    local trigger t = null

    if RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId) then
        set t = GetNativeEventTrigger(eventId)
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(index), whichEvent, null)
            set index = index + 1
            exitwhen index == bj_MAX_PLAYER_SLOTS
        endloop
        set t = null
    endif

    call TriggerAddCondition(GetNativeEventTrigger(eventId), Condition(cb))
endfunction

function RegisterPlayerUnitEvent$SPECIFIC$ returns nothing
    local integer playerId = GetPlayerId(whichPlayer)
    local integer eventId = GetHandleId(whichEvent)

    if RegisterNativeEventTrigger(playerId, eventId) then
        call TriggerRegisterPlayerUnitEvent(GetIndexNativeEventTrigger(playerId, eventId), whichPlayer, whichEvent, null)
    endif

    call TriggerAddCondition(GetIndexNativeEventTrigger(playerId, eventId), Condition(cb))
endfunction
//! endtextmacro

static if RPUE_VERSION_NEW then
    //! runtextmacro DEFINE_REGISTER_PLAYER_UNIT_EVENT("Any", " takes player whichPlayer, playerunitevent whichEvent, code cb")
else
    //! runtextmacro DEFINE_REGISTER_PLAYER_UNIT_EVENT("", "ForPlayer takes playerunitevent whichEvent, code cb, player whichPlayer")
endif

function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
    return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction

function GetPlayerUnitEventTriggerForPlayer takes player whichPlayer, playerunitevent whichEvent returns trigger
    return GetIndexNativeEventTrigger(GetPlayerId(whichPlayer), GetHandleId(whichEvent))
endfunction

endlibrary
RegisterPlayerEvent:
JASS:
/*****************************************************************************
*
*    RegisterPlayerEvent v1.0.1.1
*       by Bannar
*
*    Register version of TriggerRegisterPlayerEvent.
*
******************************************************************************
*
*    Requirements:
*
*       RegisterNativeEvent by Bannar
*          hiveworkshop.com/forums/submissions-414/snippet-registerevent-pack-250266/
*
******************************************************************************
*
*    Functions:
*
*       function RegisterAnyPlayerEvent takes playerevent whichEvent, code cb returns nothing
*          registers generic playerevent whichEvent adding code cb as callback
*
*       function RegisterPlayerEvent takes player whichPlayer, playerevent whichEvent, code cb returns nothing
*          registers playerevent whichEvent for player whichPlayer adding code cb as callback
*
*       function GetPlayerEventTrigger takes playerevent whichEvent returns trigger
*          retrieves trigger handle for playerevent whichEvent
*
*       function GetPlayerEventTriggerForPlayer takes player whichPlayer, playerevent whichEvent returns trigger
*          retrieves trigger handle for playerevent whichEvent specific to player whichPlayer
*
*****************************************************************************/
library RegisterPlayerEvent requires RegisterNativeEvent

function RegisterAnyPlayerEvent takes playerevent whichEvent, code cb returns nothing
    local integer eventId = GetHandleId(whichEvent)
    local integer index = 0
    local trigger t = null

    if RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId) then
        set t = GetNativeEventTrigger(eventId)
        loop
            call TriggerRegisterPlayerEvent(t, Player(index), whichEvent)
            set index = index + 1
            exitwhen index == bj_MAX_PLAYER_SLOTS
        endloop
        set t = null
    endif

    call TriggerAddCondition(GetNativeEventTrigger(eventId), Condition(cb))
endfunction

function RegisterPlayerEvent takes player whichPlayer, playerevent whichEvent, code cb returns nothing
    local integer playerId = GetPlayerId(whichPlayer)
    local integer eventId = GetHandleId(whichEvent)

    if RegisterNativeEventTrigger(playerId, eventId) then
        call TriggerRegisterPlayerEvent(GetIndexNativeEventTrigger(playerId, eventId), whichPlayer, whichEvent)
    endif

    call TriggerAddCondition(GetIndexNativeEventTrigger(playerId, eventId), Condition(cb))
endfunction

function GetPlayerEventTrigger takes playerevent whichEvent returns trigger
    return GetNativeEventTrigger(GetHandleId(whichEvent))
endfunction

function GetPlayerEventTriggerForPlayer takes player whichPlayer, playerevent whichEvent returns trigger
    return GetIndexNativeEventTrigger(GetPlayerId(whichPlayer), GetHandleId(whichEvent))
endfunction

endlibrary
 
Last edited:
Seems like a cool idea. Atm there are some issues. Try this code out:
JASS:
library A initializer Init requires RegisterPlayerEvent
    private function OnEsc takes nothing returns boolean
        call BJDebugMsg("Hello World!")
        return false
    endfunction
    
    private function OnChat takes nothing returns boolean
        call BJDebugMsg("Chat!")
        return false
    endfunction

    private function Init takes nothing returns nothing
        call RegisterAnyPlayerEvent(EVENT_PLAYER_END_CINEMATIC, function OnEsc)
        call RegisterAnyPlayerEvent(EVENT_PLAYER_CHAT, function OnChat)
    endfunction
endlibrary

It didn't work for me. It seemed to work after I added a second event registry, but then it ended up having weird bugs (e.g. if I put the same register 3 times, it would fire the actions 6 times).
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Thanks for spotting this out. Its because of multiple updates done just before uploading script to accomodate it for hive :p

Was checking for false during register process instead of true within Register<>Event libs.

Should be fixed now, at least I hope so.

Edit: should I add hidden tags for each of those libs?
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Added RegisterPlayerUnitEvent. It contains whats missing within Maggys RPUE.
Separate triggers for each player per playerunitevent are not created. Instead, there is one trigger per event as it should be. Creates less handles.
Allows one to retrieve any trigger handle which is in use due to reason mentioned above.

This script is not ment to have the same api as Maggys. It follows standard warcraft3 naming convention: Register/RegisterAny.
Since all of my previous scripts follow that rule, making an exception would be pointless.

I've been using all of those through my codes and found no problems or errors. Retrieving triggers is so much needed, escpecially when every event is registered via such lib and you want to disable/enable trigger temporarily, preventing events from taking place. Functionality > less functionality.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
The native library existed for some time now. And this version of RPUE was done couple weeks later after maggy uploaded his, since the missing things always prevented me from using this "modificated version". And for the sake of completeness, its good to have this one too here.

And Ruke, those "things" were reported in Maggies thread several times already, it's been years now. There is no reason not to paste this here. Whatmore, when using registerevents from this libs, it was pain in ass to couple naming convention with original RPUG.

Fact that those several triggers were created was not the worse part. I've had troubles with retrieval of triggers many times, because original RPUG wouldnt allow me to. Also, this "RegisterEvent" comes as a pack. The main lib is core for every other since those are just unique wrappers. Win win.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
@edo494 perfect example of.. what everyone knows. And now, will GetTriggeringTrigger retrieve handle in other triggers execution? Dont be foolish. Sometimes you need to get access to handle from the "outside".

@Ruke, which thread? RPUE? Dude, some pages I learnt by heart.
If u speak of reduction of trigger handles - this one is even better. Plus, once again, you can get every trigger u want.

Whatever man, you only use if u want to. It's your own choice. However, there is nothing wrong with uploading different version, is there?
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
no, you said you cant, I show you can. And more to the point, whats the point of manipulating the executing trigger? if you want to remove it at certain point, you can just as much use your own trigger. There is 0 cases where you would use RegisterXXXEvent with trigger retrieval that I can think of.

I dont quite understand how this works internally, I didnt take the time to look into it very good, and it is a bit bigger than Mags one, but it has the other events, which is very good in my opinion
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
@edo494 It wasn't about just showing "how can we retrive trigger handle". Read the topic again. I was in need of retrival many times - you need you use. If you don't, whats the point of denying the need?

This pack was uploaded some time ago. And it's not RPUE as you both arguing about, in fact RPUE is one of extensions pack brings. Registering Player/Game/Unit in such form wasn't even uploaded on hive. And the purpose of RegisterNativeEvent is to archive everything within same core.

Now, you say Maggies is shorter, true, yet when you were to use additional one, lets say for Player, then this pack would be a better choice without a doubt.

EDIT: To clarify: You can read form posts above why I've uploaded RPUE, yet ITS NOT RPUE per se. This one is a "pack" with kind of "core" as a storage.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Nope? RPUE made no difference in performance, nor does this one.

This offers just 2 points, which has been mentioned milion times:
-less handles (even lower amount than in popular RPUE)
-posibility to retrieve any trigger handle

There is non:
JASS:
local integer i = 16 * GetHandleId(p) + GetPlayerId(pl)
:)

RegisterNativeEvent does the job. The rest of scripts are just wrappers to make everything clean, and to bring proper naming convention as stated.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
well yea lower handle count is nice and dandy and all, but you know, we are not living in 2003 where every 200 bytes object matters, nor is anyone running Warcraft 3 on embedded system like Arduino, where the memory is very limited
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
And ^this should prevent me from uploading something I've been using for a while, and has enough quality in my opinion to share with hive users?

Guys with such atitude, none should upload anything in case most guys viewing jass section got their own, modified codes and it's unlikely that they will change their habits.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Y, and UnitDex by TH exists. And basically the only difference between his and Nes one is that its smaller and uses no requirements. So..

None uses 2000 machines now, guess TH should remove his script? ^)^
Nope, in fact I rly enjoy using both UI :)

Btw, without that pro, original RPUE has no point of existence either.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
it has point of existance, because you dont have to write loop every time you want PlayerUnitEvent registered, you just call one function.

No, having "less" handles is not pro in my opinion. But you know, different people, different opinions

And UnitDex is the only Jass unit indexer currently on Hive
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
TH.. why not? I have listed all of them. Just read the thread.

Also, this is not just RPUE - I've uploaded it as the lastest module. This snippet provides nicely coupled pack for unit, player, playerunit and game events - is even smaller than 2 separate resources if you need more than just RPUE.

Moreover, as stated - this allows you to retrieve trigger attached to given event regardless of circumstances (RPUE does not), generates less handless then RPUE and has better naming :)

The head lib in form of RegisterNativeEvent also provides additional API.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Handle count:
This > Maggies > standard

Maggy' script creates separate triggers when event is registered for individual player, on the top of generic event-triggers. This does not perform such silly operation.

Retrieval of trigger:
This > Maggies

Because of reason written above, in RPUE you can not access triggers created for individual players connected for specific events - only the generic ones. This snippet fixes that mistake.

Again, this is not just RPUE - see the modules and head library. It's more than that.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
I understand your thoughts. But this doesn't replace RegisterPlayerUnitEvent nor will Mag,
change RegisterPlayerUnitEvent to be compatible with this.

It's hard, I would say impossible to depreciate a resource, which is used widely over tons of scripts ( Table, RegisterPlayerUnitEvent, TimerUtils, .... )
, BIG IF you have a change in the API. In this case only RegisterPlayerUnitEvent has to be changed, but will that happen ever?!

In your future version of RegisterPlayerUnitEvent you changed the whole API, probably because you choose more generic names.
Taken arguments are also no longer the same as before.
Meaning: Users have to change their code everywhere they used RegisterPlayerUnitEvent or write a wrapper function.

Conclusion: If you wish to depreciate a monumental resource like RPUE then please use the exact same API for easy
backwards compatibility. After so many years there is no reason to argue about function names.
Tim Cook also doesn't figure out that Apple should be named Orbital from tomorrow on. :p

I could approve this, assuming it's working perfectly, but I'm not sure if it a valuable addition to our jass section.

Please don't argue about pros and cons over existing resources anymore, as I know them.
I want to figure out how likely it is, that this is beeing used ever by someone except yourself.

Consider what I mentioned above and we can come to a good solution.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
I've given arguments about usefulness of this resource already so I won't be repeating myself, you do not want it either.

Simply put, it's here to simplify Player/Game/Unit and PlayerUnit event handling, just like Maggy's PlayerUnit or Bribe's SpellEffectEvent.
There are clear advantages over Maggy's script, though the naming is a big con - Maggy would probably name his functions differently as he already once told. However, that idea came too late and script has been popular already.
When he posted his resource, I was still closer to joining the ranks of medicine students than the IT ones and I had noticed the naming error very late, making my suggestion in his thread rather irrelevant although right.

Due to RPUE function naming, options are very limited here in order to provide backward compatibility ("ForPlayer" one is OK, the other function is complicating stuff).
Instead, I've wrapped snippet within the macro with default implementation set to be compatibilte with RPUE. This way I avoid any overhead yet still providing solution both, for my personal stuff (or general approach) and public needs.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
I wonder why you accept integer as eventId, instead of accepting event type?

If you want ints, it could be good to provide some or all the event's named constants or at least putting the list up, because unless you look at the example of AnyPlayerEvent etc, you dont really know what to pass as eventId.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
This is because native event types don't really inherit any interface. Instead, they all extend 'eventid' which is in fact handle and can be used for GetHandleId() function.
function GetNativeEventTrigger takes integer eventId returns trigger is a base function and a link for all the event types when retrieving proper trigger handle. However, I've expanded upon that subject in all "Register<T>Event" snippets and provided user-friendly interface.

Comes in form of:
JASS:
function GetPlayerEventTrigger takes playerevent whichEvent returns trigger
function GetGameEventTrigger takes gameevent whichEvent returns trigger
function GetUnitEventTrigger takes unitevent whichEvent returns trigger
function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
I could have kept GetNativeEventTrigger private, but honestly, I see no reason to do so.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
what about named constants for a little little bit easier usage?

Anyways, I think this could actually work as even a replacement for the old RPUE, since this basically does what it does in more generic way(not limiting to PUE).
 
Level 13
Joined
Nov 7, 2014
Messages
571
JASS:
        // 122 native events, unfortunatelly ids are not continuous
        static method operator[] takes integer eventId returns integer
            if ( eventId > 286 ) then
                return eventId - 174
            elseif ( eventId > 259 ) then
                return eventId - 165
            elseif ( eventId > 91 ) then
                return eventId - 164
            endif
            return eventId
        endmethod

This seems pretty pointless, you can easily increase set table = TableArray[295] or get rid of it entirely.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
I don't agree with that. operator[] won't be invoked often enough for that to matter - and in my opinion, allocating over twice the number of Tables necessary is big minus to that.

Again, I've already considered that option almost 2 years ago when lib was first launched but registration happens almost always during initialization and afterwards stays behind the scenes.
When I've written this for the first time, I was going to cover more native event types - not just playerunit, player, game and unit types. Declaring random TableArray with hundreds of keys when only portion stays in use seemed dirty to me. Meaby it's a matter of taste.
 
Level 13
Joined
Nov 7, 2014
Messages
571
I don't agree with that. operator[] won't be invoked often enough for that to matter
Sure.

and in my opinion, allocating over twice the number of Tables necessary is big minus to that.

JASS:
set table = TableArray[295] // TableArray[xxx] calls the static method operator[] bellow

struct TableArray extends array

static method operator [] takes integer array_size returns TableArray
    local Table tb = dex.size [array_size] //Get the unique recycle list for this array size
    local TableArray this = tb[0]         //The last-destroyed TableArray that had this array size

    debug if array_size <= 0 then
        debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
        debug return 0
    debug endif

    if this == 0 then
        set this = less - array_size
        set less = this
    else
        set tb[0] = tb[this]  //Set the last destroyed to the last-last destroyed
        call tb.remove(this)  //Clear hashed memory
    endif

    set dex.size[this] = array_size //This remembers the array size
    return this
endmethod

endstruct

I don't see any Table allocations in the sense of: Table.create() here, and it's unlikely to run out of 2147483648 integers, so there is no "big minus"?
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
TableArray has to get its Tables out from somewhere, and it indeed allocates Tables, one per id, so basically if you say TableArray[500], it will indeed allocate 500 tables, otherwise it couldnt work, because it would have nothing to return on nonstatic [] call(it returns Table)
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
It doesn't allocate 500 Tables by calling "Table.create()" 500 times, it simply uses the negative-integer space to reserve a range of negative integers which function as Tables just like the individual, positive integers, except you don't destroy the negative integer Tables (you just destroy TableArrays directly).

When a TableArray gets recycled, it is indexed by its array size. You couldn't get a size 1000 array fom a size 10 array reserve space. That's why I typically recommend people to use size 8192 TableArrays, as the consistent size means that there will be better recycling compatibility between resources. Nevertheless, I don't think I've seen anyone destroying TableArrays - mostly they are declared on Init and never recycled. Originally, TableArrays didn't even have a way to be recycled.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
interesting, didnt know that(very apparently from my post :D)

I am for approval of this, and maybe even potential deprecation/graveyarding of RPUE, since this achieves the same thing and more, and the script is right there ready to be copy-pasted(yes I do understand that RPUE is widely used, but this is superior version of event registration in my opinion)
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Due to fact that I've been working with Table very closely (when writing List<T>/ Vector<T>) I knew about allocating method for TableArray. Still, allocating unnecessarily big array just doesn't apeal to me - guess due to how I'm used to handle containers in c++.

Global on top of RPUE enables user to control its API syntax, but honestly, ctrl+R isn't that hard and sticking to Blizzard native syntax seems like the right thing to do - it's very intuitive, especially for new users.
 
I am for approval of this, and maybe even potential deprecation/graveyarding of RPUE
This actually.

Edit:

It's quite a step but I would make this the new standard resource for event registrations.
It would be still okay that people use(d) others, as they work, but this is superior and more generic.

I would approve this soon and deprecate Maggy's snippet if noone jumps in.
 
Last edited:
Level 13
Joined
Nov 7, 2014
Messages
571
Am I mistaken or this can be (arguably) more concisely written as:
JASS:
library SingleTriggerPerEvent

globals
    private trigger array trgs
endglobals

function GetEventTrigger takes eventid ee returns trigger
    return trgs[GetHandleId(ee)]
endfunction

function RegisterAnyPlayerEvent takes playerevent ee, code f returns nothing
    local integer e = GetHandleId(ee)
    local integer p

    if trgs[e] == null then
        set trgs[e] = CreateTrigger()

        set p = 0
        loop
            exitwhen p > 15 // could use PlayerArray.PlayingPlayers
            call TriggerRegisterPlayerEvent(trgs[e], Player(p), ee)
            set p = p + 1
        endloop
    endif

    call TriggerAddAction(trgs[e], f)
endfunction

function RegisterGameEvent takes gameevent ee, code f returns nothing
    local integer e = GetHandleId(ee)

    if trgs[e] == null then
        set trgs[e] = CreateTrigger()
        call TriggerRegisterGameEvent(trgs[e], ee)
    endif

    call TriggerAddAction(trgs[e], f)
endfunction

function RegisterAnyPlayerUnitEvent takes playerunitevent ee, code f returns nothing
    local integer e = GetHandleId(ee)
    local integer p

    if trgs[e] == null then
        set trgs[e] = CreateTrigger()

        set p = 0
        loop
            exitwhen p > 15 // could use PlayerArray.PlayingPlayers
            call TriggerRegisterPlayerUnitEvent(trgs[e], Player(p), ee, null)
            set p = p + 1
        endloop
    endif

    call TriggerAddAction(trgs[e], f)
endfunction


globals
    private hashtable ht = InitHashtable()
endglobals

function RegisterPlayerEvent takes player pp, playerevent ee, code f returns nothing
    local integer e = GetHandleId(ee)
    local integer p = GetPlayerId(pp)
    local trigger t

    set t = LoadTriggerHandle(ht, e, p)
    if t == null then
        set t = CreateTrigger()
        call SaveTriggerHandle(ht, e, p, t)
        call TriggerRegisterPlayerEvent(t, pp, ee)
    endif

    call TriggerAddAction(t, f)
    set t = null
endfunction
function GetPlayerEventTrigger takes player pp, playerevent ee returns trigger
    return LoadTriggerHandle(ht, GetHandleId(ee), GetPlayerId(pp))
endfunction

function RegisterUnitEvent takes unit uu, unitevent ee, code f returns nothing
    local integer e = GetHandleId(ee)
    local integer u = GetHandleId(uu)
    local trigger t

    set t = LoadTriggerHandle(ht, e, u)
    if t == null then
        set t = CreateTrigger()
        call SaveTriggerHandle(ht, e, u, t)
        call TriggerRegisterUnitEvent(t, uu, ee)
    endif

    call TriggerAddAction(t, f)
    set t = null
endfunction
function GetUnitEventTrigger takes unit uu, playerevent ee returns trigger
    return LoadTriggerHandle(ht, GetHandleId(ee), GetHandleId(uu))
endfunction

function RegisterPlayerUnitEvent takes player pp, playerunitevent ee, code f returns nothing
    local integer e = GetHandleId(ee)
    local integer p = GetHandleId(pp)
    local trigger t

    set t = LoadTriggerHandle(ht, e, p)
    if t == null then
        set t = CreateTrigger()
        call SaveTriggerHandle(ht, e, p, t)
        call TriggerRegisterPlayerUnitEvent(t, pp, ee, null)
    endif

    call TriggerAddAction(t, f)
    set t = null
endfunction
function GetPlayerUnitEventTrigger takes unit uu, playerevent ee returns trigger
    return LoadTriggerHandle(ht, GetHandleId(ee), GetHandleId(uu))
endfunction

endlibrary
 
Last edited:
Level 8
Joined
Jan 23, 2015
Messages
121
I noticed that Maggy's RPUE has a bit different order of arguments in RegisterPlayerUnitEventForPlayer than yours. That's bad actually since any system written with Maggy's RPUE would not be able to exist in one map with another system written using yours RPUE because of that different order without additional help which would also make any fixed system unoriginal.
I would be annoyed changing systems just to have them in my map because they use different RPUEs both because of dirty work and because that systems are no more original and the action would be repeated on next system's update.
I think else should force everyone using Maggy's to update to yours RPUE, else you should update your RPUE to Maggy's format and then force to update everyone using yours old one.
 
Last edited:
Level 8
Joined
Jan 23, 2015
Messages
121
if constant boolean RPUE_VERSION_NEW = false, then you should be able to use Mag's API style.
Arguments order, please
function RegisterPlayerUnitEvent$SPECIFIC$ takes player whichPlayer, playerunitevent whichEvent, code cb returns nothing - that's Bannar's code
function RegisterPlayerUnitEventForPlayer takes playerunitevent p, code c, player pl returns nothing - that's Maggy's code
As you can see, order (player, event, code) isn't (event, code, player)
That's what I'm talking about and this almost as bad as different function name is. It breaks usage of new snippet where Maggy's snippet is supposed to be.
 
Hey, I was able to get this working, but I am confused about this warning:

Destroy native event trigger on your own responsibility

What does this mean? Is there some kind of leak I have to get rid of?

Also, is there a way to "deregister" an object in the callback? In case I only want the trigger to fire once per object.
 
Last edited:
Top