r3-legacy/src/r3-entityManager.js

415 lines
11 KiB
JavaScript

/**
* R3.EntityManager
* @param apiComponent
* @constructor
*/
R3.EntityManager = function(
apiComponent
) {
/**
* The 'register' array is a register of each component currently loaded - when the linking
* system starts it also loads all the current components from the entity manager
* @type {Array}
*/
this.register = {};
this.idRegister = {};
this.defaultEntity = null;
this.instanceDisposal = [];
R3.Event.Subscribe(
R3.Event.INSTANCE_CREATED,
this.instanceCreated.bind(this)
);
R3.Event.Subscribe(
R3.Event.REMOVE_COMPONENT,
this.removeComponent.bind(this)
);
R3.Event.Subscribe(
R3.Event.INSTANCE_DISPOSAL,
this.removeInstances.bind(this)
)
// R3.Event.Subscribe(
// R3.Event.ENTITY_LOADED,
// this.entityLoaded.bind(this)
// );
};
R3.EntityManager.prototype.instanceCreated = function(data) {
/**
* Register this component in componentType to Component register
*/
if (R3.Utils.UndefinedOrNull(this.register[data.component.componentType])) {
this.register[data.component.componentType] = {};
}
if (R3.Utils.UndefinedOrNull(this.register[data.component.componentType][data.component.id])) {
this.register[data.component.componentType][data.component.id] = data.component;
}
/**
* Register this component in the Component.id to Component register
*/
if (R3.Utils.UndefinedOrNull(this.idRegister[data.component.id])) {
this.idRegister[data.component.id] = data.component;
}
};
/**
* Removes the component from both registries (the component type to component register, and the component ID to
* component register)
* @param data
*/
R3.EntityManager.prototype.removeComponent = function(data) {
/**
* Sanity Check 1
*/
if (R3.Utils.UndefinedOrNull(this.register[data.component.componentType]) ||
R3.Utils.UndefinedOrNull(this.register[data.component.componentType][data.component.id])
) {
throw new Error('EntityManager register out of sync');
}
/**
* Delete the component from the componentType to Component register
*/
delete this.register[data.component.componentType][data.component.id];
if (R3.Utils.IsEmpty(this.register[data.component.componentType])) {
delete this.register[data.component.componentType];
}
/**
* Sanity Check 2
*/
if (R3.Utils.UndefinedOrNull(this.idRegister[data.component.id])){
throw new Error('EntityManager idRegister out of sync');
}
/**
* Delete the component from the ID to Component register
*/
delete this.idRegister[data.component.id];
/**
* Now we have to be quite careful - we only have one copy left of this component - the one in data.component.
* we need a handle on all instances in this object. We need to store them to allow the 'REMOVE_COMPONENT' event
* to finish getting handled, then we need to dispose of the instance themselves.
* This gives our systems and other objects a chance to cleanly stop relying on these components at which point
* we can safely clean up our instances.
*/
var component = data.component;
for (var property in component) {
if (property === 'parent') {
continue;
}
if (component.hasOwnProperty(property)) {
if (component[property] instanceof R3.Component) {
R3.Utils.PushUnique(this.instanceDisposal, component[property].instance);
}
}
}
};
R3.EntityManager.prototype.removeInstances = function(data) {
this.instanceDisposal = this.instanceDisposal.reduce(
function(result, instance) {
if (
R3.Utils.Defined(instance.dispose) &&
typeof instance.dispose === 'function'
) {
instance.dispose();
}
if (instance instanceof HTMLElement) {
instance.parentElement.removeChild(instance);
}
return result;
},
[]
);
};
// R3.EntityManager.prototype.entityLoaded = function(data) {
// this.defaultEntity = data.entity;
// };
// R3.EntityManager.prototype.registerComponent = function(data) {
//
// // var updated = false;
//
// if (R3.Utils.UndefinedOrNull(this.register[data.component.componentType])) {
// this.register[data.component.componentType] = {};
// // R3.Event.Emit(
// // R3.Event.COMPONENT_TYPES_UPDATE,
// // {
// // componentType : data.component.componentType,
// // componentTypes : Object.keys(this.register)
// // }
// // );
// // updated = true;
// }
//
// if (R3.Utils.UndefinedOrNull(this.register[data.component.componentType][data.component.id])) {
// this.register[data.component.componentType][data.component.id] = data.component;
// // updated = true;
// }
//
// if (R3.Utils.UndefinedOrNull(this.idRegister[data.component.id])) {
// this.idRegister[data.component.id] = data.component;
// // updated = true;
// }
//
// // if (updated) {
// // R3.Event.Emit(
// // R3.Event.REGISTER_UPDATE,
// // {
// // componentType : data.component.componentType,
// // components : this.register[data.component.componentType],
// // idRegister : this.idRegister,
// // register : this.register
// // }
// // );
// // }
// };
/**
* Returns an entity by ID or null
* @param id
* @returns {*}
*/
R3.EntityManager.prototype.findEntityById = function(id) {
var entity = this.register[R3.Component.ENTITY][id];
if (entity) {
return entity;
}
return null;
};
R3.EntityManager.prototype.findComponentById = function(id) {
return this.idRegister[id];
};
R3.EntityManager.prototype.findComponentByName = function(name) {
return Object.keys(this.idRegister).reduce(
function(result, componentId) {
if (this.idRegister[componentId].name === name) {
result = this.idRegister[componentId];
}
return result;
}.bind(this),
null
);
};
R3.EntityManager.prototype.findHelperByObject = function(object) {
if (typeof this.register[R3.Component.HELPER] === 'undefined') {
return null;
}
return Object.keys(this.register[R3.Component.HELPER]).reduce(
function(result, helperId) {
if (this.register[R3.Component.HELPER][helperId].object === object) {
result = this.register[R3.Component.HELPER][helperId];
}
return result;
}.bind(this),
null
);
};
R3.EntityManager.prototype.findSceneByObject = function(object) {
return Object.keys(this.register[R3.Component.SCENE]).reduce(
function(result, sceneId) {
if (
this.register[R3.Component.SCENE][sceneId].meshes.indexOf(object) !== -1 ||
this.register[R3.Component.SCENE][sceneId].lights.indexOf(object) !== -1
) {
result = this.register[R3.Component.SCENE][sceneId];
}
return result;
}.bind(this),
null
);
};
/**
* Adds an entity to this manager
* @param entity R3.Entity
*/
R3.EntityManager.prototype.addEntity = function(entity) {
this.entities.push(entity);
};
/**
* Returns entity by name
* @param name
* @returns {*}
*/
R3.EntityManager.prototype.queryByName = function(name) {
return this.entities.reduce(
function(result, entity){
if (entity.name === name) {
result = entity;
}
return result;
},
null
)
};
/**
* Removes an entity - do we remove all its components as well?
* @param entity R3.D3.Entity
* @returns boolean true if successful
*/
R3.EntityManager.prototype.removeEntity = function(entity) {
var index = this.entities.indexOf(entity);
if (index === -1) {
console.log('failed to remove entity : ', entity);
return false;
}
this.entities.splice(index, 1);
return true;
};
/**
* Returns all the entities with the following components
* @param components R3.Component[]
*/
// R3.EntityManager.prototype.findEntities = function(components) {
//
// var entities = this.entities.reduce(
// function(result, entity) {
//
// var hasAllComponents = components.reduce(
// function(componentResult, component) {
// if (!entity.hasComponent(component)) {
// componentResult = false;
// }
// return componentResult;
// },
// true
// );
//
// if (hasAllComponents) {
// result.push(entity);
// }
//
// return result;
// },
// []
// );
//
// return entities;
// };
/**
* Returns all actual components of all entities that contain this component
* More efficient
* @param componentTypes (array of component types or a single component type)
*/
R3.EntityManager.prototype.queryComponents = function(componentTypes) {
var result = [];
if (componentTypes instanceof Array) {
componentTypes.map(
function(componentType) {
if (typeof this.register[componentType] === 'undefined') {
return;
}
Object.keys(this.register[componentType]).map(
function(componentId) {
result.push(this.register[componentType][componentId]);
}.bind(this)
)
}.bind(this)
)
} else {
if (typeof this.register[componentTypes] === 'undefined') {
return result;
}
Object.keys(this.register[componentTypes]).map(
function(componentId) {
result.push(this.register[componentTypes][componentId]);
}.bind(this)
)
}
return result;
};
/**
* Slower way of retrieving objects
* @param constructors (array of constructors, or a constructor)
* @returns {*}
*/
R3.EntityManager.prototype.findComponentsByConstructor = function(constructors) {
return Object.keys(this.idRegister).reduce(
function(result, componentId) {
if (constructors instanceof Array) {
constructors.map(
function(constructor) {
if (this.idRegister[componentId] instanceof constructor) {
result.push(this.idRegister[componentId]);
}
}.bind(this)
)
} else {
if (this.idRegister[componentId] instanceof constructors) {
result.push(this.idRegister[componentId]);
}
}
return result;
}.bind(this),
[]
);
};