@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
208 lines • 9.59 kB
JavaScript
import { Logger } from "../Misc/logger.js";
import { Color3, Color4 } from "../Maths/math.color.js";
import { Matrix, Quaternion, Vector2, Vector3, Vector4 } from "../Maths/math.vector.js";
import { FlowGraphInteger } from "./CustomTypes/flowGraphInteger.js";
import { getRichTypeByFlowGraphType } from "./flowGraphRichTypes.js";
import { FlowGraphMatrix2D, FlowGraphMatrix3D } from "./CustomTypes/flowGraphMatrix.js";
function IsVectorClassName(className) {
return (className === "Vector2" /* FlowGraphTypes.Vector2 */ ||
className === "Vector3" /* FlowGraphTypes.Vector3 */ ||
className === "Vector4" /* FlowGraphTypes.Vector4 */ ||
className === "Quaternion" /* FlowGraphTypes.Quaternion */ ||
className === "Color3" /* FlowGraphTypes.Color3 */ ||
className === "Color4" /* FlowGraphTypes.Color4 */);
}
function IsMatrixClassName(className) {
return className === "Matrix" /* FlowGraphTypes.Matrix */ || className === "Matrix2D" /* FlowGraphTypes.Matrix2D */ || className === "Matrix3D" /* FlowGraphTypes.Matrix3D */;
}
function IsAnimationGroupClassName(className) {
return className === "AnimationGroup";
}
function GetSceneNodeFromSerializedReference(serializedReference, scene) {
if (!serializedReference || (!serializedReference.id && !serializedReference.name)) {
return undefined;
}
const nodes = scene.getNodes().filter((node) => (serializedReference.id ? node.id === serializedReference.id : node.name === serializedReference.name));
if (nodes.length === 0) {
return undefined;
}
const className = serializedReference.type ?? serializedReference.className;
const classMatches = className ? nodes.filter((node) => node.getClassName() === className) : [];
const candidates = classMatches.length > 0 ? classMatches : nodes;
return (serializedReference.uniqueId ? candidates.find((node) => node.uniqueId === serializedReference.uniqueId) : undefined) ?? candidates[0];
}
function ParseVector(className, value, flipHandedness = false) {
if (className === "Vector2" /* FlowGraphTypes.Vector2 */) {
return Vector2.FromArray(value);
}
else if (className === "Vector3" /* FlowGraphTypes.Vector3 */) {
if (flipHandedness) {
value[2] *= -1;
}
return Vector3.FromArray(value);
}
else if (className === "Vector4" /* FlowGraphTypes.Vector4 */) {
return Vector4.FromArray(value);
}
else if (className === "Quaternion" /* FlowGraphTypes.Quaternion */) {
if (flipHandedness) {
value[2] *= -1;
value[3] *= -1;
}
return Quaternion.FromArray(value);
}
else if (className === "Color3" /* FlowGraphTypes.Color3 */) {
return new Color3(value[0], value[1], value[2]);
}
else if (className === "Color4" /* FlowGraphTypes.Color4 */) {
return new Color4(value[0], value[1], value[2], value[3]);
}
else {
throw new Error(`Unknown vector class name ${className}`);
}
}
/**
* The default function that serializes values in a context object to a serialization object
* @param key the key where the value should be stored in the serialization object
* @param value the value to store
* @param serializationObject the object where the value will be stored
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
export function defaultValueSerializationFunction(key, value, serializationObject) {
const className = value?.getClassName?.() ?? "";
if (IsVectorClassName(className) || IsMatrixClassName(className)) {
serializationObject[key] = {
value: value.asArray(),
className,
};
}
else if (className === "FlowGraphInteger" /* FlowGraphTypes.Integer */) {
serializationObject[key] = {
value: value.value,
className,
};
}
else {
if (className && (value.id || value.name)) {
serializationObject[key] = {
id: value.id,
name: value.name,
className,
uniqueId: value.uniqueId,
};
}
else {
if (typeof value !== "object" || value === null) {
serializationObject[key] = value;
}
else {
// Skip known non-serializable keys immediately to avoid
// expensive JSON.stringify attempts on large object trees
// (e.g. pathConverter holds the entire glTF parse tree).
if (key === "pathConverter") {
return;
}
// Quick check: if any own property is a function, the object
// is not JSON-safe and stringify would be wasteful.
const hasFunction = Object.values(value).some((v) => typeof v === "function");
if (hasFunction) {
return;
}
// Plain object (e.g. parsed event config) — store it if JSON-safe.
try {
serializationObject[key] = JSON.parse(JSON.stringify(value));
}
catch {
Logger.Warn(`FlowGraph serialization: value for key "${key}" is not JSON-serializable and was skipped.`);
}
}
}
}
}
/**
* The default function that parses values stored in a serialization object
* @param key the key to the value that will be parsed
* @param serializationObject the object that will be parsed
* @param assetsContainer the assets container that will be used to find the objects
* @param scene
* @returns
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
export function defaultValueParseFunction(key, serializationObject, assetsContainer, scene) {
const intermediateValue = serializationObject[key];
let finalValue;
const className = intermediateValue?.type ?? intermediateValue?.className;
const sceneNode = GetSceneNodeFromSerializedReference(intermediateValue, scene);
if (sceneNode) {
finalValue = sceneNode;
}
else if (IsVectorClassName(className)) {
finalValue = ParseVector(className, intermediateValue.value);
}
else if (IsAnimationGroupClassName(className)) {
// do not use the scene.getAnimationGroupByName because it is possible that two AGs will have the same name
const ags = scene.animationGroups.filter((ag) => ag.name === intermediateValue.name);
// uniqueId changes on each load. this is used for the glTF loader, that uses serialization after the scene was loaded.
finalValue = ags.length === 1 ? ags[0] : ags.find((ag) => ag.uniqueId === intermediateValue.uniqueId);
}
else if (className === "Matrix" /* FlowGraphTypes.Matrix */) {
finalValue = Matrix.FromArray(intermediateValue.value);
}
else if (className === "Matrix2D" /* FlowGraphTypes.Matrix2D */) {
finalValue = new FlowGraphMatrix2D(intermediateValue.value);
}
else if (className === "Matrix3D" /* FlowGraphTypes.Matrix3D */) {
finalValue = new FlowGraphMatrix3D(intermediateValue.value);
}
else if (className === "FlowGraphInteger" /* FlowGraphTypes.Integer */) {
finalValue = FlowGraphInteger.FromValue(intermediateValue.value);
}
else if (className === "number" /* FlowGraphTypes.Number */ || className === "string" /* FlowGraphTypes.String */ || className === "boolean" /* FlowGraphTypes.Boolean */) {
finalValue = intermediateValue.value[0];
}
else if (intermediateValue && intermediateValue.value !== undefined) {
finalValue = intermediateValue.value;
}
else {
if (Array.isArray(intermediateValue)) {
// Check if this is an event configuration array (objects with id/eventData)
// versus a plain array of primitives (e.g. variable name lists)
if (intermediateValue.length > 0 && typeof intermediateValue[0] === "object" && intermediateValue[0] !== null && "eventData" in intermediateValue[0]) {
// configuration data of an event
finalValue = intermediateValue.reduce((acc, val) => {
if (!val.eventData) {
return acc;
}
acc[val.id] = {
type: getRichTypeByFlowGraphType(val.type),
};
if (typeof val.value !== "undefined") {
acc[val.id].value = defaultValueParseFunction("value", val, assetsContainer, scene);
}
return acc;
}, {});
}
else {
// Plain array of primitives — return as-is
finalValue = intermediateValue;
}
}
else {
finalValue = intermediateValue;
}
}
return finalValue;
}
/**
* Given a name of a flow graph block class, return if this
* class needs to be created with a path converter. Used in
* parsing.
* @param className the name of the flow graph block class
* @returns a boolean indicating if the class needs a path converter
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
export function needsPathConverter(className) {
// I am not using the ClassName property here because it was causing a circular dependency
return className === "FlowGraphJsonPointerParserBlock" /* FlowGraphBlockNames.JsonPointerParser */;
}
//# sourceMappingURL=serialization.js.map