935 lines
25 KiB
JavaScript
935 lines
25 KiB
JavaScript
/**
|
|
* Linking System takes care of linking components and dependencies (after they have loaded) -
|
|
* and managing the relationships between objects - ex. what happens when a parent entity changes,
|
|
* or a parent scene changes.
|
|
* @param apiSystem GameLib.API.System
|
|
* @constructor
|
|
*/
|
|
GameLib.System.Linking = function(
|
|
apiSystem
|
|
) {
|
|
GameLib.System.call(
|
|
this,
|
|
apiSystem
|
|
);
|
|
|
|
/**
|
|
* The dependencies of each component is tracked through this dependencies object -
|
|
* it maps the id of the object on which a component depends back to the component which depends on it,
|
|
* ex. texture.image = 'abcdefghi', then this.dependencies = {'abcdefghi' : [texture]}
|
|
* @type {{}}
|
|
*/
|
|
this.dependencies = {};
|
|
|
|
this.resolved = [];
|
|
|
|
/**
|
|
* Components
|
|
*/
|
|
this.componentCreatedSubscription = null;
|
|
this.componentClonedSubscription = null;
|
|
this.registerDependenciesSubscription = null;
|
|
this.componentRemoveSubscription = null;
|
|
|
|
/**
|
|
* Parents
|
|
*/
|
|
this.parentSceneChangeSubscription = null;
|
|
this.parentWorldChangeSubscription = null;
|
|
this.parentEntityChangeSubscription = null;
|
|
|
|
/**
|
|
* Instances
|
|
*/
|
|
this.instanceCreatedSubscription = null;
|
|
this.instanceClonedSubscription = null;
|
|
|
|
/**
|
|
* Meshes
|
|
*/
|
|
this.removeMeshSubscription = null;
|
|
|
|
/**
|
|
* Images
|
|
*/
|
|
this.imageChangedSubscription = null;
|
|
|
|
/**
|
|
* Materials
|
|
*/
|
|
this.materialTypeChangedSubscription = null;
|
|
|
|
/**
|
|
* Arrays
|
|
*/
|
|
this.arrayItemAddedSubscription = null;
|
|
};
|
|
|
|
GameLib.System.Linking.prototype = Object.create(GameLib.System.prototype);
|
|
GameLib.System.Linking.prototype.constructor = GameLib.System.Linking;
|
|
|
|
GameLib.System.Linking.prototype.start = function() {
|
|
|
|
GameLib.System.prototype.start.call(this);
|
|
|
|
/**
|
|
* Components
|
|
*/
|
|
this.componentCreatedSubscription = this.subscribe(
|
|
GameLib.Event.COMPONENT_CREATED,
|
|
this.componentCreated.bind(this)
|
|
);
|
|
|
|
this.componentClonedSubscription = this.subscribe(
|
|
GameLib.Event.COMPONENT_CLONED,
|
|
this.componentCloned.bind(this)
|
|
);
|
|
|
|
this.registerDependenciesSubscription = this.subscribe(
|
|
GameLib.Event.REGISTER_DEPENDENCIES,
|
|
this.registerDependenciesDirect
|
|
);
|
|
|
|
this.componentRemoveSubscription = this.subscribe(
|
|
GameLib.Event.REMOVE_COMPONENT,
|
|
this.removeComponent
|
|
);
|
|
|
|
/**
|
|
* Parents
|
|
*/
|
|
this.parentSceneChangeSubscription = this.subscribe(
|
|
GameLib.Event.PARENT_SCENE_CHANGE,
|
|
this.onParentSceneChange
|
|
);
|
|
|
|
this.parentWorldChangeSubscription = this.subscribe(
|
|
GameLib.Event.PARENT_WORLD_CHANGE,
|
|
this.onParentWorldChange
|
|
);
|
|
|
|
this.parentEntityChangeSubscription = this.subscribe(
|
|
GameLib.Event.PARENT_ENTITY_CHANGE,
|
|
this.onParentEntityChange
|
|
);
|
|
|
|
/**
|
|
* Instances
|
|
*/
|
|
this.instanceCreatedSubscription = this.subscribe(
|
|
GameLib.Event.INSTANCE_CREATED,
|
|
this.instanceCreated
|
|
);
|
|
|
|
this.instanceClonedSubscription = this.subscribe(
|
|
GameLib.Event.INSTANCE_CLONED,
|
|
this.instanceCloned
|
|
);
|
|
|
|
/**
|
|
* Meshes
|
|
*/
|
|
this.removeMeshSubscription = this.subscribe(
|
|
GameLib.Event.REMOVE_MESH,
|
|
this.removeMesh
|
|
);
|
|
|
|
/**
|
|
* Images
|
|
*/
|
|
this.imageChangedSubscription = this.subscribe(
|
|
GameLib.Event.IMAGE_CHANGED,
|
|
this.imageChanged
|
|
);
|
|
|
|
/**
|
|
* Materials
|
|
*/
|
|
this.materialTypeChangedSubscription = this.subscribe(
|
|
GameLib.Event.MATERIAL_TYPE_CHANGED,
|
|
this.materialTypeChanged
|
|
);
|
|
|
|
/**
|
|
* Arrays
|
|
*/
|
|
this.arrayItemAddedSubscription = this.subscribe(
|
|
GameLib.Event.ARRAY_ITEM_ADDED,
|
|
this.arrayItemAdded
|
|
);
|
|
|
|
};
|
|
|
|
GameLib.System.Linking.prototype.link = function(component, data) {
|
|
for (var property in component.linkedObjects) {
|
|
if (component.linkedObjects.hasOwnProperty(property)) {
|
|
if (component.linkedObjects[property] instanceof Array) {
|
|
|
|
var linked = [];
|
|
|
|
component[property] = component[property].map(function (entry) {
|
|
if (entry === data.component.id) {
|
|
|
|
linked.push({
|
|
parent : component,
|
|
property : property,
|
|
child : data.component
|
|
});
|
|
|
|
return data.component;
|
|
} else {
|
|
return entry;
|
|
}
|
|
});
|
|
|
|
linked.map(function(link) {
|
|
GameLib.Event.Emit(
|
|
GameLib.Event.COMPONENT_LINKED,
|
|
link
|
|
);
|
|
})
|
|
|
|
} else {
|
|
if (component[property] &&
|
|
component[property] === data.component.id) {
|
|
component[property] = data.component;
|
|
|
|
GameLib.Event.Emit(
|
|
GameLib.Event.COMPONENT_LINKED,
|
|
{
|
|
parent : component,
|
|
property : property,
|
|
child : data.component
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
GameLib.System.Linking.prototype.resolveDependencies = function(component) {
|
|
|
|
if (!component.loaded) {
|
|
/**
|
|
* This component has not fully loaded - we should resolve dependencies to it later
|
|
*/
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Now find all the components which depend on this component
|
|
*/
|
|
var parentComponents = this.dependencies[component.id];
|
|
|
|
/**
|
|
* If we don't have any components which depend on this component, simply return
|
|
*/
|
|
if (GameLib.Utils.UndefinedOrNull(parentComponents)) {
|
|
|
|
/**
|
|
* We don't know about components which depend on this component - but it could still load.
|
|
* However, it is stored in the register and dependency list for later use
|
|
*/
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Otherwise, process them all
|
|
*/
|
|
parentComponents.map(
|
|
|
|
function (parentComponent) {
|
|
|
|
/**
|
|
* Link the parent component to this component
|
|
*/
|
|
this.link(parentComponent, {component: component});
|
|
|
|
/**
|
|
* We record that we linked a child component to a parent component
|
|
*/
|
|
GameLib.Utils.PushUnique(this.resolved, component);
|
|
|
|
/**
|
|
* First check if the dependencies have already been met
|
|
*/
|
|
if (
|
|
GameLib.Utils.UndefinedOrNull(parentComponent.dependencies) ||
|
|
(
|
|
parentComponent.dependencies instanceof Array &&
|
|
parentComponent.dependencies.length === 0
|
|
)
|
|
) {
|
|
|
|
/**
|
|
* This means - a parent component instance could maybe have been delayed to be created
|
|
* because the component constructor or linking system did not know at time of 'createInstance'
|
|
* that it required another object to fully become active
|
|
*/
|
|
if (
|
|
!parentComponent.loaded ||
|
|
GameLib.Utils.UndefinedOrNull(parentComponent.instance)
|
|
) {
|
|
|
|
try {
|
|
|
|
parentComponent.performInstanceCreation();
|
|
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
|
|
} else {
|
|
/**
|
|
* These dependencies have already been met - the parentComponent properties have changed.
|
|
* It is time to 'update' this instance with this information (if any of it is relevant - depends
|
|
* on the component)
|
|
*/
|
|
// parentComponent.updateInstance();
|
|
}
|
|
|
|
} else {
|
|
|
|
/**
|
|
* Remove the actual dependency
|
|
*/
|
|
var index = parentComponent.dependencies.indexOf(component.id);
|
|
if (index !== -1) {
|
|
parentComponent.dependencies.splice(index, 1);
|
|
}
|
|
|
|
/**
|
|
* If we now managed to link the objects, and this object has no more dependencies
|
|
*/
|
|
if (parentComponent.dependencies.length === 0) {
|
|
parentComponent.performInstanceCreation();
|
|
}
|
|
}
|
|
|
|
}.bind(this)
|
|
);
|
|
|
|
/**
|
|
* We now linked all the components which depends on this component, to this component. Time to cleanup our
|
|
* dependencies
|
|
*/
|
|
delete this.dependencies[component.id];
|
|
|
|
/**
|
|
* For now this essentially only notifies the Editor - We have some more work to do however
|
|
*/
|
|
GameLib.Event.Emit(
|
|
GameLib.Event.UNRESOLVED_DEPENDENCIES_UPDATE,
|
|
{
|
|
dependencies : this.dependencies
|
|
}
|
|
);
|
|
|
|
/**
|
|
* If we happen to have no more dependencies - we linked a bunch of components which are ready to use
|
|
*/
|
|
if (GameLib.Utils.IsEmpty(this.dependencies)) {
|
|
|
|
/**
|
|
* This also only notifies the Editor - We still have some more work to here
|
|
*/
|
|
GameLib.Event.Emit(
|
|
GameLib.Event.COMPONENTS_LINKED,
|
|
{
|
|
components: this.resolved.map(
|
|
function(component) {
|
|
return component;
|
|
}
|
|
)
|
|
}
|
|
);
|
|
|
|
this.resolved = [];
|
|
|
|
}
|
|
//else {
|
|
|
|
// var keys = Object.keys(this.dependencies);
|
|
|
|
/**
|
|
* And this is it - we need to check if the dependencies array contains any 'resolved' components -
|
|
* If it does - resolve the dependencies of this newly 'resolved' component
|
|
*/
|
|
// this.resolved = this.resolved.reduce(
|
|
//
|
|
// function(result, component) {
|
|
//
|
|
// if (keys.indexOf(component.id) !== -1) {
|
|
// /**
|
|
// * We found a resolved component - which is a dependency for another component.
|
|
// * Resolve the dependencies of this component - this is recursive and should be done carefully
|
|
// */
|
|
// this.resolveDependencies(component);
|
|
// } else {
|
|
// result.push(component);
|
|
// }
|
|
//
|
|
// return result;
|
|
//
|
|
// }.bind(this),
|
|
// []
|
|
// );
|
|
//}
|
|
|
|
};
|
|
|
|
GameLib.System.Linking.prototype.registerDependencies = function(component) {
|
|
|
|
/**
|
|
* We only care about components with unloaded dependencies -
|
|
* other components will have already had their instance objects created
|
|
*/
|
|
if (component.dependencies &&
|
|
component.dependencies.length > 0) {
|
|
|
|
component.dependencies = component.dependencies.reduce(
|
|
|
|
function(result, id) {
|
|
|
|
/**
|
|
* Check if we already processed a component on which this component is dependent
|
|
*/
|
|
var processedComponent = GameLib.EntityManager.Instance.findComponentById(id);
|
|
|
|
if (processedComponent && processedComponent.loaded) {
|
|
|
|
/**
|
|
* Link the component
|
|
*/
|
|
this.link(component, {component: processedComponent});
|
|
|
|
GameLib.Utils.PushUnique(this.resolved, processedComponent);
|
|
|
|
} else {
|
|
|
|
/**
|
|
* Create a new link if none exists
|
|
*/
|
|
if (GameLib.Utils.UndefinedOrNull(this.dependencies[id])) {
|
|
this.dependencies[id] = [];
|
|
}
|
|
|
|
/**
|
|
* Don't store duplicate dependencies
|
|
*/
|
|
if (this.dependencies[id].indexOf(component) === -1) {
|
|
this.dependencies[id].push(component);
|
|
GameLib.Event.Emit(
|
|
GameLib.Event.UNRESOLVED_DEPENDENCIES_UPDATE,
|
|
{
|
|
dependencies : this.dependencies
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Also - we remember that this component has a dependency
|
|
*/
|
|
result.push(id);
|
|
}
|
|
|
|
return result;
|
|
|
|
}.bind(this),
|
|
[]
|
|
);
|
|
|
|
if (component.dependencies.length === 0) {
|
|
component.performInstanceCreation();
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* When a component is created, register its dependencies, and try to resolve them
|
|
* @param data
|
|
*/
|
|
GameLib.System.Linking.prototype.componentCreated = function(data) {
|
|
|
|
/**
|
|
* Shorthand
|
|
*/
|
|
var component = data.component;
|
|
|
|
/**
|
|
* Register any dependencies of this component
|
|
*/
|
|
this.registerDependencies(component);
|
|
|
|
/**
|
|
* Resolve any dependencies to this component
|
|
*/
|
|
this.resolveDependencies(component);
|
|
|
|
};
|
|
|
|
GameLib.System.Linking.prototype.componentCloned = function(data) {
|
|
|
|
this.componentCreated(data);
|
|
|
|
if (data.component instanceof GameLib.D3.Mesh) {
|
|
|
|
if (!(data.parent instanceof GameLib.D3.Mesh)){
|
|
throw new Error('no scene parent');
|
|
}
|
|
|
|
if (data.parent.parentScene) {
|
|
data.parent.parentScene.addClone(data.component);
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* When you want to register dependencies directly - Component constructor does this when it knows the
|
|
* component instance cannot be created because it has a bunch of dependencies. So it tells the linking
|
|
* system about it, so the linking system can create the instance when the dependency loads or already exists
|
|
* @param data
|
|
*/
|
|
GameLib.System.Linking.prototype.registerDependenciesDirect = function(data) {
|
|
this.registerDependencies(data.component);
|
|
};
|
|
|
|
GameLib.System.Linking.prototype.removeComponent = function(data) {
|
|
|
|
if (!data.component) {
|
|
console.error('no component to remove');
|
|
return;
|
|
}
|
|
|
|
var component = data.component;
|
|
|
|
if (component.parentEntity instanceof GameLib.Entity) {
|
|
component.parentEntity.removeComponent(component);
|
|
}
|
|
|
|
if (component instanceof GameLib.D3.Mesh &&
|
|
component.parentScene instanceof GameLib.D3.Scene) {
|
|
|
|
component.removeHelper();
|
|
|
|
component.parentScene.removeObject(component);
|
|
}
|
|
|
|
if (component instanceof GameLib.D3.Light &&
|
|
component.parentScene instanceof GameLib.D3.Scene) {
|
|
component.parentScene.removeObject(component);
|
|
}
|
|
|
|
if (component instanceof GameLib.Entity) {
|
|
GameLib.EntityManager.Instance.removeEntity(component);
|
|
}
|
|
};
|
|
|
|
GameLib.System.Linking.prototype.imageChanged = function(data) {
|
|
|
|
var materials = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Material);
|
|
|
|
materials.map(function(material){
|
|
|
|
var textures = material.getTextures();
|
|
|
|
if (textures.indexOf(data.texture) !== -1) {
|
|
material.updateInstance();
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
GameLib.System.Linking.prototype.arrayItemAdded = function(data) {
|
|
if (
|
|
data.component instanceof GameLib.D3.PhysicsWorld &&
|
|
data.item instanceof GameLib.D3.RigidBody
|
|
) {
|
|
data.component.addRigidBody(data.item);
|
|
}
|
|
|
|
if (data.component instanceof GameLib.D3.Mesh &&
|
|
data.item instanceof GameLib.D3.Material
|
|
) {
|
|
data.component.addMaterial(data.item);
|
|
}
|
|
};
|
|
|
|
GameLib.System.Linking.prototype.instanceCloned = function(data) {
|
|
|
|
if (data.component instanceof GameLib.D3.Particle) {
|
|
|
|
var mesh = data.component.mesh;
|
|
|
|
if (mesh.parentScene && mesh.parentScene.instance) {
|
|
data.instance.userData.scene = mesh.parentScene.instance;
|
|
mesh.parentScene.instance.add(data.instance);
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
GameLib.System.Linking.prototype.instanceCreated = function(data) {
|
|
|
|
this.resolveDependencies(data.component);
|
|
|
|
if (data.component instanceof GameLib.D3.Image) {
|
|
/**
|
|
* Find all textures which use this image
|
|
*/
|
|
GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Texture).map(
|
|
function(texture) {
|
|
if (texture.image === data.component ||
|
|
texture.images.indexOf(data.component) !== -1
|
|
) {
|
|
|
|
/**
|
|
* Ok - this image is in use - this should notify materials when its image changes
|
|
*/
|
|
texture.updateInstance('image');
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Link all scenes
|
|
*/
|
|
if (data.component instanceof GameLib.D3.Scene) {
|
|
/**
|
|
* Check ALL components for 'parentScenes' - this is expensive so it checks the register directly
|
|
*/
|
|
GameLib.EntityManager.Instance.register.map(
|
|
function(component) {
|
|
if (component.parentScene === data.component.id) {
|
|
component.parentScene = data.component;
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
if (
|
|
data.component.parentScene &&
|
|
typeof data.component.parentScene === 'string'
|
|
) {
|
|
GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Scene).map(
|
|
function (scene) {
|
|
if (data.component.parentScene === scene.id) {
|
|
data.component.parentScene = scene;
|
|
scene.addObject(data.component);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Link all meshes
|
|
*/
|
|
if (data.component instanceof GameLib.D3.Mesh) {
|
|
|
|
/**
|
|
* Check if this mesh is a parentMesh to any component- this is an expensive call, so check if we should call it
|
|
* Also - it inspects the register directly instead of querying it twice (since it checks ALL components)
|
|
*/
|
|
if (!data.preventParentMeshCheck) {
|
|
GameLib.EntityManager.Instance.register.map(
|
|
function (component) {
|
|
if (component.parentMesh &&
|
|
component.parentMesh === data.component.id ) {
|
|
|
|
component.parentMesh = data.component;
|
|
|
|
/**
|
|
* Check if a component has this mesh as a parent
|
|
*/
|
|
if (component instanceof GameLib.D3.Mesh) {
|
|
component.setParentMesh(data.component);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Maybe this component has a parent mesh
|
|
*/
|
|
if (
|
|
data.component.parentMesh &&
|
|
typeof data.component.parentMesh === 'string'
|
|
) {
|
|
GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh).map(
|
|
function (mesh) {
|
|
if (data.component.parentMesh === mesh.id) {
|
|
|
|
data.component.parentMesh = mesh;
|
|
|
|
if (data.component instanceof GameLib.D3.Mesh) {
|
|
data.component.setParentMesh(mesh);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
if (
|
|
data.component.parentWorld &&
|
|
typeof data.component.parentWorld === 'string'
|
|
) {
|
|
GameLib.EntityManager.Instance.queryComponents(GameLib.D3.PhysicsWorld).map(
|
|
function (world) {
|
|
if (data.component.parentWorld === world.id) {
|
|
data.component.parentWorld = world;
|
|
|
|
if (typeof data.component.instance.addToWorld === 'function') {
|
|
data.component.instance.addToWorld(world.instance);
|
|
console.log('instance added to physics world');
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
};
|
|
|
|
GameLib.System.Linking.prototype.materialTypeChanged = function(data) {
|
|
|
|
var meshes = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh);
|
|
|
|
meshes.map(
|
|
function(mesh){
|
|
var inUse = mesh.materials.reduce(
|
|
function(result, material) {
|
|
if (material === data.material) {
|
|
result = true;
|
|
}
|
|
return result;
|
|
},
|
|
false
|
|
);
|
|
|
|
if (inUse) {
|
|
|
|
if (mesh.materials.length === 1) {
|
|
mesh.instance.material = mesh.materials[0].instance
|
|
} else {
|
|
mesh.instance.material = mesh.materials.map(
|
|
function(material) {
|
|
return material.instance;
|
|
}
|
|
)
|
|
}
|
|
|
|
mesh.instance.geometry.uvsNeedUpdate = true;
|
|
mesh.instance.material.needsUpdate = true;
|
|
}
|
|
|
|
}
|
|
);
|
|
|
|
};
|
|
|
|
/**
|
|
*
|
|
* @param data
|
|
*/
|
|
GameLib.System.Linking.prototype.onParentWorldChange = function(data) {
|
|
|
|
if (
|
|
data.object instanceof GameLib.D3.RigidBody
|
|
) {
|
|
|
|
|
|
if (data.originalWorld instanceof GameLib.D3.PhysicsWorld) {
|
|
data.originalWorld.removeRigidBody(data.object);
|
|
}
|
|
|
|
if (data.newWorld instanceof GameLib.D3.PhysicsWorld) {
|
|
data.newWorld.addRigidBody(data.object);
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* Defines what should happen when a parent scene changes
|
|
* @param data
|
|
*/
|
|
GameLib.System.Linking.prototype.onParentSceneChange = function(data) {
|
|
|
|
if (
|
|
data.object instanceof GameLib.D3.Mesh ||
|
|
data.object instanceof GameLib.D3.Light
|
|
) {
|
|
|
|
/**
|
|
* We remove the helper (if any) from the old scene and add it to the new scene
|
|
*/
|
|
var helper = GameLib.EntityManager.Instance.findHelperByObject(data.object);
|
|
if (helper) {
|
|
|
|
if (data.originalScene && data.originalScene.instance) {
|
|
data.originalScene.instance.remove(helper.instance);
|
|
}
|
|
data.newScene.instance.add(helper.instance);
|
|
}
|
|
|
|
/**
|
|
* We remove the mesh from the old scene and add it to the new scene
|
|
*/
|
|
if (data.originalScene && data.originalScene.removeObject) {
|
|
data.originalScene.removeObject(data.object);
|
|
}
|
|
|
|
if (data.newScene) {
|
|
data.newScene.addObject(data.object);
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* Change parent entity
|
|
* @param data
|
|
*/
|
|
GameLib.System.Linking.prototype.onParentEntityChange = function(data) {
|
|
|
|
if (data.originalEntity instanceof GameLib.Entity) {
|
|
data.originalEntity.removeComponent(data.object);
|
|
}
|
|
|
|
if (data.newEntity instanceof GameLib.Entity) {
|
|
data.newEntity.addComponent(data.object);
|
|
}
|
|
|
|
GameLib.Event.Emit(
|
|
GameLib.Event.PARENT_ENTITY_CHANGED,
|
|
{
|
|
originalEntity : data.originalEntity,
|
|
newEntity : data.newEntity,
|
|
component : data.object
|
|
}
|
|
)
|
|
};
|
|
|
|
/**
|
|
* When a mesh is deleted - build a list of all the mesh children objects - also - find out if any of these
|
|
* children objects are in use by another object - if it is - don't delete it, otherwise, do
|
|
* @param data
|
|
*/
|
|
GameLib.System.Linking.prototype.removeMesh = function(data) {
|
|
|
|
/**
|
|
* First we get the list of all components we would like to delete
|
|
*/
|
|
var componentsToDelete = data.meshes.reduce(
|
|
function(result, mesh) {
|
|
|
|
result.push(mesh);
|
|
|
|
var components = mesh.getChildrenComponents();
|
|
|
|
components.map(function(component){
|
|
result.push(component);
|
|
});
|
|
|
|
return result;
|
|
},
|
|
[]
|
|
);
|
|
|
|
/**
|
|
* Now, we want to get a list of all the meshes which we don't want to delete, and all their children
|
|
*/
|
|
var meshes = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh);
|
|
meshes = meshes.filter(function(mesh){
|
|
return data.meshes.indexOf(mesh) === -1;
|
|
});
|
|
|
|
/**
|
|
* Now we have a list of meshes still in use in meshes, now find all their children
|
|
*/
|
|
var componentsInUse = meshes.reduce(
|
|
function(result, mesh) {
|
|
|
|
result.push(mesh);
|
|
|
|
var components = mesh.getChildrenComponents();
|
|
|
|
components.map(function(component){
|
|
result.push(component);
|
|
});
|
|
|
|
return result;
|
|
},
|
|
[]
|
|
);
|
|
|
|
/**
|
|
* Now we don't want to remove any children in use, so filter out the components in use
|
|
*/
|
|
componentsToDelete = componentsToDelete.filter(
|
|
function(component) {
|
|
return componentsInUse.indexOf(component) === -1;
|
|
}
|
|
);
|
|
|
|
/**
|
|
* componentsToDelete should now be the final list of components to delete
|
|
*/
|
|
componentsToDelete.map(
|
|
function(component){
|
|
component.remove();
|
|
}
|
|
);
|
|
};
|
|
|
|
GameLib.System.Linking.prototype.stop = function() {
|
|
GameLib.System.prototype.stop.call(this);
|
|
/**
|
|
* Components
|
|
*/
|
|
this.componentCreatedSubscription.remove();
|
|
this.componentClonedSubscription.remove();
|
|
this.registerDependenciesSubscription.remove();
|
|
this.componentRemoveSubscription.remove();
|
|
|
|
/**
|
|
* Parents
|
|
*/
|
|
this.parentSceneChangeSubscription.remove();
|
|
this.parentWorldChangeSubscription.remove();
|
|
this.parentEntityChangeSubscription.remove();
|
|
|
|
/**
|
|
* Instances
|
|
*/
|
|
this.instanceCreatedSubscription.remove();
|
|
this.instanceClonedSubscription.remove();
|
|
|
|
/**
|
|
* Meshes
|
|
*/
|
|
this.removeMeshSubscription.remove();
|
|
|
|
/**
|
|
* Images
|
|
*/
|
|
this.imageChangedSubscription.remove();
|
|
|
|
/**
|
|
* Materials
|
|
*/
|
|
this.materialTypeChangedSubscription.remove();
|
|
|
|
/**
|
|
* Arrays
|
|
*/
|
|
this.arrayItemAddedSubscription.remove();
|
|
};
|
|
|