[How-To] Use get offset from entity in world coords on server side

This is an implementation of GetOffsetFromEntityInWorldCoords:

-- server.lua
function getEntityMatrix(element)
    local rot = GetEntityRotation(element) -- ZXY
    local rx, ry, rz = rot.x, rot.y, rot.z
    rx, ry, rz = math.rad(rx), math.rad(ry), math.rad(rz)
    local matrix = {}
    matrix[1] = {}
    matrix[1][1] = math.cos(rz)*math.cos(ry) - math.sin(rz)*math.sin(rx)*math.sin(ry)
    matrix[1][2] = math.cos(ry)*math.sin(rz) + math.cos(rz)*math.sin(rx)*math.sin(ry)
    matrix[1][3] = -math.cos(rx)*math.sin(ry)
    matrix[1][4] = 1
    
    matrix[2] = {}
    matrix[2][1] = -math.cos(rx)*math.sin(rz)
    matrix[2][2] = math.cos(rz)*math.cos(rx)
    matrix[2][3] = math.sin(rx)
    matrix[2][4] = 1
	
    matrix[3] = {}
    matrix[3][1] = math.cos(rz)*math.sin(ry) + math.cos(ry)*math.sin(rz)*math.sin(rx)
    matrix[3][2] = math.sin(rz)*math.sin(ry) - math.cos(rz)*math.cos(ry)*math.sin(rx)
    matrix[3][3] = math.cos(rx)*math.cos(ry)
    matrix[3][4] = 1
	
    matrix[4] = {}
    local pos = GetEntityCoords(element)
    matrix[4][1], matrix[4][2], matrix[4][3] = pos.x, pos.y, pos.z - 1.0
    matrix[4][4] = 1
	
    return matrix
end

function GetOffsetFromEntityInWorldCoords(entity, offX, offY, offZ)
    local m = getEntityMatrix(entity)
    local x = offX * m[1][1] + offY * m[2][1] + offZ * m[3][1] + m[4][1]
    local y = offX * m[1][2] + offY * m[2][2] + offZ * m[3][2] + m[4][2]
    local z = offX * m[1][3] + offY * m[2][3] + offZ * m[3][3] + m[4][3]
    return vector3(x, y, z)
end

The example below illustrates how to teleport a player always 5 units forward using only server side:

-- server/warp.lua
RegisterCommand("warp", function(source)
    local ped = GetPlayerPed(source)
    local coords = GetOffsetFromEntityInWorldCoords(ped, 0.0, 5.0, 0.0)
    SetEntityCoords(ped, coords.x, coords.y, coords.z)
end, false)
References:
  1. GetElementMatrix - Multi Theft Auto: Wiki
11 Likes

Same code in C# for anyone who needs it, save rewriting it. Cheers @draobrehtom.

/// <summary>
/// Credit to draobrehtom.
/// https://forum.cfx.re/t/p/4502297.
/// https://forum.cfx.re/u/draobrehtom.
/// </summary>
internal Vector3 GetOffsetFromEntityInWorldCoords(Entity entity, Vector3 offset)
{
    Vector3 position = entity.Position;
    Vector3 rotation = entity.Rotation;

    float rX = MathUtil.DegreesToRadians(rotation.X);
    float rY = MathUtil.DegreesToRadians(rotation.Y);
    float rZ = MathUtil.DegreesToRadians(rotation.Z);

    double cosRx = Math.Cos(rX);
    double cosRy = Math.Cos(rY);
    double cosRz = Math.Cos(rZ);
    double sinRx = Math.Sin(rX);
    double sinRy = Math.Sin(rY);
    double sinRz = Math.Sin(rZ);

    Matrix matrix = new()
    {
        M11 = (float)((cosRz * cosRy) - (sinRz * sinRx * sinRy)),
        M12 = (float)((cosRy * sinRz) + (cosRz * sinRx * sinRy)),
        M13 = (float)(-cosRx * sinRy),
        M14 = 1,

        M21 = (float)(-cosRx * sinRz),
        M22 = (float)(cosRz * cosRx),
        M23 = (float)sinRx,
        M24 = 1,

        M31 = (float)((cosRz * sinRy) + (cosRy * sinRz * sinRx)),
        M32 = (float)((sinRz * sinRy) - (cosRz * cosRy * sinRx)),
        M33 = (float)(cosRx * cosRy),
        M34 = 1,

        Row4 = new(position.X, position.Y, position.Z - 1f, 1f)
    };

    return new()
    {
        X = (offset.X * matrix.M11) + (offset.Y * matrix.M21) + (offset.Z * matrix.M31) + matrix.M41,
        Y = (offset.X * matrix.M12) + (offset.Y * matrix.M22) + (offset.Z * matrix.M32) + matrix.M42,
        Z = (offset.X * matrix.M13) + (offset.Y * matrix.M23) + (offset.Z * matrix.M33) + matrix.M43
    };
}

Same code in JS

function getEntityMatrix(entity) {
    let dtr = Math.PI/180

    let [x, y, z] = GetEntityCoords(entity)
    let [rx, ry, rz] = GetEntityRotation(entity);

    rx = rx * dtr
    ry = ry * dtr
    rz = rz * dtr

    let matrix = [
        [
            Math.cos(rz)*Math.cos(ry) - Math.sin(rz)*Math.sin(rx)*Math.sin(ry),
            Math.cos(ry)*Math.sin(rz) + Math.cos(rz)*Math.sin(rx)*Math.sin(ry),
            -Math.cos(rx)*Math.sin(ry),
            1
        ],
        [
            -Math.cos(rx)*Math.sin(rz),
            Math.cos(rz)*Math.cos(rx),
            Math.sin(rx),
            1
        ],
        [
            Math.cos(rz)*Math.sin(ry) + Math.cos(ry)*Math.sin(rz)*Math.sin(rx),
            Math.sin(rz)*Math.sin(ry) - Math.cos(rz)*Math.cos(ry)*Math.sin(rx),
            Math.cos(rx)*Math.cos(ry),
            1
        ],
        [
            x,
            y,
            z - 1.0,
            1
        ]
    ]
    
    return matrix
}


function GetOffsetFromEntityInWorldCoords (entity, offX, offY, offZ) {
    let m = getEntityMatrix(entity);
    let v = {
        x: offX * m[0][0] + offY * m[1][0] + offZ * m[2][0] + m[3][0],
        y: offX * m[0][1] + offY * m[1][1] + offZ * m[2][1] + m[3][1],
        z: offX * m[0][2] + offY * m[1][2] + offZ * m[2][2] + m[3][2]
    }

    return v;
}

Here it is in Lua if anyone needs it :slight_smile:

function GetOffsetFromEntityInWorldCoords(entity, offset)
    local position = GetEntityCoords(entity)
    local rotation = GetEntityRotation(entity)

    local rX = math.rad(rotation.x)
    local rY = math.rad(rotation.y)
    local rZ = math.rad(rotation.z)

    local cosRx = math.cos(rX)
    local cosRy = math.cos(rY)
    local cosRz = math.cos(rZ)
    local sinRx = math.sin(rX)
    local sinRy = math.sin(rY)
    local sinRz = math.sin(rZ)

    local matrix = {
        M11 = (cosRz * cosRy) - (sinRz * sinRx * sinRy),
        M12 = (cosRy * sinRz) + (cosRz * sinRx * sinRy),
        M13 = -cosRx * sinRy,
        M14 = 1,

        M21 = -cosRx * sinRz,
        M22 = cosRz * cosRx,
        M23 = sinRx,
        M24 = 1,

        M31 = (cosRz * sinRy) + (cosRy * sinRz * sinRx),
        M32 = (sinRz * sinRy) - (cosRz * cosRy * sinRx),
        M33 = cosRx * cosRy,
        M34 = 1,

        Row4 = {position.x, position.y, position.z}
    }

    return vector3(
        offset.x * matrix.M11 + offset.y * matrix.M21 + offset.z* matrix.M31 + matrix.Row4[1],
        offset.x * matrix.M12 + offset.y * matrix.M22 + offset.z* matrix.M32 + matrix.Row4[2],
        offset.x * matrix.M13 + offset.y * matrix.M23 + offset.z * matrix.M33 + matrix.Row4[3]
    )
end
1 Like