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

JASS:
library PlayerUtils initializer onInit uses optional GroupUtils
/**************************************************************
*
*   v1.1.0 by TriggerHappy
*
*   This library provides utilities for dealing with players, as well 
*   as caches player data for improved efficiency. 
*
*   Public Variables
*
*       force FORCE_ACTIVE_PLAYERS - Player group of everyone who is playing.
*
*   Function API
*
*       -- These functions are to be used with the "player" type.
*
*       function PlayerEx takes integer i returns player                // this function is an alternitve to Player()
*       function GetPlayer takes integer i returns player               // this function is an alternitve to Player()
*       function GetPlayerCount takes nothing returns integer           // returns how many active players there are
*       function GetPlayerNameEx takes player p returns string          // should be used instead of GetPlayerName
*       function GetPlayerNameColored takes player p returns string     // returns the players name with color
*       function GetPlayerHex takes player p returns string             // returns player color code
*       function GetActivePlayer takes integer i returns player         // get a player from list of playing players
*       function IsPlayerPlaying takes player p returns boolean         // returns true if the player is playing
*
*   Struct API
*
*       -- These provide the most efficiency and should be used whenever possible.
*
*       static method get       takes integer i returns player
*       static method fromLocal takes nothing returns player
*       static method fromEnum  takes nothing returns Player
*       static method do        takes code func returns nothing
*       static method for       takes force f, code func returns nothing
*       
*       method isPlaying takes nothing returns boolean
*       method setColor  takes playercolor c, boolean changeUnits returns nothing
*
*       static method operator count takes nothing returns integer
*       static method operator []    takes integer id returns player
*
*       method operator name         takes nothing returns string
*       method operator name=        takes string name returns nothing
*       method operator color        takes nothing returns playercolor
*       method operator color=       takes playercolor c returns nothing 
*       method operator defaultColor takes nothing returns playercolor
*       method operator hex          takes nothing returns string
*       method operator nameColored  takes nothing returns string
*
**************************************************************/

    globals
        constant force FORCE_ACTIVE_PLAYERS = CreateForce()
        
        private player Local
        private integer ActivePlayerCount = -1
        private string array Name
        private player array ActivePlayers
        private boolean array IsActive
        private string array HexData
        private string array Hex
    endglobals
    
    static if (not LIBRARY.GroupUtils) then
        globals
            private constant group ENUM_GROUP = CreateGroup()
        endglobals
    endif
    
    struct Players
        
        player handle

        static playercolor array Color
        
        static method get takes integer i returns player
            return thistype(i).handle
        endmethod
        
        static method fromLocal takes nothing returns player
            return Local
        endmethod
        
        static method do takes code func returns nothing
            call ForForce(FORCE_ACTIVE_PLAYERS, func)
        endmethod
        
        static method for takes force f, code func returns nothing
            call ForForce(f, func)
        endmethod
        
        method isPlaying takes nothing returns boolean
            return IsActive[this]
        endmethod
        
        method setColor takes playercolor c, boolean changeUnits returns nothing
            local unit u
            call SetPlayerColor(this.handle, c)
            if (changeUnits) then
                call GroupEnumUnitsOfPlayer(ENUM_GROUP, this.handle, null)
                loop
                    set u = FirstOfGroup(ENUM_GROUP)
                    exitwhen u == null
                    call SetUnitColor(u, c)
                    call GroupRemoveUnit(ENUM_GROUP, u)
                endloop
            endif
        endmethod
        
        static method operator count takes nothing returns integer
            return ActivePlayerCount + 1
        endmethod
        
        static method operator [] takes player p returns thistype
            return thistype(GetPlayerId(p))
        endmethod
        
        method operator name takes nothing returns string
            return Name[this]
        endmethod
        
        method operator name= takes string name returns nothing
            call SetPlayerName(this.handle, name)
        endmethod
        
        method operator color takes nothing returns playercolor
            return GetPlayerColor(this.handle)
        endmethod
        
        method operator color= takes playercolor c returns nothing 
            call SetPlayerColor(this.handle, c)
        endmethod
        
        method operator defaultColor takes nothing returns playercolor
            return Color[this]
        endmethod
        
        method operator hex takes nothing returns string
            return Hex[this]
        endmethod
        
        method operator nameColored takes nothing returns string
            return Hex[this] + Name[this] + "|r"
        endmethod
        
    endstruct
    
    function PlayerEx takes integer i returns player
        return Players(i).handle
    endfunction
    
    function GetPlayer takes integer i returns player
        return Players(i).handle
    endfunction
    
    function LocalPlayer takes nothing returns player
        return Local
    endfunction
    
    function GetPlayerCount takes nothing returns integer
        return ActivePlayerCount + 1
    endfunction
    
    function GetPlayerNameEx takes player p returns string
        return Name[GetPlayerId(p)]
    endfunction
    
    function GetPlayerNameColored takes player p returns string
        local integer i = GetPlayerId(p)
        return Hex[i] + Name[i] + "|r"
    endfunction
    
    function GetPlayerHex takes player p returns string
        return Hex[GetPlayerId(p)]
    endfunction
    
    function GetActivePlayer takes integer i returns player
        return ActivePlayers[i]
    endfunction
    
    function IsPlayerPlaying takes player p returns boolean
        return IsActive[GetPlayerId(p)]
    endfunction
    
//===========================================================================
    
    private function SetPlayerNameHook takes player p, string name returns nothing
        set Name[GetPlayerId(p)] = name
    endfunction
    
    private function SetPlayerColorHook takes player p, playercolor c returns nothing
        set Hex[GetPlayerId(p)] = HexData[GetHandleId(c)]
    endfunction

    private function onLeave takes nothing returns boolean
        local integer i = 0
        local player p  = GetTriggerPlayer()
        
        loop
            exitwhen i > ActivePlayerCount
            
            if (ActivePlayers[i] == p) then
                set ActivePlayers[i]  = ActivePlayers[ActivePlayerCount]
                set ActivePlayerCount = ActivePlayerCount - 1
                set IsActive[GetPlayerId(p)] = false
                call ForceRemovePlayer(FORCE_ACTIVE_PLAYERS, ActivePlayers[i])
                return false
            endif
            
            set i = i + 1
        endloop
        
        return false
    endfunction
    
    private function onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        local Players p
        
        set Local       = GetLocalPlayer()
        
        set HexData[0]  = "|cffff0303"
        set HexData[1]  = "|cff0042ff"
        set HexData[2]  = "|cff1ce6b9"
        set HexData[3]  = "|cff540081"
        set HexData[4]  = "|cfffffc01"
        set HexData[5]  = "|cfffe8a0e"
        set HexData[6]  = "|cff20c000"
        set HexData[7]  = "|cffe55bb0"
        set HexData[8]  = "|cff959697"
        set HexData[9]  = "|cff7ebff1"
        set HexData[10] = "|cff106246"
        set HexData[11] = "|cff4e2a04"
        
        loop
            exitwhen i == bj_MAX_PLAYER_SLOTS
            
            set p         = Players(i)
            set p.handle  = Player(i)
            
            set Players.Color[i] = GetPlayerColor(p.handle)
            
            if (GetPlayerController(p.handle) == MAP_CONTROL_USER and GetPlayerSlotState(p.handle) == PLAYER_SLOT_STATE_PLAYING) then
                set ActivePlayerCount = ActivePlayerCount + 1
                set ActivePlayers[ActivePlayerCount] = p.handle
                set IsActive[i] = true
                call TriggerRegisterPlayerEvent(t, p.handle, EVENT_PLAYER_LEAVE)
                call ForceAddPlayer(FORCE_ACTIVE_PLAYERS, p.handle)
                set Hex[i] = HexData[GetHandleId(Players.Color[i])]
            endif
            
            set Name[i] = GetPlayerName(p.handle)
            set i = i + 1
            
        endloop
        
        call TriggerAddCondition(t, Filter(function onLeave))
        
    endfunction
    
    hook SetPlayerName SetPlayerNameHook
    hook SetPlayerColor SetPlayerColorHook
    
endlibrary

JASS:
// Here's an example of enumerating through all active players via a force

function Callback takes nothing returns nothing
    local Players p = Players[GetFilterPlayer()]
    
    call p.setColor(Players.Color[GetRandomInt(0, 11)], true) // randomize player color
    call BJDebugMsg(p.nameColored) // display name (with player color)
endfunction

call Players.do(function Callback)

// Now without a force

local integer i = 0
loop
    exitwhen i == GetPlayerCount() // or Players.count
    call Players(i).setColor(Players.Color[GetRandomInt(0, 11)], true) // randomize player color
    call BJDebugMsg(Players(i).nameColored)
    set i = i + 1
endloop
 
Last edited:
Good to know and yes add GetLocalPlayer.

Btw does GetPlayerName work for computer players?

Yes, it returns "Player #".

I've updated the main post, I'll look into possibly implementing LocalHelper.

I did some benchmarks with these function wrappers and the speed was obviously slower because of the private keyword (longer variable name). But it does seem that JassHelper correctly inlines each function. PlayerEx was actually a tiny bit slower then calling Player, however when the script has been optimized it was faster. The same principle applies to all the wrappers.

PlayerNameFromId was 50% faster than the native alternative, while PlayerName was still about 40% because of theGetPlayerId call. So basically everything included in this library is faster, at least when the map is ran through Vex's optimizer (which every finished map should be).

I also may add player color support to this and will of course finish wrapper common player natives.
 
It's not uncommon for players to change their names in-game.

Why do you have to shit on my dreams? Here I am thinking this resource had nothing wrong with it :p

Anyway, any ideas? Would hooking SetPlayerName really be that bad? I need to finally see how hooks are compiled, I remember seeing somewhere they used TriggerEvaluate or something? I might have just made that up though.

EDIT God damnit, hooks really are ugly behind the scenes. Why did Vex implement them like that? I'll create a version with hooks, but that goes against the whole idea of this script which is efficiency. Maybe I'll add in the documentation to just use SetPlayerNameEx.

SetPlayerName shouldn't be called often at all anyways, although I want to hear what you guys think.

I'm considering that it may just be better for users to have something like this in their own maps, where they can intelligently use it instead of having a public resource which uses hacks to get around things.

I do still see the usefulness in this however there are probably other natives which will end up having to be hooked, and not to mention the API all ends with "Ex", which is hacky.
 
function PlayerEx on its own would make this a complete resource in my eyes :p

Extra stuff like player name caching is the cherry on top.

PlayerEx is only ~10% faster (I deleted the part of the OP where it stated that).

But the performance increases significantly when the other natives are wrapped, for example:

JASS:
call GetPlayerName(Player(0)) // is 50% slower than GetPlayerNameById(0)
// and 40% slower then GetPlayerNameEx(PlayerEx(0))

I also disagree about PlayerEx being a standalone resource, I think modders should handle that themselves.

I mean it's really just one array.
 
You should add a list of active players. Sometimes you want to perform iterations for just the players that are (1) users and (2) playing.
if (GetPlayerController(Player(index)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(index)) == PLAYER_SLOT_STATE_PLAYING) then

IMO the overall difference efficiency-wise is negligible but if this has enough features, it could be worth implementing. :) Although, I'm curious how much faster Name[GetPlayerId(p)] is compared to GetPlayerName(p).

EDIT: Sorry, I can't read. :p Didn't 'know you posted it in the previous post.
 
Last edited:
PurgeandFire said:
IMO the overall difference efficiency-wise is negligible but if this has enough features, it could be worth implementing. :) Although, I'm curious how much faster Name[GetPlayerId(p)] is compared to GetPlayerName(p).

Like I said above, it's 40% faster which definitely isn't negligible.

50% for GetPlayerNameById.

Of course this was with variables names of length one.
 
Updated, these should be inlined.

JASS:
local integer i = 0
loop
    exitwhen i > GetPlayerCount()
    call BJDebugMsg(GetPlayerNameEx(ActivePlayer(i)))
    set i = i + 1
endloop

// becomes

local integer i= 0
loop
    exitwhen i > (PlayerUtils__ActivePlayerCount) // INLINED!!
    call BJDebugMsg((PlayerUtils__Name[GetPlayerId(((PlayerUtils__ActivePlayers[(i)])))])) // INLINED!!
    set i=i + 1
endloop
 
Level 16
Joined
Aug 7, 2009
Messages
1,403
An "IsActive" or much rather, "IsPlayerActive" function could be useful as well. I don't think I need to tell you its benefits.

By the way:

JASS:
hook SetPlayerName SetPlayerNameEx

JASS:
function SetPlayerNameEx takes player p, string name returns nothing
        call SetPlayerName(p, name)
        set Name[GetPlayerId(p)] = name
    endfunction

Demonstrating how to make infinite loops with hooks, are we? :) (Not exactly an infinite loop as there are triggers behind hooks, if I recall correctly, but it should never stop firing).
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
An "IsActive" or much rather, "IsPlayerActive" function could be useful as well. I don't think I need to tell you its benefits.

By the way:

JASS:
hook SetPlayerName SetPlayerNameEx

JASS:
function SetPlayerNameEx takes player p, string name returns nothing
        call SetPlayerName(p, name)
        set Name[GetPlayerId(p)] = name
    endfunction

Demonstrating how to make infinite loops with hooks, are we? :) (Not exactly an infinite loop as there are triggers behind hooks, if I recall correctly, but it should never stop firing).

The JassHelper is supposed to ignore the recursive hook, and if not you can disable GetTriggeringTrigger() and then re-enable it.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Wait, now the name isn't changed if we use the native function SetPlayerName ...
The correct way to do it is to include a boolean control inside the hooked function to avoid an infinite loop.

EDIT : like this


JASS:
library PlayerUtils initializer onInit
/**************************************************************
*
*   v1.0.1 by TriggerHappy
*
*   API:
*       function PlayerEx takes integer i returns player  
*       function ActivePlayer takes integer i returns player
*       function IsPlayerActive takes player p returns boolean
*       function IsPlayerActiveById takes integer i returns boolean
*       function GetPlayerCount takes nothing returns integer
*       function GetPlayerNameById takes integer i returns string
*       function SetPlayerNameById takes integer i, string name returns nothing
*       function GetPlayerNameEx takes player p returns string
*
**************************************************************/
    globals
        player LocalPlayer
        private integer ActivePlayerCount = -1
        private player array Handle
        private string array Name
        private player array ActivePlayers
        private boolean array IsActive
        private boolean DoTheHook = true
    endglobals
    
    function PlayerEx takes integer i returns player
        return Handle[i]
    endfunction
    
    function ActivePlayer takes integer i returns player
        return ActivePlayers[i]
    endfunction
    
    function IsPlayerActive takes player p returns boolean
        return IsActive[GetPlayerId(p)]
    endfunction
    
    function IsPlayerActiveById takes integer i returns boolean
        return IsActive[i]
    endfunction
    
    function GetPlayerCount takes nothing returns integer
        return ActivePlayerCount
    endfunction
    
    function GetPlayerNameById takes integer i returns string
        return Name[i]
    endfunction
    
    function SetPlayerNameById takes integer i, string name returns nothing
        call SetPlayerName(Handle[i], name)
        set Name[i] = name
    endfunction
    
    function GetPlayerNameEx takes player p returns string
        return Name[GetPlayerId(p)]
    endfunction
    
    private function SetPlayerNameEx takes player p, string name returns nothing
        if DoTheHook then
            set DoTheHook = false
            call SetPlayerName(p,name)
            set DoTheHook = true
            set Name[GetPlayerId(p)] = name
        endif
    endfunction

    private function PlayerLeave takes nothing returns boolean
        local integer i = 0
        local player p  = GetTriggerPlayer()
        loop
            exitwhen i > ActivePlayerCount
            if (ActivePlayers[i] == p) then
                set ActivePlayers[i]  = ActivePlayers[ActivePlayerCount]
                set ActivePlayerCount = ActivePlayerCount - 1
                set IsActive[GetPlayerId(p)] = false
                return false
            endif
            set i = i + 1
        endloop
        return false
    endfunction
    
    private function onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        
        set LocalPlayer = GetLocalPlayer()
        
        loop
            exitwhen i == bj_MAX_PLAYER_SLOTS
            set Handle[i] = Player(i)
            if (GetPlayerController(Handle[i]) == MAP_CONTROL_USER and  GetPlayerSlotState(Handle[i]) == PLAYER_SLOT_STATE_PLAYING) then
                set ActivePlayerCount = ActivePlayerCount + 1
                set ActivePlayers[ActivePlayerCount] = Handle[ActivePlayerCount]
                set IsActive[i] = true
                call TriggerRegisterPlayerEvent(t, Handle[i], EVENT_PLAYER_LEAVE)
            endif
            set Name[i] = GetPlayerName(Handle[i])
            set i = i + 1
        endloop
        
        call TriggerAddCondition(t, Filter(function PlayerLeave))
        
    endfunction
    
    hook SetPlayerName SetPlayerNameEx
    
endlibrary

EDIT : Nevermid, wrong though about how hooks worked.
 
Last edited:
Level 17
Joined
Apr 27, 2008
Messages
2,455
Hmm, i thought the native hooked function was completely remplaced, that's not the case ?
I mean we have the TriggerEvaluate part + the native function call ? In short, what's the jass output ?

EDIT : Ok i was out of my mind, according to the jasshelper documentation it's obvious that the native function is kept.
It's hook after all, not define ...
So just forget what i've said above ...
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
But there is still an issue i think, if we use SetPlayerName with a long string (more characters than allowed for a player name), GetPlayerName should return a different string than the string array Name. I guess that the string is just cut off.
But it could be considered as a feature, i don't know ...
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Ok, here is the fix to the problem mentionned above (if it's not considered as a feature).
Or well maybe only the display length is limited, not the name length itself, but you didn't answered, so.

JASS:
    function SetPlayerNameById takes integer i, string name returns nothing
        call SetPlayerName(Handle[i], name)
        set Name[i] = SubString(name,0,42) // or just GetPlayerName...
    endfunction
    
    private function SetPlayerNameEx takes player p, string name returns nothing
        set Name[GetPlayerId(p)] = SubString(name,0,42)
    endfunction
42 is just a random value, i don't know which one is valid.
 
Level 16
Joined
Aug 7, 2009
Messages
1,403

To be honest I never looked for a PlayerUtils snippet as I had one of my own (or at least I had all those things covered in IID - active players in the multiboard (I think, been a while since I touched IID) snippet, original/extended/colored names in PlayerUtils).

If you really wanted to make yours special though then you could try to find a way to reset a players name to their original one when the game restarts. This is useful in single player, as if you played an AoS (for example) versus bots, that modified your name and you restarted the map once you finished it, your name would remain the same, so it'd be possible to get a name like "Luorax (HName1) (HName2)[, ...]". I remember I got working it (I think) with game caches but something got screwed up so I simply scratched it - but since you like to toy around with these kind of things, I figured you might be interested in solving this.

[EDIT]

And it's not just me, BTW. I remember I came across this problem during the first few weeks when I first started mapping seriously, so posted this on TheHelper, in the GUI section, and others had the same issue. It's a fairly complex issue so of course they didn't manage to find a solution (even though it was during 1.23, when caches were so popular), that's why I think it has potential. And for the sake of it, of course.
 
42 is just a random value, i don't know which one is valid.

UsingGetPlayerNamedoesn't work because the hook is ran beforeSetPlayerNameso I'll hold on updating until I figure out the max username length.

I modified some of the API as well. Although, SetPlayerNameEx should work as intended.

JASS:
library PlayerUtils initializer onInit
/**************************************************************
*
*   v1.0.2 by TriggerHappy
*
*   This library caches player data to improve efficiency, as well as
*   provides support for dealing with player colors and strings.
*
*   API:
*       function PlayerEx takes integer i returns player  
*       function GetPlayerCount takes nothing returns integer
*       function SetPlayerNameEx takes player p, string name returns nothing
*       function GetPlayerNameEx takes player p returns string
*       function SetPlayerNameById takes integer i, string name returns nothing
*       function GetPlayerNameById takes integer i returns string
*       function GetPlayerHex takes player p returns string
*       function GetPlayerHexById takes integer i returns string
*       function GetActivePlayer takes integer i returns player
*       function IsPlayerPlaying takes player p returns boolean
*       function IsPlayerPlayingById takes integer i returns boolean
*
**************************************************************/
    globals
        private constant boolean LENGTH_SAFTEY = false // Account for long usernames

        // Don't modify below this line
        player LocalPlayer
        private integer ActivePlayerCount = -1
        private player array Handle
        private string array Name
        private player array ActivePlayers
        private boolean array IsActive
        private string array Hex
    endglobals
    
//===========================================================================
    
    function PlayerEx takes integer i returns player
        return Handle[i]
    endfunction
    
    function GetPlayerCount takes nothing returns integer
        return ActivePlayerCount
    endfunction
    
    function SetPlayerNameById takes integer i, string name returns nothing
        call SetPlayerName(Handle[i], name)
        static if (LENGTH_SAFTEY) then
            set name = GetPlayerName(p)
        endif
        set Name[i] = name
    endfunction
    
    function SetPlayerNameEx takes player p, string name returns nothing
        call SetPlayerName(p, name)
        static if (LENGTH_SAFTEY) then
            set name = GetPlayerName(p)
        endif
        set Name[GetPlayerId(p)] = name
    endfunction
    
    function GetPlayerNameEx takes player p returns string
        return Name[GetPlayerId(p)]
    endfunction
    
    function GetPlayerNameById takes integer i returns string
        return Name[i]
    endfunction
    
    function GetPlayerHex takes player p returns string
        return Hex[GetPlayerId(p)]
    endfunction
    
    function GetPlayerHexById takes integer i returns string
        return Hex[i]
    endfunction
    
    function GetActivePlayer takes integer i returns player
        return ActivePlayers[i]
    endfunction
    
    function IsPlayerPlaying takes player p returns boolean
        return IsActive[GetPlayerId(p)]
    endfunction
    
    function IsPlayerPlayingById takes integer i returns boolean
        return IsActive[i]
    endfunction
    
//===========================================================================
    
    private function SetPlayerNameHook takes player p, string name returns nothing
        set Name[GetPlayerId(p)] = name
    endfunction
    
    private function SetPlayerColorEx takes player p, playercolor c returns nothing
        set Hex[GetPlayerId(p)] = Hex[GetHandleId(c)]
    endfunction

    private function PlayerLeave takes nothing returns boolean
        local integer i = 0
        local player p  = GetTriggerPlayer()
        loop
            exitwhen i > ActivePlayerCount
            if (ActivePlayers[i] == p) then
                set ActivePlayers[i]  = ActivePlayers[ActivePlayerCount]
                set ActivePlayerCount = ActivePlayerCount - 1
                set IsActive[GetPlayerId(p)] = false
                return false
            endif
            set i = i + 1
        endloop
        return false
    endfunction
    
    private function onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        
        set LocalPlayer = GetLocalPlayer()
        
        loop
            exitwhen i == bj_MAX_PLAYER_SLOTS
            set Handle[i] = Player(i)
            if (GetPlayerController(Handle[i]) == MAP_CONTROL_USER and GetPlayerSlotState(Handle[i]) == PLAYER_SLOT_STATE_PLAYING) then
                set ActivePlayerCount = ActivePlayerCount + 1
                set ActivePlayers[ActivePlayerCount] = Handle[ActivePlayerCount]
                set IsActive[i] = true
                call TriggerRegisterPlayerEvent(t, Handle[i], EVENT_PLAYER_LEAVE)
            endif
            set Name[i] = GetPlayerName(Handle[i])
            set i = i + 1
        endloop
        
        set Hex[0]  = "|cffff0303"
        set Hex[1]  = "|cff0042ff"
        set Hex[2]  = "|cff1ce6b9"
        set Hex[3]  = "|cff540081"
        set Hex[4]  = "|cfffffc01"
        set Hex[5]  = "|cfffe8a0e"
        set Hex[6]  = "|cff20c000"
        set Hex[7]  = "|cffe55bb0"
        set Hex[8]  = "|cff959697"
        set Hex[9]  = "|cff7ebff1"
        set Hex[10] = "|cff106246"
        set Hex[11] = "|cff4e2a04"
        
        call TriggerAddCondition(t, Filter(function PlayerLeave))
        
    endfunction
    
    hook SetPlayerName SetPlayerNameHook
    hook SetPlayerColor SetPlayerColorEx
    
endlibrary

To be honest I never looked for a PlayerUtils snippet as I had one of my own (or at least I had all those things covered in IID - active players in the multiboard (I think, been a while since I touched IID) snippet, original/extended/colored names in PlayerUtils).

If you really wanted to make yours special though then you could try to find a way to reset a players name to their original one when the game restarts. This is useful in single player, as if you played an AoS (for example) versus bots, that modified your name and you restarted the map once you finished it, your name would remain the same, so it'd be possible to get a name like "Luorax (HName1) (HName2)[, ...]". I remember I got working it (I think) with game caches but something got screwed up so I simply scratched it - but since you like to toy around with these kind of things, I figured you might be interested in solving this.

I guess I can try.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
I know about the hook before, else i would have suggest to use it GetPlayerName also in SetPlayerNameEx (old hooked function name) as well.
Yes that doesn't really add something, but meh when i'm not wrong i can't leave any doubt about it :p

Now to be on-topic, what about include LocalHelper in that, too much ? (ofc no need of credits or silly stuff like that ...)
Utils leads to collection or mixed stuff for me (TimerUtils is a bad name imho, as it is nothing more than a timer stack with integer data attachment, after all)

EDIT :

JASS:
function DisplayMaxNameLength takes nothing returns nothing
    local integer i = 0
    local string s = "a"
    loop
    exitwhen i == 777
    set i = i+1
        set s = s+"b"
    endloop
    call SetPlayerName(GetLocalPlayer(),s)
    call BJDebugMsg(I2S(StringLength(GetPlayerName(GetLocalPlayer())))
endfunction
 
Last edited:
I know about the hook before, else i would have suggest to use it GetPlayerName also in SetPlayerNameEx (old hooked function name) as well.
Yes that doesn't really add something, but meh when i'm not wrong i can't leave any doubt about it :p

Now to be on-topic, what about include LocalHelper in that, too much ? (ofc no need of credits or silly stuff like that ...)
Utils leads to collection or mixed stuff for me (TimerUtils is a bad name imho, as it is nothing more than a timer stack with integer data attachment, after all)

Sure I'll implement LocalHelper.

JASS:
function DisplayMaxNameLength takes nothing returns nothing
    local integer i = 0
    local string s = "a"
    loop
    exitwhen i == 777
    set i = i+1
        set s = s+"b"
    endloop
    call SetPlayerName(GetLocalPlayer(),s)
    call BJDebugMsg(I2S(StringLength(GetPlayerName(GetLocalPlayer())))
endfunction

Yeah but I don't have access to battle.net

There's no limit in single player or LAN (I tested up to 1,000)
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Well ofc a test would be good but that wouln't make sense that there is a string length limitation in battle.net and not on lan. So no i'm not 100 % sure, more like 99.9 %
My guess is that limit is only visual but GetPlayerName still return the full name.

It was just questions anyway, remember that i don't have wc3 installed anymore since a while ^^
 
Level 16
Joined
Aug 7, 2009
Messages
1,403
LocalPlayer should be private as well as it could lead to name collision.

Also, since you keep track of player colours, you might as well provide a "GetPlayerColored[ById]" function, so that the user doesn't have to make it (because I'm pretty sure that's the first thing they'd do after installing the snippet - or at least that's what I did [currently collecting ideas for a possible new project and I decided I might as well put together a raw skeleton])
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
LocalPlayer should be private as well as it could lead to name collision.
I think it is good as it is now, otherwise you couldn't access it directly. A more save way would be to make it a struct & readonly, but that would generate really unnessesary extra code.
Also, since you keep track of player colours, you might as well provide a "GetPlayerColored[ById]" function, so that the user doesn't have to make it
There is GetPlayerHexById or do you mean something different?

PlayerManager is more powerful, but this one is really easy to use for everyone. I like it.
 
Updated.

Still need to finish length safety (apparently max b.net characters allowed is 15) and update documentation.

Basically I fixed a few bugs and added OOP Syntax for the "ById" functions as well as some other features.

JASS:
function Callback takes nothing returns nothing
    local Players p = Players.fromEnum()
    
    // set p.color = PLAYER_COLOR_BLUE (doesn't change unit colors)

    // randomize player color and change units accordingly
    call p.setColor(Players.Color[GetRandomInt(0, 12)], true)

    // display name (with player color)
    call BJDebugMsg(p.nameColored)
endfunction

call Players.do(function Callback)
 
Top