From 824e54bf8ffb44165e8a7b11de6c441fdec4862d Mon Sep 17 00:00:00 2001 From: David Peicho Date: Thu, 20 Aug 2020 17:17:02 +0100 Subject: [PATCH] component: add AbstractComponent to separate schema-constructable and raw component --- src/Component.d.ts | 40 +++++++++++------ src/Component.js | 95 +++++++++++++++++++++++++++-------------- src/ComponentManager.js | 25 ++++++----- src/Entity.d.ts | 12 +++--- src/TagComponent.js | 12 ++++-- 5 files changed, 120 insertions(+), 64 deletions(-) diff --git a/src/Component.d.ts b/src/Component.d.ts index dea6022a..25e141b6 100644 --- a/src/Component.d.ts +++ b/src/Component.d.ts @@ -4,27 +4,43 @@ import { PropType } from "./Types"; * Base class for components. */ -export type ComponentSchemaProp = { - default?: any; - type: PropType; +export type ComponentSchemaProp = { + default?: T; + type: PropType; }; export type ComponentSchema = { - [propName: string]: ComponentSchemaProp; + [propName: string]: ComponentSchemaProp; }; -export class Component { - static schema: ComponentSchema; +export type SchemaProperties = + Partial>>; + +export class AbstractComponent { static isComponent: true; - constructor(props?: Partial>> | false); - copy(source: this): this; - clone(): this; + static getName(): string; + constructor(props?: Properties); + copy(source: this | Properties): this; + clone(): this + setProperties(props?: Properties): this; reset(): void; dispose(): void; } -export interface ComponentConstructor> { - schema: ComponentSchema; +export class Component + extends AbstractComponent> { + static schema: ComponentSchema; + static isSchemaComponent: true; + constructor(props?: SchemaProperties); +} + +export interface ComponentConstructor> { isComponent: true; - new (props?: Partial>> | false): C; + new (...args: any): C; +} + +export interface SchemaConstructable> { + schema: ComponentSchema; + isSchemaComponent: true; + new (props?: SchemaProperties): C; } diff --git a/src/Component.js b/src/Component.js index 45c8dcb1..57c44ff5 100644 --- a/src/Component.js +++ b/src/Component.js @@ -1,27 +1,47 @@ -export class Component { - constructor(props) { - if (props !== false) { - const schema = this.constructor.schema; +export class AbstractComponent { + copy() { + if (process.env.NODE_ENV !== "production") { + throw new Error(`'.copy()' method unimplemented`); + } + return this; + } - for (const key in schema) { - if (props && props.hasOwnProperty(key)) { - this[key] = props[key]; - } else { - const schemaProp = schema[key]; - if (schemaProp.hasOwnProperty("default")) { - this[key] = schemaProp.type.clone(schemaProp.default); - } else { - const type = schemaProp.type; - this[key] = type.clone(type.default); - } - } - } + clone() { + return new this.constructor().copy(this); + } - if (process.env.NODE_ENV !== "production" && props !== undefined) { - this.checkUndefinedAttributes(props); - } + setProperties() { + if (process.env.NODE_ENV !== "production") { + throw new Error(`'.setProperties()' method unimplemented`); + } + return this; + } + + reset() { + if (process.env.NODE_ENV !== "production") { + throw new Error(`'.reset()' method unimplemented`); + } + } + + dispose() { + if (this._pool) { + this._pool.release(this); } + } + + getName() { + return this.constructor.getName(); + } +} +AbstractComponent.getName = function() { + return this.displayName || this.name; +}; +AbstractComponent.isComponent = true; +export class Component extends AbstractComponent { + constructor(props) { + super(); + this.setProperties(props); this._pool = null; } @@ -44,8 +64,28 @@ export class Component { return this; } - clone() { - return new this.constructor().copy(this); + setProperties(props) { + const schema = this.constructor.schema; + + for (const key in schema) { + if (props && props.hasOwnProperty(key)) { + this[key] = props[key]; + } else { + const schemaProp = schema[key]; + if (schemaProp.hasOwnProperty("default")) { + this[key] = schemaProp.type.clone(schemaProp.default); + } else { + const type = schemaProp.type; + this[key] = type.clone(type.default); + } + } + } + + if (process.env.NODE_ENV !== "production" && props !== undefined) { + this.checkUndefinedAttributes(props); + } + + return this; } reset() { @@ -63,12 +103,6 @@ export class Component { } } - dispose() { - if (this._pool) { - this._pool.release(this); - } - } - getName() { return this.constructor.getName(); } @@ -88,7 +122,4 @@ export class Component { } Component.schema = {}; -Component.isComponent = true; -Component.getName = function () { - return this.displayName || this.name; -}; +Component.isSchemaComponent = true; diff --git a/src/ComponentManager.js b/src/ComponentManager.js index ca0f3b28..e65cf269 100644 --- a/src/ComponentManager.js +++ b/src/ComponentManager.js @@ -23,23 +23,26 @@ export class ComponentManager { } const schema = Component.schema; + if (schema) { + for (const propName in schema) { + const prop = schema[propName]; + if (!prop.type) { + throw new Error( + `Invalid schema for component "${Component.getName()}". Missing type for "${propName}" property.` + ); + } + } + } - if (!schema) { + console.log(Component.getName()); + console.log(Component.isSchemaComponent); + + if (Component.isSchemaComponent && !schema) { throw new Error( `Component "${Component.getName()}" has no schema property.` ); } - for (const propName in schema) { - const prop = schema[propName]; - - if (!prop.type) { - throw new Error( - `Invalid schema for component "${Component.getName()}". Missing type for "${propName}" property.` - ); - } - } - Component._typeId = this.nextComponentId++; this.Components.push(Component); this._ComponentsMap[Component._typeId] = Component; diff --git a/src/Entity.d.ts b/src/Entity.d.ts index cf601c8b..1271b063 100644 --- a/src/Entity.d.ts +++ b/src/Entity.d.ts @@ -19,17 +19,17 @@ export class Entity { * @param Component Type of component to get * @param includeRemoved Whether a component that is staled to be removed should be also considered */ - getComponent?>( + getComponent>( Component: ComponentConstructor, includeRemoved?: boolean - ): Readonly; + ): Readonly | undefined; /** * Get a component that is slated to be removed from this entity. */ - getRemovedComponent?>( + getRemovedComponent>( Component: ComponentConstructor - ): Readonly; + ): Readonly | undefined; /** * Get an object containing all the components on this entity, where the object keys are the component types. @@ -50,9 +50,9 @@ export class Entity { * Get a mutable reference to a component on this entity. * @param Component Type of component to get */ - getMutableComponent?>( + getMutableComponent>( Component: ComponentConstructor - ): C; + ): C | undefined; /** * Add a component to the entity. diff --git a/src/TagComponent.js b/src/TagComponent.js index afdc82c5..cf21f650 100644 --- a/src/TagComponent.js +++ b/src/TagComponent.js @@ -1,9 +1,15 @@ -import { Component } from "./Component"; +import { AbstractComponent } from "./Component"; -export class TagComponent extends Component { +export class TagComponent extends AbstractComponent { constructor() { - super(false); + super(); } + + copy() {} + + reset() {} + + setProperties() {} } TagComponent.isTagComponent = true;