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

[System] PlayerManager

Level 11
Joined
Nov 4, 2007
Messages
337
JASS:
    private function GetHost takes nothing returns player
        call StoreInteger(getTheHost, "missionKey", "key", GetPlayerId(GetLocalPlayer()) + 1)
        call TriggerSyncStart()
        call SyncStoredInteger(getTheHost, "missionKey", "key")
        call TriggerSyncReady()
        return Player(GetStoredInteger(getTheHost, "missionKey", "key") - 1)
    endfunction

This function was stolen!
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
JASS:
    private function GetHost takes nothing returns player
        call StoreInteger(getTheHost, "missionKey", "key", GetPlayerId(GetLocalPlayer()) + 1)
        call TriggerSyncStart()
        call SyncStoredInteger(getTheHost, "missionKey", "key")
        call TriggerSyncReady()
        return Player(GetStoredInteger(getTheHost, "missionKey", "key") - 1)
    endfunction

This function was stolen!

I actually wrote that myself mate -.-. Syncing data up between players is pretty common knowledge... someone used this technique to get the delay of players.
 
Level 16
Joined
Oct 12, 2008
Messages
1,570
Something that might be handy to add:
the GET_PLAYER, GET_COMPUTER and GET_ALL take the integer you assign to it, right? Make versions of those that take a player or global player Id (meaning the one generated by GetPlayerId()), because i might not have those integers somewhere where i actually do need this function. I know it seems unlikely but it shouldnt be hard and might actually come in hand i think. Or just GetPlayerCustomId or whatever that returns the ID you assigned to it.

for the rest, this seems like a nice system, good job.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Yixx, originally there were things in this for getting a player using an id... but there's already a native for that =).

If you're going to loop, then just use the regular player array. If you want to attach data to a player, use the player's id. When you are looping, do GetPlayerId(PTN_GET_PLAYER(x)) to access you arrays =).
 
Level 11
Joined
Nov 4, 2007
Messages
337
I've got a system that does pretty much the same thing, but is able to do more things (I didn't post it in forums, just use it for me and myself):
It is able to return the highest number of all players.
And it is able to return how many players are still playing.

You should add these things.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Mine is also able to return how many players are playing and it can even get the highest player in the game (computer, player, or combination)

Tracks player and computer players through out the game

The key words are through out, meaning the variables are updated during the game.
JASS:
PTN_GET_PLAYER_COUNT()
will always return the proper total count of all players =).

As for getting the highest player in the game, the player arrays in the background are indexed in the most efficient way meaning that the players get scrambled after one player leaves.

If you can come up with a really good reason, I'll add it in =). It'd only be 2 lines of code for lowest and biggest.
 
Level 11
Joined
Nov 4, 2007
Messages
337
And what if sb wants to split up respoueces to all players and max player ID is 10, but 3 players play, really, you need two vars.
Also your function/variable naming is always horribly none-saying.
Please think clearly before starting to make a system, that really makes it less complicated and maybe it's designed better then.
This Is not bad, but I won't use it, because it's not very complex.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
You don't need a max player id... it's all indexed into an array...

PTN_GET_PLAYER(0)
PTN_GET_PLAYER(1)

Those aren't necessarily player 0 and player 1..

If you want to loop thru all players in the map, then just use 0 thru PTN_GET_PLAYER_COUNT()

if you want to get player via id, then use the GetPlayerId() native.

I don't know how you are using it, but GET_PLAYER does not take a player id =), it takes an internal index because it's kept sequential so that it can be used in loops. It's not meant to be used on specific players, it's meant to be used for all players =).

Again, there is absolutely no need for tracking the highest player id, lol...
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Found a bug in this ; o. It caused leaving players to not be registered except for Player 0. It was 1 line fix.

Increased the ini loop speed, so it should be faster.

Benchmark code to compare old method and new method of slot check
JASS:
include "cj_types.j"
include "cj_typesEx.j"
include "cj_print.j"
include "cj_types_priv.j"  
include "cj_typesEx_priv.j"
include "cj_order.j"  
include "cj_antibj_base.j"

scope Demo initializer Initialization {
    trigger t = CreateTrigger()
    event e = TriggerRegisterTimerEvent(t, 0, false)
    int sw, i = 5000; float mark
    
    bool Test() {
        sw = StopWatchCreate()
        do {
            if GetPlayerTeam(Player(0)) != -1 {} //.007
            //if GetPlayerSlotState(Player(0)) == PLAYER_SLOT_STATE_PLAYING {} //.011
        } whilenot --i == 0
        mark = StopWatchMark(sw)
        StopWatchDestroy(sw)
        printf(R2S(mark))
        return false
    }
    
    void Initialization() {
        TriggerAddCondition(t, Condition(function Test))
    }
}

Player 4 left.
Player count is 5.
Highest Player number is 6.

This wasn't working right because the trigger wasn't firing ^_^. It should be ok now ; p.

If player 4 leaves
Player count is 5

it'll go from this-

1 2 3 4 5 6

to this

1 2 3 6 5

4 is removed and the last player is put in it's place. This is why you can always loop through all the current players ^_^.
 
Level 11
Joined
Nov 4, 2007
Messages
337
This uses StopWatch.

Here:
JASS:
scope Tests initializer SetUp

    globals
        private HandleTable Data
    endglobals
    
private function test takes nothing returns nothing
    local timer t
    local integer i
    call TestHelper.NextInstance()

        if TestHelper.IsFinished() then
            call PauseTimer(GetExpiredTimer())
            call DestroyTimer(GetExpiredTimer())
            call Test.Compare()
            //call Test.createTable()
            return
        endif
    
        call Test.Start("PT","GetPlayer")
            call GetPlayer(0)
        call Test.End()
        
        call Test.Start("Native","Player")
            call Player(0)
        call Test.End()

endfunction

    function TestSC takes nothing returns nothing
        call TestHelper.SetTest(170,170)
        call TimerStart(CreateTimer(),0.,true,function test)
    endfunction
    
    private function SetUp takes nothing returns nothing
        set Data = HandleTable.create()
        call Test.Declare("PT")
        call Test.Declare("Native")
    endfunction

endscope
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Actually this stuff was benchmarked on TheHelper too and there were 3 different results, none of which are what you got -.-.

Result 1: Array is 33% faster
Result 2: The same or virtually the same
Result 3: Array is faster 7 out of 10 times


What we concluded was that in general, the array method is "slightly" better, but benchmarking tests are virtually inconclusive due to the nature of the JASS language : ).

For example, strings will screw up your results... etc.

This stuff was tested thoroughly and went through 12+ pages of debate


Now... for me it's not surprising that your results were way off base in regards to everyone else's. We all coded our stuff very specifically, inlined everything, and made it as tight as possible. You didn't.

Now it's either that or wc3 has had some major changes through the patches since these tests were done (1.24a I think).
 
Level 11
Joined
Nov 4, 2007
Messages
337
Ok.
I have redone the test.
Player Tracking is 5% faster than the native
Here is the code I used:

JASS:
        call Test.Start("PT","GetPlayer")
            set p = allPlayers[0]
        call Test.End()
        
        call Test.Start("Native","Player")
            set p = Player(0)
        call Test.End()

You can place the screen in the first post if you want to.
 

Attachments

  • Natives vs Nestharus 3.jpg
    Natives vs Nestharus 3.jpg
    546.9 KB · Views: 129
It's inline friendly -.-

vjass just fails now... I haven't seen it inline anything since like 1 version before Zinc...


I guess we wait until Vexorian fixes inlining or we can move to cJASS definitions (which will probably never happen) since they never let you down.

This isn't even doing inline-
JASS:
call GetComputerCount()

And that is just this
JASS:
    constant function GetComputerCount takes nothing returns integer
        return computerCount
    endfunction

Inliner is broken atm...

So yea, all code from jasshelper going to be extra slower until vex fixes

But go ahead and continue to blame it on me Malte. I know you love that.

Lol. Of course that's not going to inline. You can't just call a variable. If it did inline it'd end up as, simply,
JASS:
computerCount
which is obviously a syntax error.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
woops

Phase 1: import/novjass/delimited comments
Phase 2: text macros
Phase 3: Zinc
Phase 4: Libraries
Phase 5: Static ifs
Phase 6: Modules
Phase 7: Structs and many other things
Phase 8: PJass
Phase 9: Shadowhelper
Phase 10: PJass
Phase 11: Optimization (inline)

no wonder ^_^... I was checking via an error and optimization is done on the last phase so the inlining wouldn't have shown up ;o.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
You can look at the generated map script by going to
Code:
<Your NewGen Installation>\logs\outputWar3Map.j

I know how to look at generated map script : p. I actually looked at map script and went, oh it inlines.. that means it does a dif order. From there I proceeded to Zinc manual cuz I knew the order was somewhere in there, and lo and behold there it was : o. Optimization is done last : D.

I always just use MPQ Editor since it takes me one second as MPQ Editor already points to all the right places ;p.


Btw, cjass updated to 1.3 : ). Sevion was running into syntax errors, I investigated and found a mistake due to a one liner definition that was set up with multi line method (yea.. cjass needs to fix that bug).

Changed it to one liner definition to fix the issue and now it works : ).

Thank you sevion for notifying me ^_^.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
My benchmark was not broken.

you made mistakes too malte

function calls
use of strings

I don't think you used loops within the actual benchmarks, so that's one thing you did right : ). I don't want to open the map to find out because opening a map is a serious pain for me ><

So yea.. you had your mistakes too : ). You have no idea what strings do to running code ;o


The best method was to run a series of benchmarks and add them up, each benchmark maybe taking 10 results all exact operations with 0 extra calls. The loop would run outside of the benchmarking so that each operation was the exact system running : ). No strings until after the benchmarking took place and only one benchmark per run of the map as a previous benchmark could screw up results for following benchmarks. The computer has to be in the exact same state for each benchmark (making this entire effort futile ><).
 
Level 8
Joined
Oct 3, 2008
Messages
367
Yes it was. Look here.

JASS:
call Test.Start("PT","GetPlayer")
    call GetPlayer(0)
call Test.End()

call Test.Start("Native","Player")
    call Player(0)
call Test.End()

First flaw: those are not in separate functions called via TriggerExecute. Which means you can get weird results.

Second flaw: you call Player and GetPlayer, which means GetPlayer cannot inline like it should. So, GetPlayer should be even faster than your benchmark says it is.
 
Level 11
Joined
Nov 4, 2007
Messages
337
Yes it was. Look here.

JASS:
call Test.Start("PT","GetPlayer")
    call GetPlayer(0)
call Test.End()

call Test.Start("Native","Player")
    call Player(0)
call Test.End()

First flaw: those are not in separate functions called via TriggerExecute. Which means you can get weird results.

Second flaw: you call Player and GetPlayer, which means GetPlayer cannot inline like it should. So, GetPlayer should be even faster than your benchmark says it is.
Please read!
I directly inlined the GetPlayer function and the test.Start is just a synonym for StopWatchMark()
 
This is the only code I saw...
MapperMalte said:
JASS:
scope Tests initializer SetUp

    globals
        private HandleTable Data
    endglobals

private function test takes nothing returns nothing
    local timer t
    local integer i
    call TestHelper.NextInstance()

        if TestHelper.IsFinished() then
            call PauseTimer(GetExpiredTimer())
            call DestroyTimer(GetExpiredTimer())
            call Test.Compare()
            //call Test.createTable()
            return
endif

        call Test.Start("PT","GetPlayer")
            call GetPlayer(0)
        call Test.End()

        call Test.Start("Native","Player")
            call Player(0)
        call Test.End()

endfunction

    function TestSC takes nothing returns nothing
        call TestHelper.SetTest(170,170)
        call TimerStart(CreateTimer(),0.,true,function test)
    endfunction

    private function SetUp takes nothing returns nothing
        set Data = HandleTable.create()
        call Test.Declare("PT")
        call Test.Declare("Native")
    endfunction

endscope
 
Top