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

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
Ok, I just realized there is a terrible bug with the RegisterPlayerUnitEvent and RegisterPlayerEvent. A single trigger for both 'certain' playerunit event and 'any' playerunit event won't work as intended because for example:
JASS:
call RegisterPlayerUnitEventForPlayer(Player(0), function Func, EVENT_PLAYER_UNIT_SELECTED)
call RegisterPlayerUnitEventForPlayer(Player(1), function Func, EVENT_PLAYER_UNIT_SELECTED)
call RegisterPlayerUnitEventForPlayer(Player(2), function Func, EVENT_PLAYER_UNIT_SELECTED)
1 trigger is shared for Players 1, 2, & 3 therefore, whenever a unit is selected from either of the three players, the trigger will run for all of them.
The same goes for specific playerevents. So we still need 1 trigger for each player for the specific player events and 1 shared trigger for the generic player event.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Updated:

RegisterNativeEvent to 1.0.1.0:

- Now offers new GetPlayerIdNativeEventTrigger function.
- Fixed bug when creating/attaching trigger to event for specific player id.

RegisterPlayerEvent to 1.0.1.0:
- Now offers new GetPlayerEventTriggerForPlayer function.
- Fixed bug when creating/attaching trigger to event for specific player id.
- Improved loop behavior for generic register method, now always registers for ANY-player id (16).

RegisterGameEvent to 1.0.0.2:
- Now always registers for ANY-player id (16) rather than 0.

RegisterPlayerUnitEvent to 1.0.2.0:
- Now offers new GetPlayerUnitEventTriggerForPlayer function.
- Fixed bug when creating/attaching trigger to event for specific player id.
- Improved loop behavior for generic register method, now always registers for ANY-player id (16).
- Fixed macro usage i.e. compatibility with old RPUE. Trigger retrieval functions no longer located within macro.

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.

Thank you for spotting this out. Addressed in RegisterPlayerUnitEvent 1.0.2.0.

Four-five years ago I had spoken with Maggy about the naming convention, and he agreed that different one should be chosen. However, he realized that late thus that was no longer possible without breaking the compatibility (meaby that should be done anyway, that many years ago?).
This is why from the start, script is provided with global for users to choose their preference.

Hey, I was able to get this working, but I am confused about this warning:



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.

User has access to any trigger registered via this system, thus theoretically one could call DestroyTrigger function on trigger retrieved. Note is here to warn anyone doing so.

There is no method for deregistering an already registered event, sorry.

Ok, I just realized there is a terrible bug with the RegisterPlayerUnitEvent and RegisterPlayerEvent. A single trigger for both 'certain' playerunit event and 'any' playerunit event won't work as intended because for example:
JASS:
call RegisterPlayerUnitEventForPlayer(Player(0), function Func, EVENT_PLAYER_UNIT_SELECTED)
call RegisterPlayerUnitEventForPlayer(Player(1), function Func, EVENT_PLAYER_UNIT_SELECTED)
call RegisterPlayerUnitEventForPlayer(Player(2), function Func, EVENT_PLAYER_UNIT_SELECTED)
1 trigger is shared for Players 1, 2, & 3 therefore, whenever a unit is selected from either of the three players, the trigger will run for all of them.
The same goes for specific playerevents. So we still need 1 trigger for each player for the specific player events and 1 shared trigger for the generic player event.

Thank you for spotting this out. Addressed in RegisterPlayerUnitEvent 1.0.2.0, RegisterPlayerEvent 1.0.1.0 and RegisterNativeEvent 1.0.1.0.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Updated - mainly RegisterNativeEvent, to 1.1.0.0.
Simplified main library, removed unnecessary private methods, removed global trigger array. Now fully Table/hashtable dependent. TableArray now of size 0x2000 to allow for custom event registration.

GetPlayerIdNativeEventTrigger renamed to GetIndexNativeEventTrigger. The former was very young (few days) and did not match the spirit of the function.
New convenience method:
function CreateNativeEvent takes nothing returns integer
Purpose: prevent custom (declared within imported library) event-id ambiguity. In most cases, those start at 0, thus having array/table EVENT-id dependent is impossible. Since this is a RegisterEvent pack, having such convenient function is reasonable. Read last line for more info.

The explicit "any player" index typing has been replaced by bj_MAX_PLAYER_SLOTS, to be Warcraft-patch resistant. The bj_ equals 28 for current patch and 16 for pre-1.29. In other words, it's PLAYER_NEUTRAL_PASSIVE + 1 which has been commonly used explicitly in the past as "any-player" index.

Updated reference event-ids in OP to match state official 1.29 list. Three new player events available, and several more has had their id changed (all events which used to start from index 268).
JASS:
    constant playerevent        EVENT_PLAYER_MOUSE_DOWN                 = ConvertPlayerEvent(269)
    constant playerevent        EVENT_PLAYER_MOUSE_UP                   = ConvertPlayerEvent(270)
    constant playerevent        EVENT_PLAYER_MOUSE_MOVE                 = ConvertPlayerEvent(271)
Verified for pre-1.29 and 1.29 itself.
Verified to be Wurst-friendly. TriggerRegisterVariableEvent is unacceptable by wurst, thus custom event should be interpreted by id-trigger pair, and calling such must be done by TriggerEvaluate rather than real variable setting.
 
Last edited:

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
The time has come to shatter this clockwork universe forever!
Let us no longer be slaves of the hourglass!
I warn you: those who do not embrace the greater path shall become victims of its passing!

-Aoenus

After over four years of deprecation, the streamlining of function naming finally commences. Both, RegisterPlayerUnitEvent and RegisterPlayerEvent now match Blizzard alike function naming convention.
Reference to old, obsolete snippets can still be found at the bottom of OP but will be removed in the future.
With the increased activity on Warcraft3 forums and chat servers due to visible interest from Blizzard side, I decided that this is the right time to finally make word flesh.

RegisterNativeEvent:
- CreateNativeEvent function now immediately registers ANY-PLAYER trigger by default before returning to caller
- Added RegisterNativeEvent and RegisterIndexNativeEvent which have the exact same purpose as RegisterPlayerUnitEvent and the rest, but are targeted for user-defined events

RegisterPlayerUnitEvent:

- Removed constant boolean RPUE_VERSION_NEW
- Removed textmacro DEFINE_REGISTER_PLAYER_UNIT_EVENT
- Register function names streamlined to RegisterAnyPlayerUnitEvent and RegisterPlayerUnitEvent. The same pattern has been used for trigger retrieval functions
- Appended missing credits

RegisterPlayerEvent:

- Register function names streamlined to RegisterAnyPlayerEvent and RegisterPlayerEvent. The same pattern has been used for trigger retrieval functions

RegisterUnitEvent:
- RegisterUnitEvent function now properly assigns separate trigger for each unit handle, rather than registering event for event-generic trigger

General:
- All snippets have been adjusted to reflect API changes made to RegisterNativeEvent
- Updated documentation
 
Last edited:

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Even if so, I'd probably add it as extension snippet rather than append new code to existing one.
RegisterNativeEvent is supposed to provide one simple functionality without any real overhead in form of blizzard-like streamlined api. Anything that comes after is what I call the noise.

Idk if it's even worth it, core-arrays are on the horizon : )
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Even if so, I'd probably add it as extension snippet rather than append new code to existing one.
RegisterNativeEvent is supposed to provide one simple functionality without any real overhead in form of blizzard-like streamlined api. Anything that comes after is what I call the noise.

Idk if it's even worth it, core-arrays are on the horizon : )
Did they say anything about that, or any other JASS functionality they want to incorporate?
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
RegisterNativeEvent is supposed to provide one simple functionality without any real overhead in form of blizzard-like streamlined api. Anything that comes after is what I call the noise.
Makes sense. I guess I should just ask you to return the triggerconditions from the registering functions instead.

EDIT:
And a simple UnregisterNativeEventHandler(integer whichEvent, triggercondition handler) in conjunction would also be favorable.
 
Last edited:
Level 15
Joined
Nov 30, 2007
Messages
1,202
I think you should add possibility to disable/enable trigger event. It's a pretty easy thing to add and doesn't add much code imo.

JASS:
function EnableAnyPlayerUnitEvent takes playerunitevent whichEvent returns nothing
    call EnableTrigger(GetNativeEventTrigger(GetHandleId(whichEvent)))
endfunction
function DisableAnyPlayerUnitEvent takes playerunitevent whichEvent returns nothing
    call DisableTrigger(GetNativeEventTrigger(GetHandleId(whichEvent)))
endfunction

Can be useful to prevent triggers for repeat fiering when you don't want them to.
 
Last edited:

NEL

NEL

Level 6
Joined
Mar 6, 2017
Messages
113
How about RemovePlayerAnyUnitEvent (all events). Because I have a few triggers like trigger checks the number of deaths of a unit, once the trigger reached the specific number, trigger must be remove in the game.
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
How about RemovePlayerAnyUnitEvent (all events). Because I have a few triggers like trigger checks the number of deaths of a unit, once the trigger reached the specific number, trigger must be remove in the game.

I think you could do this:

call ClearActions(GetNativeEventTrigger(GetHandleId(whichEvent))) // Don't remeber if it's action or condition based.
 
Level 2
Joined
Apr 13, 2020
Messages
23
Thank you for cool libs! Please help, how i need to rewrite this code with your snippet?

Code:
private function Init takes nothing returns nothing
        set gg_trg_Learn_Skills = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ( gg_trg_Learn_Skills, EVENT_PLAYER_HERO_SKILL )
        call TriggerAddCondition(gg_trg_Learn_Skills, Condition( function Conditions))
        call TriggerAddAction( gg_trg_Learn_Skills, function Actions )
endfunction

or this one?

Code:
private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_CONSTRUCT_START)
        call TriggerAddCondition(t, Condition( function Conditions))
        call TriggerAddAction(t, function Actions)
endfunction
 
Level 2
Joined
Apr 13, 2020
Messages
23
JASS:
RegisterAnyPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function Conditions)
RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_START, function Conditions)

Merge the Actions script into Conditions. You can't use Waits though (not like those are healthy for the game)
Thanks! I rewrited code according to your example and everything works fine! I hope I can reduce the load on the game with this code snippet.
 
Level 1
Joined
Apr 8, 2020
Messages
110
@Bannar There are times when I want the code handler registered to an event to only run one time, when the event gets fired for the first time for instance, so I needed a way to unbind the code handler from the event.

If you could add a simple function like the following:
JASS:
function UnregisterNativeEventHandler takes integer whichEvent, triggercondition handler returns nothing
    call TriggerRemoveCondition(GetNativeEventTrigger(whichEvent), handler)
endfunction
It would do wonders for my cause.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
@Bribe, please correct me if I'm wrong, but removing conditions did not yield expected results in the past. In order for one to be truly sure about event-handler being removed, one had to destroy trigger handle and re-add all the conditions except for those which are to be "removed". Has this somehow changed or is my memory failing me as we speak?
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
@AGD I believe you want me to update both of the following, yes?
JASS:
function RegisterIndexNativeEvent takes integer whichIndex, integer whichEvent, code func returns nothing

function RegisterNativeEvent takes integer whichEvent, code func returns nothing
Given the existing return type - void (nothing) - no compatibility is broken after the change.
 
Last edited:

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
@GhostHunter123 your reply is much appreciated.

Unfortunately, both GetEventPlayerChatString and GetEventPlayerChatStringMatched are intended to work with TriggerRegisterPlayerChatEvent rather than TriggerRegisterPlayerEvent - this is implicitly suggested by the very location of mentioned getters within common.j.

I did some testing with following diff:
Code:
diff --git a/jass/RegisterPlayerEvent.j b/jass/RegisterPlayerEvent.j
index f3fc572..4e58af6 100644
--- a/jass/RegisterPlayerEvent.j
+++ b/jass/RegisterPlayerEvent.j
@@ -39,6 +39,14 @@ function GetPlayerEventTrigger takes player whichPlayer, playerevent whichEvent
     return GetIndexNativeEventTrigger(GetPlayerId(whichPlayer), GetHandleId(whichEvent))
endfunction

+private function TriggerRegisterPlayerEventAware takes trigger t, player p, playerevent evt returns event
+    if evt == EVENT_PLAYER_CHAT then
+        return TriggerRegisterPlayerChatEvent(t, p, "", false) // match any string
+    else
+        return TriggerRegisterPlayerEvent(t, p, evt)
+    endif
+endfunction
+
function RegisterAnyPlayerEvent takes playerevent whichEvent, code func returns nothing
     local integer eventId = GetHandleId(whichEvent)
     local integer index = 0
@@ -47,7 +55,7 @@ function RegisterAnyPlayerEvent takes playerevent whichEvent, code func returns
     if RegisterNativeEventTrigger(bj_MAX_PLAYER_SLOTS, eventId) then
         set t = GetNativeEventTrigger(eventId)
         loop
-            call TriggerRegisterPlayerEvent(t, Player(index), whichEvent)
+            call TriggerRegisterPlayerEventAware(t, Player(index), whichEvent)
             set index = index + 1
             exitwhen index == bj_MAX_PLAYER_SLOTS
         endloop
@@ -62,7 +70,7 @@ function RegisterPlayerEvent takes player whichPlayer, playerevent whichEvent, c
     local integer eventId = GetHandleId(whichEvent)

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

     call RegisterIndexNativeEvent(playerId, eventId, func)

and the results are promising. Could you give a try on your end?
 
Level 11
Joined
Jul 4, 2016
Messages
626
RegisterAnyPlayerEvent takes
This works fantastically. However, the only problem I seem to be having is that for some reason displays a second message that is empty first then the actual message.

EDIT: fixed the issue; made a mistake in copying.
 
Last edited:
Top