1. Join Texturing Contest #30 now in a legendary battle of mythological creatures!
    Dismiss Notice
  2. The Aftermath has been revealed for the 19th Terraining Contest! Be sure to check out the Results and see what came out of it.
    Dismiss Notice
  3. Melee Mapping Contest #3 - Results are out! Congratulate the winners and check plenty of new 4v4 melee maps designed for this competition!
    Dismiss Notice
  4. The winners of our cinematic soundtrack competition have been decided! Step by the Music Contest #11 - Results to check the entries and congratulate the winners!
    Dismiss Notice
  5. Check out the Staff job openings thread.
    Dismiss Notice

Fixing SmartCameraPanBJ Desync

Discussion in 'Trigger (GUI) Editor Tutorials' started by Daffa the Mage, Oct 20, 2013.

  1. Daffa the Mage

    Daffa the Mage

    Map Moderator

    Joined:
    Jan 30, 2013
    Messages:
    7,477
    Resources:
    26
    Packs:
    1
    Maps:
    8
    Spells:
    16
    Tutorials:
    1
    Resources:
    26
    Introduction of SmartCameraPanBJ
    This Guide is made to fix
    • Camera - Pan Camera as necessary (timed)
    As some of you may know, the function does desync on multiplayer maps (100% guaranteed).

    What is Desync? Desync is an event in multiplayer games where all players that plays (or some players, in that case it's possible to be a server split) become disconnected except the host itself.

    Solution (Recommended for Hasty People)
    Copy the code into the Map Header (the one above all triggers folders)
    Code (vJASS):
    function SmartCameraPanBJModified takes player whichPlayer, location loc, real duration returns nothing
        local real tx = GetLocationX(loc)
        local real ty = GetLocationY(loc)
        local real dx = tx - GetCameraTargetPositionX()
        local real dy = ty - GetCameraTargetPositionY()
        local real dist = SquareRoot(dx * dx + dy * dy)
        if (GetLocalPlayer() == whichPlayer) then
            if (dist >= bj_SMARTPAN_TRESHOLD_SNAP) then
                call PanCameraToTimed(tx, ty, 0)
                // Far away = snap camera immediately to point
            elseif (dist >= bj_SMARTPAN_TRESHOLD_PAN) then
                call PanCameraToTimed(tx, ty, duration)
                // Moderately close = pan camera over duration
            else
                // User is close, don't move camera
            endif
        endif
    endfunction


    to call the function :
    call SmartCameraPanBJModified( Player(), Location(), Timer() )

    Replace
    SmartCameraPanBJModified
    with your modified name.
    Remember,
    Player()
    is the Player,
    Location()
    is the target location and
    Timer()
    is the time amount for the pan.

    A recommendation for GUI Users is to set these 3 things into variables and call the function with those variables instead, ex (by PurgeandFire) :
    • Set TempPlayer = Player 1 (Red)
    • Set TempLoc = (Position of (Triggering unit))
    • Set TempDuration = 12.00
    • Custom script: call SmartCameraPanBJModified( udg_TempPlayer, udg_TempLoc, udg_TempDuration )
    Notes : Global Variables uses udg_VariableName in Jass, so don't miss them when calling the custom native!



    Explanation
    The Actual Problem with SmartCameraPanBJ
    SmartCameraPanBJ desyncs was a mystery, in GUI, this can't be solved, but the actual problem lies on how the function execute itself.
    Code (vJASS):
    function SmartCameraPanBJ takes player whichPlayer, location loc, real duration returns nothing
        local real dist
        if (GetLocalPlayer() == whichPlayer) then
            // Use only local code (no net traffic) within this block to avoid desyncs.

            set dist = DistanceBetweenPoints(loc, GetCameraTargetPositionLoc())
            if (dist >= bj_SMARTPAN_TRESHOLD_SNAP) then
                // If the user is too far away, snap the camera.
                call PanCameraToTimed(GetLocationX(loc), GetLocationY(loc), 0)
            elseif (dist >= bj_SMARTPAN_TRESHOLD_PAN) then
                // If the user is moderately close, pan the camera.
                call PanCameraToTimed(GetLocationX(loc), GetLocationY(loc), duration)
            else
                // User is close enough, so don't touch the camera.
            endif
        endif
    endfunction
     

    The code create location on local block (this one :
    set dist = DistanceBetweenPoints(loc, GetCameraTargetPositionLoc())
    ), which causes desync as location may not be created at local block


    How to solve this problem?

    It might looks complicated, but it's not THAT complicated. Read below to know how to fix it :

    The script below is the fixer for this issue (Credits to PurgeandFire) :
    Code (vJASS):
    function SmartCameraPanBJ takes player whichPlayer, location loc, real duration returns nothing
        local real tx = GetLocationX(loc)
        local real ty = GetLocationY(loc)
        local real dx = tx - GetCameraTargetPositionX()
        local real dy = ty - GetCameraTargetPositionY()
        local real dist = SquareRoot(dx * dx + dy * dy)
        if (GetLocalPlayer() == whichPlayer) then
            if (dist >= bj_SMARTPAN_TRESHOLD_SNAP) then
                call PanCameraToTimed(tx, ty, 0)
                // Far away = snap camera immediately to point
            elseif (dist >= bj_SMARTPAN_TRESHOLD_PAN) then
                call PanCameraToTimed(tx, ty, duration)
                // Moderately close = pan camera over duration
            else
                // User is close, don't move camera
            endif
        endif
    endfunction


    However, if you directly copy this script to your map header (or a trigger), it will causes map compiling to fail, there are 2 workaround to this :

    1. Copy the script to Map Header, to deal with the bug mentioned above, I recommend copy pasting this script instead :

    Code (vJASS):
    function SmartCameraPanBJModified takes player whichPlayer, location loc, real duration returns nothing
        local real tx = GetLocationX(loc)
        local real ty = GetLocationY(loc)
        local real dx = tx - GetCameraTargetPositionX()
        local real dy = ty - GetCameraTargetPositionY()
        local real dist = SquareRoot(dx * dx + dy * dy)
        if (GetLocalPlayer() == whichPlayer) then
            if (dist >= bj_SMARTPAN_TRESHOLD_SNAP) then
                call PanCameraToTimed(tx, ty, 0)
                // Far away = snap camera immediately to point
            elseif (dist >= bj_SMARTPAN_TRESHOLD_PAN) then
                call PanCameraToTimed(tx, ty, duration)
                // Moderately close = pan camera over duration
            else
                // User is close, don't move camera
            endif
        endif
    endfunction


    to call the function :
    call SmartCameraPanBJModified( Player(), Location(), Timer() )

    Replace
    SmartCameraPanBJModified
    with your modified name.
    Remember,
    Player()
    is the Player,
    Location()
    is the target location and
    Timer()
    is the time amount for the pan.

    A recommendation for GUI Users is to set these 3 things into variables and call the function with those variables instead, ex (by PurgeandFire) :
    • Set TempPlayer = Player 1 (Red)
    • Set TempLoc = (Position of (Triggering unit))
    • Set TempDuration = 12.00
    • Custom script: call SmartCameraPanBJModified( udg_TempPlayer, udg_TempLoc, udg_TempDuration )
    Notes : Global Variables uses udg_VariableName in Jass, so don't miss them when calling the custom native!

    2. Override the original script at blizzard.j then import it to the map. This will allow you to use the default native without issues, because blizzard.j from the map will be read by the game instead of the default.


    CREDITS
    PurgeandFire : The Fixing Script and Helping Me with the workaround
    Legal_Ease : On our test with http://www.hiveworkshop.com/forums/maps-564/high-road-aos-238438/?prev=status=p made by him, which let me to search for solutions once people point out the issue with
    SmartCameraPanBJ
    .

    ~Daffa the Mage
     
    Last edited: Dec 8, 2014
  2. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,419
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    It looks good. Although you should give a sample of using it in GUI. To make it friendly, you can probably use the variable technique, ex:
    Trigger
    • Set TempPlayer = Player 1 (Red)
    • Set TempLoc = (Position of (Triggering unit))
    • Set TempDuration = 12.00
    • Custom script: call SmartCameraPanBJModified( udg_TempPlayer, udg_TempLoc, udg_TempDuration )
    So that they only have to modify the variables, rather than modifying the actual code.

    You should also name the function differently in the example. I know you tell them to change it, but it'd be better if you change it to SmartCameraPanBJModified just so that there is a lower chance of error (for hasty people who don't like to read, or people who may be lost at what to name it/how JASS works).
     
  3. Daffa the Mage

    Daffa the Mage

    Map Moderator

    Joined:
    Jan 30, 2013
    Messages:
    7,477
    Resources:
    26
    Packs:
    1
    Maps:
    8
    Spells:
    16
    Tutorials:
    1
    Resources:
    26
    Modified as suggested.
    I hope I don't miss anything.

    EDIT :

    When I submit it as a Tutorial at Blizzard Modding, there's something else that I want to tell everyone.

     
    Last edited: Oct 23, 2013
  4. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,419
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Nice. Approved.

    And yeah, there used to be a snippet called "SmartCameraPanBJND" or "SmartCameraPanND" (ND = No Desync) on the old wc3jass. I believe it would be very fitting to make another snippet like that. :)
     
  5. Daffa the Mage

    Daffa the Mage

    Map Moderator

    Joined:
    Jan 30, 2013
    Messages:
    7,477
    Resources:
    26
    Packs:
    1
    Maps:
    8
    Spells:
    16
    Tutorials:
    1
    Resources:
    26
    I see, sadly wc3jass got shutdown and it's gone.
    Unless you have it somewhere in your data?

    anyway thanks for the approval, I hope this can be useful for people who usually get desync at their maps.
     
  6. Daffa the Mage

    Daffa the Mage

    Map Moderator

    Joined:
    Jan 30, 2013
    Messages:
    7,477
    Resources:
    26
    Packs:
    1
    Maps:
    8
    Spells:
    16
    Tutorials:
    1
    Resources:
    26
    *Tutorial Necromancy*
    Alright, some minor cleanup with the old Tutorial. I hope it's useful to some people.
    Also, if anyone would like to point out mistakes, I would be pleased to fix them.
     
  7. venger07

    venger07

    Joined:
    Dec 21, 2010
    Messages:
    429
    Resources:
    5
    Icons:
    4
    Maps:
    1
    Resources:
    5
    How to use pan camera without leak?

    I used this custom script " call SmartCameraPanBJModified( udg_TempPlayer, udg_TempLoc, udg_TempDuration ) " but it gave me an error saying "expected a function name"


    [EDIT] I removed "Modified" and it doesn't give an error anymore.. so the custom script should be like this
    call SmartCameraPanBJ( udg_TempPlayer, udg_TempLoc, udg_TempDuration )
     
  8. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,419
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    You have to put this script in your map header:
    Code (vJASS):
    function SmartCameraPanBJModified takes player whichPlayer, location loc, real duration returns nothing
        local real tx = GetLocationX(loc)
        local real ty = GetLocationY(loc)
        local real dx = tx - GetCameraTargetPositionX()
        local real dy = ty - GetCameraTargetPositionY()
        local real dist = SquareRoot(dx * dx + dy * dy)
        if (GetLocalPlayer() == whichPlayer) then
            if (dist >= bj_SMARTPAN_TRESHOLD_SNAP) then
                call PanCameraToTimed(tx, ty, 0)
                // Far away = snap camera immediately to point
            elseif (dist >= bj_SMARTPAN_TRESHOLD_PAN) then
                call PanCameraToTimed(tx, ty, duration)
                // Moderately close = pan camera over duration
            else
                // User is close, don't move camera
            endif
        endif
    endfunction


    Copy all of that, open your map, go to the trigger editor, click on the map's name in the upper left corner (above all the folders), and paste the code there. Then it should save without issues.

    And this tutorial's main purpose is to prevent a desync. If you use
    SmartCameraPanBJ
    , then your map will disconnect players. So you should not use it.
     
  9. Daffa the Mage

    Daffa the Mage

    Map Moderator

    Joined:
    Jan 30, 2013
    Messages:
    7,477
    Resources:
    26
    Packs:
    1
    Maps:
    8
    Spells:
    16
    Tutorials:
    1
    Resources:
    26
    Sorry for the late reply.
    Purge explains it well in his post.

    The SmartCameraPanBJ is the one which desync. The main code must exist in the map header as Purge states.

    Thanks bro :)