UNPKG

@dcl/ecs

Version:
202 lines (201 loc) • 9.87 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.instanceComposite = exports.getEntityMapping = exports.getComponentDefinition = exports.getComponentValue = exports.EntityMappingMode = void 0; const components_1 = require("../components"); const component_number_1 = require("../components/component-number"); const schemas_1 = require("../schemas"); const ByteBuffer_1 = require("../serialization/ByteBuffer"); const components_2 = require("./components"); const path = __importStar(require("./path")); /** @public */ /* @__PURE__ */ var EntityMappingMode; (function (EntityMappingMode) { EntityMappingMode[EntityMappingMode["EMM_NONE"] = 0] = "EMM_NONE"; EntityMappingMode[EntityMappingMode["EMM_NEXT_AVAILABLE"] = 1] = "EMM_NEXT_AVAILABLE"; EntityMappingMode[EntityMappingMode["EMM_DIRECT_MAPPING"] = 2] = "EMM_DIRECT_MAPPING"; })(EntityMappingMode = exports.EntityMappingMode || (exports.EntityMappingMode = {})); /** * Return the component value from composite data * @internal */ function getComponentValue(componentDefinition, component) { if (component.data?.$case === 'json') { return component.data.json; } else { return componentDefinition.schema.deserialize(new ByteBuffer_1.ReadWriteByteBuffer(component.data?.binary)); } } exports.getComponentValue = getComponentValue; /** * Return the component definition from composite info * @internal */ function getComponentDefinition(engine, component) { const existingComponentDefinition = engine.getComponentOrNull(component.name); if (!existingComponentDefinition) { if (component.name.startsWith('core::')) { if (component.name in components_1.componentDefinitionByName) { return components_1.componentDefinitionByName[component.name](engine); } else { throw new Error(`The core component ${component.name} was not found.`); } } else if (component.jsonSchema) { return engine.defineComponentFromSchema(component.name, schemas_1.Schemas.fromJson(component.jsonSchema)); } else { throw new Error(`${component.name} is not defined and there is no schema to define it.`); } } else { return existingComponentDefinition; } } exports.getComponentDefinition = getComponentDefinition; /** * Return the entity mapping or fail if there is no more * @internal */ function getEntityMapping(engine, compositeEntity, mappedEntities, { entityMapping }) { const existingEntity = mappedEntities.get(compositeEntity); if (existingEntity) { return existingEntity; } if (entityMapping?.type === EntityMappingMode.EMM_DIRECT_MAPPING) { const entity = entityMapping.getCompositeEntity(compositeEntity); mappedEntities.set(compositeEntity, entity); return entity; } // This function in runtime can be just `engine.addEntity()` const newEntity = entityMapping?.type === EntityMappingMode.EMM_NEXT_AVAILABLE ? entityMapping.getNextAvailableEntity() : engine.addEntity(); if (newEntity === null) { throw new Error('There is no more entities to allocate'); } mappedEntities.set(compositeEntity, newEntity); return newEntity; } exports.getEntityMapping = getEntityMapping; /** * @internal */ /* @__PURE__ */ function instanceComposite(engine, compositeResource, compositeProvider, options) { const { rootEntity, alreadyRequestedSrc: optionalAlreadyRequestedSrc, entityMapping } = options; const alreadyRequestedSrc = optionalAlreadyRequestedSrc || new Set(); const compositeDirectoryPath = path.dirname(path.resolve(compositeResource.src)); const TransformComponentNumber = (0, component_number_1.componentNumberFromName)('core::Transform'); const CompositeRootComponent = (0, components_2.getCompositeRootComponent)(engine); // Key => EntityNumber from the composite // Value => EntityNumber in current engine const mappedEntities = new Map(); const getCompositeEntity = (compositeEntity) => getEntityMapping(engine, compositeEntity, mappedEntities, options); // ## 1 ## // First entity that I want to map, the root entity from the composite to the target entity in the engine // If there is no `rootEntity` passed, we assign one from `getNextAvailableEntity` const compositeRootEntity = rootEntity ?? getCompositeEntity(0); if (rootEntity) { mappedEntities.set(0, rootEntity); } // ## 2 ## // If there are more composite inside this one, we instance first. // => This is not only a copy, we need to instance. Otherwise, we'd be missing that branches // => TODO: in the future, the instanciation is first, then the overides (to parameterize Composite, e.g. house with different wall colors) const childrenComposite = compositeResource.composite.components.find((item) => item.name === CompositeRootComponent.componentName); if (childrenComposite) { for (const [childCompositeEntity, compositeRawData] of childrenComposite.data) { const childComposite = getComponentValue(CompositeRootComponent, compositeRawData); const childCompositePath = path.resolveComposite(childComposite.src, compositeDirectoryPath); const childCompositeResource = compositeProvider.getCompositeOrNull(childCompositePath); const targetEntity = getCompositeEntity(childCompositeEntity); if (childCompositeResource) { if (alreadyRequestedSrc.has(childCompositeResource.src) || childCompositeResource.src === compositeResource.src) { throw new Error(`Composite ${compositeResource.src} has a recursive instanciation while try to instance ${childCompositeResource.src}. Previous instances: ${alreadyRequestedSrc.toString()}`); } instanceComposite(engine, childCompositeResource, compositeProvider, { rootEntity: targetEntity, alreadyRequestedSrc: new Set(alreadyRequestedSrc).add(childCompositeResource.src), entityMapping: entityMapping?.type === EntityMappingMode.EMM_NEXT_AVAILABLE ? entityMapping : undefined }); } } } // ## 3 ## // Then, we copy the all rest of the components (skipping the Composite ones) for (const component of compositeResource.composite.components) { // We already instanced the composite if (component.name === CompositeRootComponent.componentName) continue; // ## 3a ## // We find the component definition const componentDefinition = getComponentDefinition(engine, component); // ## 3b ## // Iterating over all the entities with this component and create the replica for (const [entity, compositeComponentValue] of component.data) { const componentValueDeserialized = getComponentValue(componentDefinition, compositeComponentValue); const targetEntity = getCompositeEntity(entity); const componentValue = componentDefinition.create(targetEntity, componentValueDeserialized); // ## 3c ## // All entities referenced in the composite probably has a different resolved EntityNumber // We'll know with the mappedEntityes if (componentDefinition.componentId === TransformComponentNumber) { const transform = componentValue; if (transform.parent) { transform.parent = getCompositeEntity(transform.parent); } else { transform.parent = getCompositeEntity(0); } // TODO: is it going to be necessary to remap assets? e.g. src param from AudioSource and GltfContainer } else { schemas_1.Schemas.mutateNestedValues(componentDefinition.schema.jsonSchema, componentValue, (value, valueType) => { if (valueType.serializationType === 'entity') { return { changed: true, value: getCompositeEntity(value) }; } else { return { changed: false }; } }); } } } const composite = CompositeRootComponent.getMutableOrNull(compositeRootEntity) || CompositeRootComponent.create(compositeRootEntity); for (const [entitySource, targetEntity] of mappedEntities) { composite.entities.push({ src: entitySource, dest: targetEntity }); } composite.src = compositeResource.src; return compositeRootEntity; } exports.instanceComposite = instanceComposite;