I'd like to emphasize on how to use GetLocalPlayer correctly, without desync.
This will desync;
-
Actions
-

Custom script: if GetLocalPlayer() == Player(0) then
-

Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
-

Custom script: endif
This won't desync;
-
Actions
-

Set UnitType = No unit-type
-

Custom script: if GetLocalPlayer() == Player(0) then
-

Set UnitType = Footman
-

Custom script: endif
-

Unit - Create 1 UnitType for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
Do you see the difference ?
In trigger 1, the function is directly being called inside the GetLocalPlayer block, which it will perform exclusively for that Player only.
While on trigger 2, the only action inside the GetLocalPlayer block is the setting of variable which is equal to the unit-type that you want to spawn.
But first, we must make the Unit-type to become null outside the GetLocalPlayer block.
Why we did this ?
It is because once we set it to null for
All Players and set it to certain unit-type for
certain player, we just call the function
outside the GetLocalPlayer block and everything will run fine.
What happens outside the block ?
Well, it basically will create a Footman (let's say you set it to Footman), for Player 1 (which is Player(0) in JASS) but it will create a null unit of the unit-type for all other players.
This still calls a global function instead of local ones, but the function applies follows to the variable sets in both outside and inside GetLocalPlayer block - which won't cause desync because
you call the function outside the GetLocalPlayer block which makes the trigger to not localized to only 1 Player, but to All Players as well.