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

[JASS] Desync when trees are placed on Blight seam

Status
Not open for further replies.
Level 13
Joined
Jul 26, 2008
Messages
1,009
Alright, I have a map where a player can put down groves of trees on the map. It's fine until the player puts a grove of trees on the seam between the blight and the grass. This causes everyone to drop.


JASS:
function GetDoodadTypeAtPT takes location pt returns integer

    local real dd
    local real df
    local real ds
    local real dg
    local real rnd

    set udg_GUI_Misc_DoodadFillCount = udg_GUI_Misc_DoodadFillCount + 1
    
    if IsTerrainWalkable(GetLocationX(pt), GetLocationY(pt)) then    
        if IsTerrainBlended(pt) then
            set udg_TEMP_Integer = GetRandomInt(0,1)
            if udg_TEMP_Integer == 0 then
                return 'ATtr'
            else
                return 'FTtw'
            endif
        elseif IsTerrainUnderground(pt) then
            return 'GTsh'
        elseif IsTerrainDungeon(pt) then
            return 'DTsh'
        elseif IsTerrainOutland(pt) then
            return 'OTtw'
        elseif IsTerrainSunkenRuins(pt) then
            return 'ZTtw'
        elseif IsTerrainBarrens(pt) then
            return 'BTtw'
        elseif IsTerrainFall(pt) then
            return 'FTtw'
        elseif IsTerrainWinter(pt) then
            set udg_TEMP_Integer = GetRandomInt(0,1)
            if udg_TEMP_Integer == 0 then
                return 'WTst'
            else
                return 'WTtw'
            endif
        elseif IsTerrainForest1(pt) then
            return 'CTtr'
        elseif IsTerrainForest2(pt) then
            return 'ATtr'
        elseif IsTerrainCity1(pt) then
            return 'LTlt'
        elseif IsTerrainCity2(pt) then
            return 'YTct'
        elseif IsTerrainCity3(pt) then
            return 'JTtw'
        
        endif
         return 'ATtr'
    endif
 return 0
endfunction

function DoodadFillArea takes rect area, boolean circle returns nothing

    local real inc = 150
    local real x
    local real y
    local location pt
    local integer dd

    //normalize value to multiple of 150 of world coords to prevent tree seams
    set x = I2R(R2I(GetRectMinX(area) / 150)) * 150
    loop
        exitwhen x > GetRectMaxX(area)
        set y = I2R(R2I(GetRectMinY(area) / 150)) * 150
        loop
            exitwhen y > GetRectMaxY(area)
                set pt = Location(x + GetRandomReal(-inc/5, inc/5),y + GetRandomReal(-inc/5, inc/5) + ModuloInteger(R2I(x / inc), 2) * inc / 2)
                set dd = GetDoodadTypeAtPT(pt)

                if GetBooleanOr(not(circle), DistanceBetweenPoints(pt, GetRectCenter(area)) <= (GetRectMaxX(area) - GetRectMinX(area))/2) then

                    call CreateDestructableLoc( dd, pt, GetRandomReal(0, 360), 1, GetDoodadVariation(dd) )
                    call KillDestructable( GetLastCreatedDestructable() )
                    call DestructableRestoreLife( GetLastCreatedDestructable(), GetDestructableMaxLife(GetLastCreatedDestructable()), true )

                    if DistanceBetweenPoints(GetDestructableLoc(GetLastCreatedDestructable()), pt) > 100 then
                        call RemoveDestructable(GetLastCreatedDestructable())
                    endif
                endif

                // (prevent trigger from being stopped and prevent game desync(<-?))
                set udg_GUI_Misc_DoodadFillCount = udg_GUI_Misc_DoodadFillCount + 1
                if udg_GUI_Misc_DoodadFillCount > 500 then
                    set udg_GUI_Misc_DoodadFillCount = 0
                    call TriggerSleepAction(0)
                endif
                
                call RemoveLocation(pt)
            set y = y + inc
        endloop
        set x = x + inc
    endloop

endfunction

JASS:
function OnPointerSmart takes location pt, player pl, boolean isunit returns nothing

    local integer id
    local force fp
    local location loc
    local location loc2
    local integer dt
    local integer goldleft
    local integer junk
    local group grp

    set id = GetConvertedPlayerId(pl)
    set fp = bj_FORCE_PLAYER[id-1]

    if udg_Status[id] == "doodad_create" then
        
        if udg_DM_SubType[id] == "grove" then
            call DoodadFillArea(RectFromCenterSizeBJ(pt, RealBrushSize[id], RealBrushSize[id]), true)

...

It's detected when the PointerHero does something like Smart order, Attack, Patrol, etc.

JASS:
    elseif (GetTriggerUnit() == GUI_D_P_Grove) then

        set udg_Status[id] = "doodad_create"
        set udg_DM_SubType[id] = "grove"
        call GUIApplyCamForDM(pl)

        call LeaderboardSetPlayerItemLabelBJ( ConvertedPlayer(4), udg_Board[id], "|cFFFFFFFF-> '|r|c0000FF00" + udg_DM_SubType[id] + "|r|cFFFFFFFF'|r" )
        call SelectUnitForPlayerSingle( udg_GUI_Pointer[id], pl )
        call DisplayTextToForce( fp, "    Right click to create a '|c0000FF00" + udg_DM_SubType[id] + "|r'." )

And this happens when you click a little thing called Grove. These are the steps that allow you to create these groves and the desync lies within. Hopefully someone can help, thanks :3

My theory is that the seam creates inconsistent tree types between the players, causing them to recieve different packets of information and blam. Desync. That or the blight can't decide what type of trees to make underneath it and goes boom. I'm wondering how to fix or solve it. Hell, is there even a way to prevent creation of trees between this area?

EDIT: Alright further testing seems to prove that when the tree is DIRECTLY on the blight and the non-blighted terrain it causes desync. Any help or fix for this?
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
So if I make a new map and create a destructable at run-time on the seam between blighted and non-blighted terrain it will cause a desync? There are many games that create/destroy trees frequently over all sorts of variations of terrain without any multiplayer issues. The first things that come to mind are:
  • The fog-of-war is causing the destructables to appear differently to different players.
  • The type of destructable that is created somehow varies for one or a few players, causing a desync.

When the map is initialized the destructables are created with the positioning/sizing/data that the editor placed objects were. If what you say is true then whenever a game is initialized that has blight in it there is a possible chance that the game will desync if the trees that run along the seam of the blight happen to vary from player-to-player (or at least player-to-host). I am quite certain that is not the case - but I want to see what exactly the problem here is.

If you could either post more code, or a link to a download of your map it would be very helpful in figuring out what is causing your game to desync. I am quite certain it is not destructable creation.
 
Level 13
Joined
Jul 26, 2008
Messages
1,009
http://www.hiveworkshop.com/forums/1663974-post14.html

That right there is the version of the map I'd prefer used for BNet testing.

I'll pastebin and throw up an unprotected version for you though incase you want to check the entirity of the code.

http://www.hiveworkshop.com/forums/pastebin.php?id=q08utg

The trigger Map Script holds part. The rest is held in the Pointer trigger and the Doodad trigger. There's a trigger to create terrain as well.

I think you might be right about the Fog of War. It's a good possibility. But there are some problems with it. The three DMs have vision of the entire map. When DM 1 drops the desync tree it desnycs them both.

The map also has the power to change terrain in multiple locations. This isn't likely to cause desyncs though. Still if there's any extra info you need I'll throw it your way and point you in the right direction.

To get this problem to show, create blight in an area by typing Blight, then type Grove and place it along the borders of the blight. It should desync.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
The map also has the power to change terrain in multiple locations. This isn't likely to cause desyncs though

Yes it does. Terrain deformations can cause desyncs in rare (but relatively common) occasions. If you're creating your own terrain and then placing destructables on-top of it then the fact that you're changing the terrain may cause the resulting destructable to be a blighted one for one player, and a non-blighted one for another (because of the fog-of-war, I believe).

To get this problem to show, create blight in an area by typing Blight, then type Grove and place it along the borders of the blight. It should desync.

To get the problem to show I'll also need an online tester; or else I personally won't know that the game is in desync.
 
Level 13
Joined
Jul 26, 2008
Messages
1,009
I can show you tomorrow around 14:00 (-7 MTN Standard Time). I will either have a friend host or I'll use a bot from my friend.

If the terrain is a result of fog of war, it would seem odd that the two who don't have fog of war end up desyncing from each other. But there is always the chance it's something along these lines. A sure fire way to test it is remedy for this problem. However, how should I remedy if this is indeed the problem?

Also the feature not so much terrain deformation (though that may come soon) as much as it is painting the terrain a different style. However this problem has only popped up under my new coding and did not occur in the old system of using rects to detect tree placement.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
as much as it is painting the terrain a different style.

Exactly, so if you're painting the terrain as blight for one player a different player may not experience that change and it could end up causing a desync for everybody. It may even not just be the terrain painting, it could be a combination of that and destructables that are created on painted terrain.

What I would first recommend is to try and test it with absolutely no fog of war, for anybody:

JASS:
call FogEnable(false)
call FogMaskEnable(false)
 
Level 13
Joined
Jul 26, 2008
Messages
1,009
The ability to blight an area has always been in. The desyncs have not. However the old system use to check what region the tree was being placed in.

I was thinking about changing it from checking what terrain the trees are being placed on to allowing players to select what tree they are putting down.

Perhaps the blight is creating a Sunken Ruins tree for one player and an Ashenvale tree for another when they're placed on the blight due to the terrain checker bringing back inconsistent values? If this is the case than it can be remedied by not checking the terrain on the ground but rather placing all of one tree.

I will check both methods, the tree and the AllFog, and return with results.
 
Status
Not open for further replies.
Top