unreal.js
Version:
A pak reader for games like VALORANT & Fortnite written in Node.JS
471 lines (470 loc) • 15.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FVector = void 0;
const FArchive_1 = require("../../../reader/FArchive");
const FVector2D_1 = require("./FVector2D");
const FVector4_1 = require("./FVector4");
const FColor_1 = require("./FColor");
const FIntVector_1 = require("./FIntVector");
const FIntPoint_1 = require("./FIntPoint");
const Const_1 = require("../../../../util/Const");
const UnrealMathUtility_1 = require("./UnrealMathUtility");
/** Allowed error for a normalized vector (against squared magnitude) */
const THRESH_VECTOR_NORMALIZED = 0.01;
/**
* Represents an UE4 FVector
* @implements {IStructType}
*/
class FVector {
/** DO NOT USE THIS CONSTRUCTOR, THIS IS FOR THE LIBRARY */
constructor(arg1, arg2, arg3) {
if (typeof arg1 === "number" && !arg2) {
this.x = arg1;
this.y = arg1;
this.z = arg1;
}
else if (arg1 instanceof FArchive_1.FArchive) {
this.x = arg1.readFloat32();
this.y = arg1.readFloat32();
this.z = arg1.readFloat32();
}
else if (arg1 instanceof FVector4_1.FVector4) {
this.x = arg1.x;
this.y = arg1.y;
this.z = arg1.z;
}
else if (arg1 instanceof FColor_1.FLinearColor) {
this.x = arg1.r;
this.y = arg1.g;
this.z = arg1.b;
}
else if (arg1 instanceof FIntVector_1.FIntVector) {
this.x = arg1.x;
this.y = arg1.y;
this.z = arg1.z;
}
else if (arg1 instanceof FIntPoint_1.FIntPoint) {
this.x = arg1.x;
this.y = arg1.y;
this.z = 0;
}
else if (arg1 instanceof FVector2D_1.FVector2D && typeof arg2 === "number") {
this.x = arg1.x;
this.y = arg1.y;
this.z = arg2;
}
else if (arg1 == null) {
this.x = 0;
this.y = 0;
this.z = 0;
}
else {
this.x = arg1;
this.y = arg2;
this.z = arg3;
}
}
/**
* Serializes this
* @param {FArchiveWriter} Ar Writer to use
* @returns {void}
* @public
*/
serialize(Ar) {
Ar.writeFloat32(this.x);
Ar.writeFloat32(this.y);
Ar.writeFloat32(this.z);
}
/**
* Turns this into json
* @returns {any} Json
* @public
*/
toJson() {
return {
x: this.x,
y: this.y,
z: this.z
};
}
/**
* Copy another FVector into this one
* @param {FVector} other The other vector
* @returns {FVector} Reference to vector after copy
* @public
*/
set(other) {
this.x = other.x;
this.y = other.y;
this.x = other.x;
return this;
}
/**
* Calculate cross product between this and another vector
* @param {FVector} v The other vector
* @returns {FVector} The cross product
* @public
*/
xor(v) {
return new FVector(this.y * v.z - this.z * v.y, this.z * v.x - this.x * v.z, this.x * v.y - this.y * v.x);
}
/**
* Calculate the dot product between this and another vector
* @param {FVector} v The other vector
* @returns {number} The dot product
* @public
*/
or(v) {
return this.x * v.x + this.y * v.y + this.z * v.z;
}
/** DO NOT USE THIS METHOD, THIS IS FOR THE LIBRARY */
"+"(arg) {
if (arg instanceof FVector)
return new FVector(this.x + arg.x, this.y + arg.y, this.z + arg.z);
return new FVector(this.x + arg, this.y + arg, this.z + arg);
}
/** DO NOT USE THIS METHOD, THIS IS FOR THE LIBRARY */
"-"(arg) {
if (arg instanceof FVector)
return new FVector(this.x - arg.x, this.y - arg.y, this.z - arg.z);
return new FVector(this.x - arg, this.y - arg, this.z - arg);
}
/** DO NOT USE THIS METHOD, THIS IS FOR THE LIBRARY */
"*"(arg) {
if (arg instanceof FVector)
return new FVector(this.x * arg.x, this.y * arg.y, this.z * arg.z);
return new FVector(this.x * arg, this.y * arg, this.z * arg);
}
/** DO NOT USE THIS METHOD, THIS IS FOR THE LIBRARY */
"/"(arg) {
if (arg instanceof FVector)
return new FVector(this.x / arg.x, this.y / arg.y, this.z / arg.z);
const rScale = 1 / arg;
return new FVector(this.x * rScale, this.y * rScale, this.z * rScale);
}
/** DO NOT USE THIS METHOD, THIS IS FOR THE LIBRARY */
equals(x, y) {
if (x instanceof FVector && y != null) {
return Math.abs(this.x - x.x) <= y
&& Math.abs(this.y - x.y) <= y
&& Math.abs(this.z - x.z) <= y;
}
else {
if (this === x)
return true;
if (!(x instanceof FVector))
return false;
return this.x === x.x
&& this.y === x.y
&& this.z === x.y;
}
}
/**
* Checks Whether all components are equal
* @param {number} tolerance Tolerance to use
* @returns {boolean}
* @public
*/
allComponentsEqual(tolerance = Const_1.KINDA_SMALL_NUMBER) {
return Math.abs(this.x - this.y) <= tolerance
&& Math.abs(this.x - this.z) <= tolerance
&& Math.abs(this.y - this.z) <= tolerance;
}
/**
* Get a negated copy of the vector
* @returns {FVector} A negated copy of the vector
* @public
*/
unaryMinus() {
return new FVector(-this.x, -this.y, -this.z);
}
/**
* Adds another vector to this
* Uses component-wise addition
* @param {FVector} v Vector to add to this
* @returns {void}
* @public
*/
"+="(v) {
this.x += v.x;
this.y += v.y;
this.z += v.z;
}
/**
* Subtracts another vector from this
* Uses component-wise subtraction
* @param {FVector} v Vector to subtract from this
* @returns {void}
* @public
*/
"-="(v) {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
}
/** DO NOT USE THIS METHOD, THIS IS FOR THE LIBRARY */
"*="(arg) {
if (arg instanceof FVector) {
this.x *= arg.x;
this.y *= arg.y;
this.z *= arg.z;
}
this.x *= arg;
this.y *= arg;
this.z *= arg;
}
/**
* Divides the vector by a number
* @param {FVector} v What to divide this vector by
* @returns {void}
* @public
*/
"/="(v) {
this.x /= v.x;
this.y /= v.y;
this.z /= v.z;
}
/**
* Gets specific component of the vector
* @param {number} index the index of vector component
* @returns {number} Copy of the component
* @throws {RangeError} If index is < 0 or > 2
* @public
*/
get(index) {
if (index === 0)
return this.x;
if (index === 1)
return this.y;
if (index === 2)
return this.z;
throw new RangeError(`Received index: ${index}, but max./min. index: 2/0`);
}
/**
* Sets specific component of the vector
* @param {number} index the index of vector component
* @param {number} value the new value of vector component
* @returns {void}
* @throws {RangeError} If index is < 0 or > 2
* @public
*/
set0(index, value) {
if (index === 0)
this.x = value;
if (index === 1)
this.y = value;
if (index === 2)
this.z = value;
throw new RangeError(`Received index: ${index}, but max./min. index: 2/0`);
}
/**
* Set the values of the vector directly
* @param {number} x New X coordinate
* @param {number} y New Y coordinate
* @param {number} z New Z coordinate
* @returns {void}
* @public
*/
set1(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
/**
* Get the maximum value of the vector's components
* @returns {number} The maximum value of the vector's components
* @public
*/
getMax() {
return Math.max(Math.max(this.x, this.y), this.z);
}
/**
* Get the maximum absolute value of the vector's components
* @returns {number} The maximum absolute value of the vector's components
* @public
*/
getAbsMax() {
return Math.max(Math.max(Math.abs(this.x), Math.abs(this.y)), Math.abs(this.z));
}
/**
* Get the minimum value of the vector's components
* @returns {number} The minimum value of the vector's components
* @public
*/
getMin() {
return Math.min(Math.min(this.x, this.y), this.z);
}
/**
* Get the minimum absolute value of the vector's components
* @returns {number} The minimum absolute value of the vector's components
* @public
*/
getAbsMin() {
return Math.min(Math.min(Math.abs(this.x), Math.abs(this.y)), Math.abs(this.z));
}
/**
* Gets the component-wise min of two vectors
* @param {FVector} other Other FVector
* @returns {FVector} New instance
* @public
*/
componentMin(other) {
return new FVector(Math.min(this.x, other.x), Math.min(this.y, other.y), Math.min(this.z, other.z));
}
/**
* Gets the component-wise max of two vectors
* @param {FVector} other Other FVector
* @returns {FVector} New instance
* @public
*/
componentMax(other) {
return new FVector(Math.max(this.x, other.x), Math.max(this.y, other.y), Math.max(this.z, other.z));
}
/**
* Get a copy of this vector with absolute value of each component
* @returns {FVector} A copy of this vector with absolute value of each component
* @public
*/
getAbs() {
return new FVector(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z));
}
/**
* The length (magnitude) of this vector
* @type {number}
* @public
*/
get size() {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}
/**
* The squared length of this vector
* @type {number}
* @public
*/
get sizeSquared() {
return this.x * this.x + this.y * this.y + this.z * this.z;
}
/**
* The length of the 2D components of this vector
* @type {number}
* @public
*/
get size2D() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
/**
* The squared length of the 2D components of this vector
* @type {number}
* @public
*/
get sizeSquared2D() {
return this.x * this.x + this.y * this.y;
}
/**
* Checks whether vector is near to zero within a specified tolerance
* @param {number} tolerance Error tolerance
* @returns {boolean} Whether the vector is near to zero, false otherwise
* @public
*/
isNearlyZero(tolerance = Const_1.KINDA_SMALL_NUMBER) {
return Math.abs(this.x) <= tolerance && Math.abs(this.y) <= tolerance && Math.abs(this.z) <= tolerance;
}
/**
* Whether all components of the vector are exactly zero
* @type {boolean}
* @public
*/
get isZero() {
return this.x === 0 && this.y === 0 && this.z === 0;
}
/**
* Check if the vector is of unit length, with specified tolerance
* @param {number} lengthSquaredTolerance Tolerance against squared length
* @returns {boolean} Whether the vector is a unit vector within the specified tolerance
* @public
*/
isUnit(lengthSquaredTolerance = Const_1.KINDA_SMALL_NUMBER) {
return Math.abs(1 - this.sizeSquared) < lengthSquaredTolerance;
}
/**
* Whether vector is normalized
* @type {boolean}
* @public
*/
get isNormalized() {
return Math.abs(1 - this.sizeSquared) < THRESH_VECTOR_NORMALIZED;
}
// TODO port more methods
/**
* Get a textual representation of this vector
* @returns {string} A string describing the vector
* @public
*/
toString() {
return `X=${this.x.toLocaleString()} Y=${this.y.toLocaleString()} Z=${this.z.toLocaleString()}`;
}
/**
* Squared distance between two points
* @param {FVector} other The other point
* @returns {number} The squared distance between two points
* @public
*/
distSquared(other) {
return UnrealMathUtility_1.square(other.x - this.x) + UnrealMathUtility_1.square(other.y - this.y);
}
/**
* Calculate the cross product of two vectors
* @param {FVector} a The first vector
* @param {FVector} b The second vector
* @returns {number} The cross product
* @public
*/
static crossProduct(a, b) {
return a.xor(b);
}
/**
* Calculate the dot product of two vectors
* @param {FVector} a The first vector
* @param {FVector} b The second vector
* @returns {number} The dot product
* @public
*/
static dotProduct(a, b) {
return a.or(b);
}
/**
* Util to calculate distance from a point to a bounding box
* @param {FVector} mins 3D Point defining the lower values of the axis of the bound box
* @param {FVector} maxs 3D Point defining the lower values of the axis of the bound box
* @param {FVector} point 3D position of interest
* @returns {number} the distance from the Point to the bounding box
* @public
* @static
*/
static computeSquaredDistanceFromBoxToPoint(mins, maxs, point) {
// Accumulates the distance as we iterate axis
let distSquared = 0;
// Check each axis for min/max and add the distance accordingly
// NOTE: Loop manually unrolled for > 2x speed up
if (point.x < mins.x) {
distSquared += (point.x - mins.x) * (point.x - mins.x);
}
else if (point.x > maxs.x) {
distSquared += (point.x - maxs.x) * (point.x - maxs.x);
}
if (point.y < mins.y) {
distSquared += (point.y - mins.y) * (point.y - mins.y);
}
else if (point.y > maxs.y) {
distSquared += (point.y - maxs.y) * (point.y - maxs.y);
}
if (point.z < mins.z) {
distSquared += (point.z - mins.z) * (point.z - mins.z);
}
else if (point.z > maxs.z) {
distSquared += (point.z - maxs.z) * (point.z - maxs.z);
}
return distSquared;
}
}
exports.FVector = FVector;