UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

206 lines (150 loc) 5.94 kB
import { assert } from "../../../assert.js"; import { abstractJSONDeserializer } from "../../../json/abstractJSONDeserializer.js"; import { NodeInstance } from "../node/NodeInstance.js"; import { NodeRegistry } from "../node/NodeRegistry.js"; /** * * @param {NodeInstance} node * @param {*} json * @param {Map<string, function>} deserializers */ function nodeParametersFromJSON(node, json, deserializers) { for (const key in json) { const jParameter = json[key]; const value = abstractJSONDeserializer(jParameter, deserializers); node.setParameterValue(key, value); } } /** * * @param {[]} j_descriptions * @param {Map<string,function>} deserializers * @param {NodeRegistry} node_registry * @param {boolean} allow_node_id_collisions * @returns {Promise<NodeDescription[]>} */ async function deserializeNodeDescriptors(j_descriptions, deserializers, node_registry, allow_node_id_collisions) { /** * * @type {NodeDescription[]} */ const result = []; /** * * @type {{index:number, promise:Promise<NodeDescription>}[]} */ const deferred = []; /** * * @type {NodeDescription[]} */ const deserialized = []; const node_description_count = j_descriptions.length; // parse node result for (let i = 0; i < node_description_count; i++) { const jDescription = j_descriptions[i]; const result = abstractJSONDeserializer(jDescription, deserializers); if (result instanceof Promise) { deferred.push({ index: i, promise: result }); } else { deserialized[i] = result; } } if (deferred.length > 0) { const resolved = await Promise.all(deferred.map(m => m.promise)); for (let i = 0; i < deferred.length; i++) { const node_description = resolved[i]; const spec = deferred[i]; deserialized[spec.index] = node_description; } } for (let i = 0; i < node_description_count; i++) { const loaded_node = deserialized[i]; if ( typeof loaded_node !== "object" || loaded_node.isNodeDescription !== true ) { const jDescription = j_descriptions[i]; throw new Error(`Deserialized object was expected to be a NodeDescription, instead got something else. Source JSON[${i}]: ${jDescription}`); } const existing_node = node_registry.getNode(loaded_node.id); if (existing_node === undefined) { result[i] = loaded_node; // make sure to register the node node_registry.addNode(loaded_node); } else { if (!existing_node.equals(loaded_node)) { // collision exists if (allow_node_id_collisions) { result[i] = loaded_node; } else { // illegal collision throw new Error(`Loaded node does not match the one in the registry. Loaded: ${loaded_node}, Existing: ${existing_node}`); } } else { // re-use node from registry result[i] = existing_node; } } } return result; } /** * * @param {NodeGraph} graph * @param {{nodes?:[], connections?:[], descriptions?:[]}} json * @param {NodeRegistry} [node_registry] * @param {Map<string, function>} [deserializers] * @param {boolean} [allow_node_id_collisions] */ export async function deserializeNodeGraphFromJSON({ graph, json, node_registry = new NodeRegistry(), deserializers = new Map(), allow_node_id_collisions = false }) { const j_nodes = json.nodes ?? []; const j_connections = json.connections ?? []; const j_descriptions = json.descriptions ?? []; assert.isArray(j_nodes, 'json.nodes'); assert.isArray(j_connections, 'json.connections'); assert.isArray(j_descriptions, 'json.descriptions'); graph.reset(); const descriptions = await deserializeNodeDescriptors( j_descriptions, deserializers, node_registry, allow_node_id_collisions ); // parse nodes const node_count = j_nodes.length; for (let i = 0; i < node_count; i++) { const jNode = j_nodes[i]; const node_id = jNode.id; assert.isNonNegativeInteger(node_id, 'node.id'); const description_index = jNode.description; const jParameters = jNode.parameters; // get node description const node_description = descriptions[description_index]; if (node_description === undefined) { throw new Error(`Index ${description_index} not found in .description`); } const nodeInstance = new NodeInstance(); nodeInstance.id = node_id; nodeInstance.setDescription(node_description); nodeParametersFromJSON(nodeInstance, jParameters, deserializers); graph.addNode(nodeInstance); } // parse connections const connection_count = j_connections.length; for (let i = 0; i < connection_count; i++) { const jConnection = j_connections[i]; const jSource = jConnection.source; const jTarget = jConnection.target; graph.createConnection(jSource.instance, jSource.port, jTarget.instance, jTarget.port); } }