Skip to content
KCKingdoms Connected Scripting APIScripting guides and API
GuideMaintainer authored

Positions, rotations and vectors

Work with the world's Z-up axes, Vector3 and Quaternion, turn a facing into a heading, and place things in front of a player.

Positions are Vector3 values in metres; rotations are Quaternion values. The world is CryEngine’s: Z is up, X and Y lie on the ground, and an entity with the identity rotation faces +Y.

// server
Events.on("playerCommand", (player, command) => {
if (command !== "where") return;
const { x, y, z } = player.position;
Chat.sendToPlayer(player, `${x.toFixed(1)}, ${y.toFixed(1)}, height ${z.toFixed(1)}`);
});

new Vector3(x, y, z) makes one. Anywhere the API takes a position it also accepts any { x, y, z } object, handy for coordinates in a config file.

Members Behaviour
add, sub, mul, div, normalize, cross, lerp, set Change the vector in place and return it. clone() first to keep the original.
dot, distance Return a number; change nothing.
length, lengthSquared Read-only properties.
// server
const ahead = player.position.clone().add(new Vector3(0, 5, 0));

a.distance(b) is straight-line. For reach checks you usually want ground distance, so a player on a roof is not “far” from someone below:

// server
function within(a: Vector3, b: Vector3, metres: number): boolean {
const dx = a.x - b.x;
const dy = a.y - b.y;
return dx * dx + dy * dy <= metres * metres; // no square root needed
}

Everything that takes a rotation (player.spawn, Horse.spawn, Prop.spawn, npc.teleport…) accepts either:

  • a Quaternion, or
  • a Vector3 of Euler angles in degrees. On flat ground only z matters: new Vector3(0, 0, 90) turns 90 degrees counterclockwise seen from above, facing -X.

Reading entity.rotation gives a Quaternion, but it is declared Quaternion | Vector3 because you may assign either. Cast the read: player.rotation as Quaternion.

Quaternion API Notes
new Quaternion(w, x, y, z) Scalar first. new Quaternion(1, 0, 0, 0) and Quaternion.identity() are the identity. Works in radians.
Quaternion.fromAxisAngle(new Vector3(0, 0, 1), radians) Turns an entity on the spot.
q.rotateVector(v) Returns a new rotated vector. On (0, 1, 0) it gives the facing.
q.mul(other), q.slerp(other, t) Compose in place; blend toward another.
q.toEuler() The heading is in its z component.

For where a player is looking rather than where their body faces, read player.lookDirection: a world-space direction, zero until their client reports one.

The default gamemode keeps these helpers in src/server/place.ts and uses them for every command that puts something down. Copy them whole:

src/server/place.ts
/** The entity's facing flattened onto the ground, so looking up or down does not shorten it. */
export function groundForward(rotation: Quaternion): Vector3 {
const facing = rotation.rotateVector(new Vector3(0, 1, 0));
const length = Math.sqrt(facing.x * facing.x + facing.y * facing.y);
return length < 1e-4 ? new Vector3(0, 1, 0) : new Vector3(facing.x / length, facing.y / length, 0);
}
/** The yaw-only rotation whose entity forward is this direction on the ground. */
export function yawTowards(directionX: number, directionY: number): Quaternion {
return Quaternion.fromAxisAngle(new Vector3(0, 0, 1), Math.atan2(-directionX, directionY));
}
export interface Placement {
position: Vector3;
rotation: Quaternion;
}
/** `distance` metres in front of the player, turned back towards them. `lift` raises it off the ground. */
export function inFrontOf(player: Player, distance: number, lift: number = 0): Placement {
const ahead = groundForward(player.rotation as Quaternion);
const from = player.position;
return {
position: new Vector3(from.x + ahead.x * distance, from.y + ahead.y * distance, from.z + lift),
rotation: yawTowards(-ahead.x, -ahead.y),
};
}

Math.atan2(-x, y) is a ground direction’s heading in radians, from +Y counterclockwise: the inverse of rotating (0, 1, 0) about Z.

src/server/horse.ts
import { inFrontOf } from "./place.js";
Events.on("playerCommand", (player, command) => {
if (command !== "horse") return;
if (!player.ready) return; // position is still the world origin
const spot = inFrontOf(player, 3);
Horse.spawn(spot.position, spot.rotation);
});