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

GetLocationZ asynchronous when?

Antares

Spell Reviewer
Level 22
Joined
Dec 13, 2009
Messages
519
Hello,

I was working on my ground movement physics when @Bawbz reminded me that GetLocationZ can cause desyncs, which I had completely forgotten about. However, the Simple Entity Engine uses GetLocationZ with abandon and I was surprised that I didn't find a mention of any potential issues in the thread discussion.

According to doomsheep, GetLocationZ only desyncs with terrain deformations (thunderclap/shockwave), but otherwise is fine.

I found some threads from around 3-4 years ago which discuss the feasibility of syncing a terrain height map across players, for example here, but there didn't seem to be a lot of progress in this regard, and because I didn't find any newer threads, this seems to be an unsolved issue?

If terrain deformations (and maybe some other stuff) causes the desyncs, wouldn't it be sufficient to simply precompute the terrain height field on map initialization and use that for all future calculations?

If even that isn't safe, the next step would be to precompute the height map into a data file and load that file into the map.

A related question: is UnitGetFlyHeight synchronous?

Thanks for any info!
 

Cokemonkey11

Spell Reviewer
Level 30
Joined
May 9, 2006
Messages
3,540

Cokemonkey11

Spell Reviewer
Level 30
Joined
May 9, 2006
Messages
3,540

Antares

Spell Reviewer
Level 22
Joined
Dec 13, 2009
Messages
519
Being accurate with terrain deformations isn't really my priority, more concerned about preventing any type of desync. If precomputing the height map will achieve that, that's good enough for me.

I wrote this function to get the terrain height at any point on the map. It's actually twice as fast as the traditional method.

Lua:
    function GetTerrainZ(x, y)
        local rx = (x - worldMinX)/128 + 1
        local ry = (y - worldMinY)/128 + 1
        local i = rx // 1
        local j = ry // 1
        rx = rx - i
        ry = ry - j
        if i < 1 then
            i = 1
            rx = 0
        elseif i > iMax then
            i = iMax
            rx = 1
        end
        if j < 1 then
            j = 1
            ry = 0
        elseif j > iMax then
            j = jMax
            ry = 1
        end
        if rx + ry > 1 then --In top-right triangle
            return (rx + ry - 1)*heightMap[i+1][j+1] + ((1 - rx)*heightMap[i][j+1] + (1 - ry)*heightMap[i+1][j])
        else
            return (1 - rx - ry)*heightMap[i][j] + (rx*heightMap[i+1][j] + ry*heightMap[i][j+1])
        end
    end
 
Last edited:
Level 2
Joined
Sep 3, 2023
Messages
6
Being accurate with terrain deformations isn't really my priority, more concerned about preventing any type of desync. If precomputing the height map will achieve that, that's good enough for me.

I wrote this function to get the terrain height at any point on the map. It's actually twice as fast as the traditional method.

Lua:
    function GetTerrainZ(x, y)
        local rx = (x - worldMinX)/128 + 1
        local ry = (y - worldMinY)/128 + 1
        local i = rx // 1
        local j = ry // 1
        rx = rx - i
        ry = ry - j
        if i < 1 then
            i = 1
            rx = 0
        elseif i > iMax then
            i = iMax
            rx = 1
        end
        if j < 1 then
            j = 1
            ry = 0
        elseif j > iMax then
            j = jMax
            ry = 1
        end
        if rx + ry > 1 then --In top-right triangle
            return (rx + ry - 1)*heightMap[i+1][j+1] + ((1 - rx)*heightMap[i][j+1] + (1 - ry)*heightMap[i+1][j])
        else
            return (1 - rx - ry)*heightMap[i][j] + (rx*heightMap[i+1][j] + ry*heightMap[i][j+1])
        end
    end
Did you mean it's faster than:
JASS:
function GetLocZ takes real x, real y returns real
    call MoveLocation(LOC, x, y)
    return GetLocationZ(LOC)
endfunction

How accurate is it compared to the MoveLocation? Looks like it would be more accurate if there are more cell segmentations of the map.
 

Antares

Spell Reviewer
Level 22
Joined
Dec 13, 2009
Messages
519
Did you mean it's faster than:
JASS:
function GetLocZ takes real x, real y returns real
    call MoveLocation(LOC, x, y)
    return GetLocationZ(LOC)
endfunction
That's the one! Yea, two native calls are definitely more expensive than a few lines of Lua code. That's kinda the funny thing, that in JASS you'd always want to use natives to solve a problem if you can. In Lua, it seems to me that it's the other way around, because Lua is so much faster, but when it comes to native calls, there's almost no difference.

How accurate is it compared to the MoveLocation? Looks like it would be more accurate if there are more cell segmentations of the map.
It's 100% accurate. You have to parse the terrain height at every 128 tile grid point. If you look at the terrain in the editor, each 128x128 tile is divided into two triangles. Those triangles are completely flat and you can simply interpolate the height. That's what my code does:
1. Find the bottom-left corner of the tile your queried coordinates are in.
2. Find out if you're in the top-right or bottom-left triangle.
3. Interpolate the height based on the three grid points that touch the triangle.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
GetLocationZ returns the client local terrain height used to place objects on the terrain. This means it will factor in terrain deformations and walkable destructables. Neither terrain deformations or walkable destructables are synchronised between clients, resulting in it having the potential to return different values for each client leading to a desync. For example a destructable might be at a different animation state between clients, or one client might have terrain deformations set to a lower quality than the other. It might even tie with frame rate and animation interpolation, but I am not sure.

Warcraft III is not really a 3D game. Although it looks 3D and terrain even has height, the simulation is largely run in the 2D XY plane with Z being mostly for visuals. This can be seen with several standard abilities that fire projectiles with a set speed (not impact time). The speed is usually relative to the XY plane meaning that the visible speed of the projectile changes depending if it is fired flat, or having to change Z height a lot while the time to impact remains the same at the same XY distance.
 
Top