linking system
parent
e725fb4694
commit
9b89113ed9
|
@ -27,7 +27,6 @@ GameLib.Event.SAVE_COMPONENT_ERROR = 0xa;
|
|||
GameLib.Event.COMPONENT_SAVED = 0xb;
|
||||
GameLib.Event.LOAD_COMPONENT = 0xc;
|
||||
GameLib.Event.LOAD_COMPONENT_ERROR = 0xd;
|
||||
GameLib.Event.COMPONENT_LOADED = 0xe;
|
||||
GameLib.Event.LOGGED_IN = 0xf;
|
||||
GameLib.Event.COMPONENT_CREATED = 0x10;
|
||||
GameLib.Event.SCENE_INSTANCE_CREATED = 0x11;
|
||||
|
@ -42,6 +41,7 @@ GameLib.Event.MESH_INSTANCE_CREATED = 0x19;
|
|||
GameLib.Event.MESH_INSTANCE_UPDATED = 0x1a;
|
||||
GameLib.Event.LIGHT_INSTANCE_CREATED = 0x1b;
|
||||
GameLib.Event.LIGHT_INSTANCE_UPDATED = 0x1c;
|
||||
GameLib.Event.DELETE_COMPONENT = 0x1d;
|
||||
|
||||
/**
|
||||
* Subscribe to some events
|
||||
|
|
|
@ -39,17 +39,20 @@ GameLib.Component = function(
|
|||
|
||||
this.dependencies = this.getDependencies();
|
||||
|
||||
this.publish(
|
||||
GameLib.Event.COMPONENT_CREATED,
|
||||
{
|
||||
component : this
|
||||
}
|
||||
);
|
||||
if (this.dependencies.length === 0) {
|
||||
delete this.dependencies;
|
||||
this.loaded = true;
|
||||
this.instance = this.createInstance();
|
||||
}
|
||||
};
|
||||
|
||||
GameLib.Component.prototype = Object.create(GameLib.API.Component.prototype);
|
||||
GameLib.Component.prototype.constructor = GameLib.Component;
|
||||
|
||||
GameLib.Component.prototype.createInstance = function() {
|
||||
|
||||
};
|
||||
|
||||
GameLib.Component.prototype.getDependencies = function() {
|
||||
|
||||
var dependencies = [];
|
||||
|
@ -241,108 +244,21 @@ GameLib.Component.prototype.buildIdToObject = function() {
|
|||
this.built = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Some components need to be loaded first, and are referenced by ID string from other objects.
|
||||
* These components should implement this 'linkObjects' function - this will be implementation specific.
|
||||
* Example: Scene has meshes which have materials which have textures.
|
||||
* However, we don't store the texture inside the material inside the mesh, since they are re-usable among meshes.
|
||||
* Instead, we store them on the scene object, reference them by string id from the mesh, and after scene has loaded,
|
||||
* we link the objects
|
||||
*/
|
||||
// GameLib.Component.prototype.linkObjects = function(idToObject) {
|
||||
//
|
||||
// if (this.loaded) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// this.loaded = true;
|
||||
//
|
||||
// for (var property in this.linkedObjects) {
|
||||
// if (
|
||||
// this.linkedObjects.hasOwnProperty(property) &&
|
||||
// this.hasOwnProperty(property) &&
|
||||
// this[property]
|
||||
// ) {
|
||||
//
|
||||
// if (this.linkedObjects[property] instanceof Array) {
|
||||
// if (this[property] instanceof Array) {
|
||||
//
|
||||
// this[property] = this[property].map(
|
||||
// function(p) {
|
||||
// if (p instanceof Object) {
|
||||
//
|
||||
// /**
|
||||
// * This object is already an object, does not need to be linked
|
||||
// */
|
||||
// if (p.linkObjects) {
|
||||
// p.linkObjects(idToObject);
|
||||
// }
|
||||
//
|
||||
// return p;
|
||||
// } else if (typeof p === 'string') {
|
||||
//
|
||||
// if (!idToObject[p]) {
|
||||
// console.warn('Could not locate the object to be linked in array - fix this');
|
||||
// throw new Error('Could not locate the object to be linked in array - fix this');
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Perform deep-linking
|
||||
// */
|
||||
// if (idToObject[p].linkObjects) {
|
||||
// idToObject[p].linkObjects(idToObject);
|
||||
// }
|
||||
//
|
||||
// return idToObject[p];
|
||||
// } else {
|
||||
// console.warn('Unhandled type : ', p);
|
||||
// throw new Error('Unhandled type : ', p);
|
||||
// }
|
||||
//
|
||||
// }.bind(this)
|
||||
// )
|
||||
// } else {
|
||||
// console.warn('Incompatible Link Type - should be instance of array');
|
||||
// throw new Error('Incompatible Link Type - should be instance of array');
|
||||
// }
|
||||
// } else {
|
||||
//
|
||||
// if (this[property] instanceof Object) {
|
||||
//
|
||||
// /**
|
||||
// * This object is already an object, perform deep linking
|
||||
// */
|
||||
// if (this[property].linkObjects) {
|
||||
// this[property].linkObjects(idToObject);
|
||||
// }
|
||||
//
|
||||
// } else if (typeof this[property] === 'string') {
|
||||
//
|
||||
// if (!idToObject[this[property]]) {
|
||||
// console.warn('Could not locate the object to be linked - fix this');
|
||||
// throw new Error('Could not locate the object to be linked - fix this');
|
||||
// }
|
||||
//
|
||||
// this[property] = idToObject[this[property]];
|
||||
//
|
||||
// //this[property].parentObjects.push(this);
|
||||
//
|
||||
// /**
|
||||
// * Perform deep-linking
|
||||
// */
|
||||
// if (this[property].linkObjects) {
|
||||
// this[property].linkObjects(idToObject);
|
||||
// }
|
||||
// } else {
|
||||
// console.warn('Unhandled property type - fix this : ' + typeof this[property]);
|
||||
// throw new Error('Unhandled property type - fix this : ' + typeof this[property]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// this.loaded = false;
|
||||
// };
|
||||
GameLib.Component.prototype.generateNewIds = function() {
|
||||
|
||||
this.buildIdToObject();
|
||||
|
||||
for (var property in this.idToObject) {
|
||||
if (this.idToObject.hasOwnProperty(property)) {
|
||||
|
||||
var oldId = this.idToObject[property].id;
|
||||
var newId = GameLib.Utils.RandomId();
|
||||
|
||||
this.idToObject[property].id = newId;
|
||||
this.idToObject[property].name = this.idToObject[property].name.replace(oldId,newId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
GameLib.Component.prototype.clone = function() {
|
||||
|
||||
|
|
|
@ -10,16 +10,6 @@ GameLib.EntityManager = function() {
|
|||
|
||||
this.entities = [];
|
||||
|
||||
this.loading = [];
|
||||
|
||||
this.dependencies = {};
|
||||
|
||||
this.subscriptions = [];
|
||||
|
||||
this.checkRegister = [];
|
||||
|
||||
this.registerCallbacks();
|
||||
|
||||
GameLib.Component.call(
|
||||
this,
|
||||
GameLib.Component.COMPONENT_ENTITY_MANAGER,
|
||||
|
@ -124,14 +114,6 @@ GameLib.EntityManager.prototype.addEntity = function(entity) {
|
|||
this.entities.push(entity);
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Adds a system to this manager
|
||||
// * @param system GameLib.System
|
||||
// */
|
||||
// GameLib.EntityManager.prototype.addSystem = function(system) {
|
||||
// this.systems.push(system);
|
||||
// };
|
||||
|
||||
/**
|
||||
* Returns entity by name
|
||||
* @param name
|
||||
|
@ -206,27 +188,32 @@ GameLib.EntityManager.prototype.query = function(components) {
|
|||
*/
|
||||
GameLib.EntityManager.prototype.queryComponents = function(constructors) {
|
||||
|
||||
return this.checkRegister.reduce(
|
||||
function(result, object) {
|
||||
return this.entities.reduce(
|
||||
function(result, entity) {
|
||||
|
||||
if (constructors instanceof Array) {
|
||||
constructors.map(
|
||||
function(constructor) {
|
||||
if (object instanceof constructor) {
|
||||
result.push(object);
|
||||
entity.components.map(
|
||||
function(component) {
|
||||
if (constructors instanceof Array) {
|
||||
constructors.map(
|
||||
function(constructor) {
|
||||
if (component instanceof constructor) {
|
||||
result.push(component);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
if (component instanceof constructors) {
|
||||
result.push(component);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
if (object instanceof constructors) {
|
||||
result.push(object);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return result;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -264,413 +251,3 @@ GameLib.EntityManager.FromObject = function(objectEntityManager) {
|
|||
|
||||
return entityManager;
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines what should happen when a parent scene changes
|
||||
* @param data
|
||||
*/
|
||||
GameLib.EntityManager.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 = this.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);
|
||||
}
|
||||
data.newScene.addObject(data.object);
|
||||
|
||||
/**
|
||||
* We inherit the parent entity of this new scene
|
||||
*/
|
||||
var originalEntity = null;
|
||||
var newEntity = null;
|
||||
|
||||
if (data.object.hasOwnProperty('parentEntity')) {
|
||||
originalEntity = data.object.parentEntity
|
||||
}
|
||||
|
||||
if (data.newScene.hasOwnProperty('parentEntity')) {
|
||||
newEntity = data.newScene.parentEntity;
|
||||
}
|
||||
|
||||
var gui = null;
|
||||
|
||||
if (originalEntity) {
|
||||
|
||||
if (originalEntity.removeComponent) {
|
||||
if (helper) {
|
||||
originalEntity.removeComponent(helper);
|
||||
}
|
||||
originalEntity.removeComponent(data.object);
|
||||
}
|
||||
|
||||
if (originalEntity.getFirstComponent) {
|
||||
gui = originalEntity.getFirstComponent(GameLib.GUI);
|
||||
if (gui) {
|
||||
gui.removeObject(data.object);
|
||||
gui.build(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newEntity) {
|
||||
|
||||
if (newEntity.addComponent) {
|
||||
if (helper) {
|
||||
newEntity.addComponent(helper);
|
||||
}
|
||||
newEntity.addComponent(data.object);
|
||||
}
|
||||
|
||||
if (newEntity.getFirstComponent) {
|
||||
gui = newEntity.getFirstComponent(GameLib.GUI);
|
||||
if (gui) {
|
||||
gui.addObject(data.object);
|
||||
gui.build(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Change parent entity
|
||||
* TODO: also change parent entity of children objects
|
||||
* @param data
|
||||
*/
|
||||
GameLib.EntityManager.prototype.onParentEntityChange = function(data) {
|
||||
|
||||
if (data.originalEntity) {
|
||||
data.originalEntity.removeComponent(data.object);
|
||||
}
|
||||
|
||||
data.newEntity.addComponent(data.object);
|
||||
|
||||
// - ok not so cool - we may have parent entities of entities -
|
||||
// - so not all children should inherit the parent entity
|
||||
// data.object.buildIdToObject();
|
||||
//
|
||||
// for (var property in data.object.idToObject) {
|
||||
// if (data.object.idToObject.hasOwnProperty(property)) {
|
||||
// if (data.object.idToObject[property].hasOwnProperty('parentEntity')) {
|
||||
// data.object.idToObject[property].parentEntity = data.newEntity;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
|
||||
GameLib.EntityManager.prototype.link = function(component, data) {
|
||||
for (var property in component.linkedObjects) {
|
||||
if (component.linkedObjects.hasOwnProperty(property)) {
|
||||
if (component.linkedObjects[property] instanceof Array) {
|
||||
component[property] = component[property].map(function (entry) {
|
||||
if (entry === data.component.id) {
|
||||
return data.component;
|
||||
} else {
|
||||
return entry;
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
if (component[property] &&
|
||||
component[property] === data.component.id) {
|
||||
component[property] = data.component;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
GameLib.EntityManager.prototype.componentCreated = function() {
|
||||
|
||||
var loading = [];
|
||||
|
||||
return function(data) {
|
||||
|
||||
/**
|
||||
* Register this component immediately
|
||||
*/
|
||||
this.checkRegister.push(data.component);
|
||||
|
||||
/**
|
||||
* If we notify ourselves - ignore it
|
||||
*/
|
||||
if (data.component === this) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store this component into our 'loaded' list
|
||||
*/
|
||||
loading.push(data.component);
|
||||
|
||||
/**
|
||||
* Store the dependencies too
|
||||
*/
|
||||
data.component.dependencies.map(function (id) {
|
||||
|
||||
/**
|
||||
* Check if we already processed a component on which this component is dependent
|
||||
*/
|
||||
|
||||
var processedComponent = this.checkRegister.reduce(
|
||||
function(result, component){
|
||||
if (component.id === id){
|
||||
result = component;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
null
|
||||
);
|
||||
|
||||
if (processedComponent) {
|
||||
|
||||
/**
|
||||
* Remove this dependency from the dependency list
|
||||
*/
|
||||
var index = data.component.dependencies.indexOf(id);
|
||||
if (index === -1) {
|
||||
console.log('failed to locate dependency which should exist');
|
||||
}
|
||||
data.component.dependencies.splice(index, 1);
|
||||
|
||||
/**
|
||||
* Now link the component
|
||||
*/
|
||||
this.link(data.component, {component: processedComponent});
|
||||
|
||||
} else {
|
||||
|
||||
if (GameLib.Utils.UndefinedOrNull(this.dependencies[id])) {
|
||||
this.dependencies[id] = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't store duplicate dependencies
|
||||
*/
|
||||
if (this.dependencies[id].indexOf(data.component === -1)) {
|
||||
this.dependencies[id].push(data.component);
|
||||
}
|
||||
}
|
||||
|
||||
}.bind(this));
|
||||
|
||||
/**
|
||||
* Now find all the components which depend on this component
|
||||
*/
|
||||
if (GameLib.Utils.UndefinedOrNull(this.dependencies[data.component.id])) {
|
||||
|
||||
/**
|
||||
* We don't know about any dependencies on this object - but maybe a component still
|
||||
* has to load which has dependencies to this object - this object is in the 'checkRegister'
|
||||
*/
|
||||
|
||||
} else {
|
||||
|
||||
/**
|
||||
* Otherwise, now - for each dependency - check if its loaded
|
||||
*/
|
||||
this.dependencies[data.component.id] = this.dependencies[data.component.id].reduce(
|
||||
|
||||
function (result, component) {
|
||||
|
||||
/**
|
||||
* Remove the actual dependency
|
||||
*/
|
||||
var index = component.dependencies.indexOf(data.component.id);
|
||||
if (index === -1) {
|
||||
console.warn('dependency mismatch');
|
||||
} else {
|
||||
component.dependencies.splice(index, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the actual place where this object should be linked - and link them
|
||||
*/
|
||||
this.link(component, data);
|
||||
|
||||
/**
|
||||
* If we now managed to link the objects, and this object has no more dependencies
|
||||
*/
|
||||
if (component.dependencies.length === 0) {
|
||||
component.loaded = true;
|
||||
component.instance = component.createInstance();
|
||||
this.emitInstanceEvents(component);
|
||||
delete component.dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Also remove this from the current dependency list
|
||||
*/
|
||||
return result;
|
||||
}.bind(this),
|
||||
[]
|
||||
);
|
||||
|
||||
delete this.dependencies[data.component.id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Now if this new component has no dependencies, load it
|
||||
*/
|
||||
if (data.component.dependencies.length === 0) {
|
||||
data.component.loaded = true;
|
||||
data.component.instance = data.component.createInstance();
|
||||
this.emitInstanceEvents(data.component);
|
||||
delete data.component.dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Now check if all components are loaded, i.e., no more dependencies - if so - create their instance objects
|
||||
*/
|
||||
var loaded = true;
|
||||
for (var i = 0; i < loading.length; i++) {
|
||||
if (!loading[i].loaded) {
|
||||
loaded = false;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All components loaded
|
||||
*/
|
||||
if (loaded) {
|
||||
loading = [];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
GameLib.EntityManager.prototype.emitInstanceEvents = function (component) {
|
||||
|
||||
if (
|
||||
component instanceof GameLib.D3.Mesh
|
||||
) {
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.MESH_INSTANCE_CREATED,
|
||||
{
|
||||
mesh: component
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
component instanceof GameLib.D3.Light
|
||||
) {
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.LIGHT_INSTANCE_CREATED,
|
||||
{
|
||||
light: component
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
component instanceof GameLib.D3.Scene
|
||||
) {
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.SCENE_INSTANCE_CREATED,
|
||||
{
|
||||
scene: component
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
component instanceof GameLib.D3.Material
|
||||
) {
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.MATERIAL_INSTANCE_CREATED,
|
||||
{
|
||||
material: component
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
component instanceof GameLib.D3.Texture
|
||||
) {
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.TEXTURE_INSTANCE_CREATED,
|
||||
{
|
||||
texture: component
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
GameLib.EntityManager.prototype.registerCallbacks = function() {
|
||||
|
||||
this.subscriptions.push(
|
||||
this.subscribe(
|
||||
GameLib.Event.PARENT_SCENE_CHANGE,
|
||||
this.onParentSceneChange
|
||||
)
|
||||
);
|
||||
|
||||
this.subscriptions.push(
|
||||
this.subscribe(
|
||||
GameLib.Event.PARENT_ENTITY_CHANGE,
|
||||
this.onParentEntityChange
|
||||
)
|
||||
);
|
||||
|
||||
this.subscriptions.push(
|
||||
this.subscribe(
|
||||
GameLib.Event.COMPONENT_CREATED,
|
||||
this.componentCreated().bind(this)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Links object Ids to actual objects
|
||||
* @param idToObject
|
||||
*/
|
||||
// GameLib.EntityManager.prototype.linkObjects = function(idToObject) {
|
||||
//
|
||||
// this.entities.map(
|
||||
// function(entity) {
|
||||
// entity.components.map(
|
||||
// function (componentId, index, array) {
|
||||
// if (componentId instanceof GameLib.Component) {
|
||||
// array[index] = componentId;
|
||||
// } else {
|
||||
// array[index] = idToObject[componentId];
|
||||
// }
|
||||
//
|
||||
// Object.keys(array[index].linkedObjects).map(
|
||||
// function (propertyName) {
|
||||
// array[index][propertyName] = idToObject[array[index][propertyName]];
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// array[index].loaded = true;
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// );
|
||||
//
|
||||
// };
|
|
@ -41,6 +41,7 @@ GameLib.System.SYSTEM_TYPE_INPUT = 0x4;
|
|||
GameLib.System.SYSTEM_TYPE_STORAGE = 0x8;
|
||||
GameLib.System.SYSTEM_TYPE_GUI = 0x10;
|
||||
GameLib.System.SYSTEM_TYPE_PHYSICS = 0x20;
|
||||
GameLib.System.SYSTEM_TYPE_LINKING = 0x40;
|
||||
GameLib.System.SYSTEM_TYPE_ALL = 0xFFFF;
|
||||
|
||||
GameLib.System.prototype.createInstance = function() {
|
||||
|
|
|
@ -0,0 +1,710 @@
|
|||
/**
|
||||
* 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 = {};
|
||||
|
||||
/**
|
||||
* 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.componentCreatedSubscription = null;
|
||||
this.parentSceneChangeSubscription = null;
|
||||
this.parentEntityChangeSubscription = null;
|
||||
this.meshInstanceCreatedSubscription = null;
|
||||
this.lightInstanceCreatedSubscription = null;
|
||||
this.sceneInstanceCreatedSubscription = null;
|
||||
this.imageInstanceCreatedSubscription = null;
|
||||
this.textureInstanceCreatedSubscription = null;
|
||||
this.materialInstanceCreatedSubscription = null;
|
||||
};
|
||||
|
||||
GameLib.System.Linking.prototype = Object.create(GameLib.System.prototype);
|
||||
GameLib.System.Linking.prototype.constructor = GameLib.System.Linking;
|
||||
|
||||
GameLib.System.Linking.prototype.start = function() {
|
||||
|
||||
this.register = GameLib.EntityManager.Instance.queryComponents([GameLib.Component]);
|
||||
|
||||
this.componentCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.COMPONENT_CREATED,
|
||||
this.componentCreated().bind(this)
|
||||
);
|
||||
|
||||
this.parentSceneChangeSubscription = this.subscribe(
|
||||
GameLib.Event.PARENT_SCENE_CHANGE,
|
||||
this.onParentSceneChange
|
||||
);
|
||||
|
||||
this.parentEntityChangeSubscription = this.subscribe(
|
||||
GameLib.Event.PARENT_ENTITY_CHANGE,
|
||||
this.onParentEntityChange
|
||||
);
|
||||
|
||||
this.sceneInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.SCENE_INSTANCE_CREATED,
|
||||
this.sceneInstanceCreated
|
||||
);
|
||||
|
||||
this.meshInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.MESH_INSTANCE_CREATED,
|
||||
this.meshInstanceCreated
|
||||
);
|
||||
|
||||
this.lightInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.LIGHT_INSTANCE_CREATED,
|
||||
this.lightInstanceCreated
|
||||
);
|
||||
|
||||
this.imageInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.IMAGE_INSTANCE_CREATED,
|
||||
this.imageInstanceCreated
|
||||
);
|
||||
|
||||
this.textureInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.TEXTURE_INSTANCE_CREATED,
|
||||
this.textureInstanceCreated
|
||||
);
|
||||
|
||||
this.materialInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.MATERIAL_INSTANCE_CREATED,
|
||||
this.materialInstanceCreated
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
GameLib.EntityManager.prototype.emitInstanceEvents = function (component) {
|
||||
|
||||
if (
|
||||
component instanceof GameLib.D3.Mesh
|
||||
) {
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.MESH_INSTANCE_CREATED,
|
||||
{
|
||||
mesh: component
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
component instanceof GameLib.D3.Light
|
||||
) {
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.LIGHT_INSTANCE_CREATED,
|
||||
{
|
||||
light: component
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
component instanceof GameLib.D3.Scene
|
||||
) {
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.SCENE_INSTANCE_CREATED,
|
||||
{
|
||||
scene: component
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
component instanceof GameLib.D3.Material
|
||||
) {
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.MATERIAL_INSTANCE_CREATED,
|
||||
{
|
||||
material: component
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
component instanceof GameLib.D3.Texture
|
||||
) {
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.TEXTURE_INSTANCE_CREATED,
|
||||
{
|
||||
texture: component
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
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) {
|
||||
component[property] = component[property].map(function (entry) {
|
||||
if (entry === data.component.id) {
|
||||
return data.component;
|
||||
} else {
|
||||
return entry;
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
if (component[property] &&
|
||||
component[property] === data.component.id) {
|
||||
component[property] = data.component;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
GameLib.System.Linking.prototype.componentCreated = function(data) {
|
||||
|
||||
/**
|
||||
* Shorthand
|
||||
*/
|
||||
var component = data.component;
|
||||
|
||||
/**
|
||||
* Register this component immediately
|
||||
*/
|
||||
this.register.push(component);
|
||||
|
||||
/**
|
||||
* We only care about components with unloaded dependencies -
|
||||
* other components will have already had their instance objects created
|
||||
*/
|
||||
if (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 = this.register.reduce(
|
||||
function(result, component){
|
||||
if (component.id === id){
|
||||
result = component;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
null
|
||||
);
|
||||
|
||||
if (processedComponent) {
|
||||
|
||||
/**
|
||||
* Link the component
|
||||
*/
|
||||
this.link(component, {component: 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Also - we remember that this component has a dependency
|
||||
*/
|
||||
result.push(id);
|
||||
}
|
||||
|
||||
return result;
|
||||
}.bind(this),
|
||||
[]
|
||||
);
|
||||
|
||||
if (component.dependencies.length === 0) {
|
||||
component.loaded = true;
|
||||
component.instance = component.createInstance();
|
||||
this.emitInstanceEvents(component);
|
||||
delete component.dependencies;
|
||||
}
|
||||
}
|
||||
|
||||
var parentComponents = this.dependencies[component.id];
|
||||
|
||||
/**
|
||||
* Now find all the components which depend on this component
|
||||
*/
|
||||
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 for later use
|
||||
*/
|
||||
|
||||
} else {
|
||||
|
||||
parentComponents.map(
|
||||
function(parentComponent) {
|
||||
this.link(parentComponent, {component: component});
|
||||
|
||||
/**
|
||||
* Remove the actual dependency
|
||||
*/
|
||||
var index = parentComponent.dependencies.indexOf(component.id);
|
||||
if (index === -1) {
|
||||
console.warn('dependency mismatch');
|
||||
} else {
|
||||
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.loaded = true;
|
||||
parentComponent.instance = parentComponent.createInstance();
|
||||
this.emitInstanceEvents(parentComponent);
|
||||
delete parentComponent.dependencies;
|
||||
}
|
||||
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
delete this.dependencies[component.id];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
GameLib.System.Linking.prototype.meshInstanceCreated = function(data) {
|
||||
|
||||
var scenes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Scene]);
|
||||
|
||||
scenes.map(function(scene){
|
||||
if (data.mesh.parentScene === scene) {
|
||||
scene.addObject(data.mesh);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
GameLib.System.Linking.prototype.lightInstanceCreated = function(data) {
|
||||
|
||||
var scenes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Scene]);
|
||||
|
||||
scenes.map(function(scene){
|
||||
if (data.light.parentScene === scene) {
|
||||
scene.addObject(data.light);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
GameLib.System.Linking.prototype.sceneInstanceCreated = function(data) {
|
||||
|
||||
var scene = data.scene;
|
||||
|
||||
scene.images.map(
|
||||
function(image){
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.LOAD_IMAGE,
|
||||
{
|
||||
onLoaded : function(image) {
|
||||
if (this.onImageLoaded) {
|
||||
this.onImageLoaded(image);
|
||||
}
|
||||
},
|
||||
onProgress : function(image, progress) {
|
||||
if (this.onImageProgress) {
|
||||
this.onImageProgress(image, progress);
|
||||
}
|
||||
},
|
||||
onError : function(image, error) {
|
||||
if (this.onImageError) {
|
||||
this.onImageError(image, error);
|
||||
}
|
||||
},
|
||||
image : image
|
||||
}
|
||||
);
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
/**
|
||||
* Add all meshes and lights
|
||||
*/
|
||||
var object = GameLib.EntityManager.Instance.queryComponents([
|
||||
GameLib.D3.Mesh,
|
||||
GameLib.D3.Light
|
||||
]);
|
||||
object.map(function(object){
|
||||
if (
|
||||
object.parentScene === scene
|
||||
) {
|
||||
scene.addObject(object);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
GameLib.System.Linking.prototype.imageInstanceCreated = function(data) {
|
||||
|
||||
var textures = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Texture]);
|
||||
|
||||
textures.map(
|
||||
function(texture) {
|
||||
/**
|
||||
* Only work with images that belong to this texture
|
||||
*/
|
||||
if (
|
||||
texture.image === data.image
|
||||
) {
|
||||
/**
|
||||
* Update instance, if already an instance
|
||||
*/
|
||||
if (texture.instance) {
|
||||
texture.updateInstance();
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.TEXTURE_INSTANCE_UPDATED,
|
||||
{
|
||||
texture : texture
|
||||
}
|
||||
)
|
||||
} else {
|
||||
/**
|
||||
* Create a new instance
|
||||
*/
|
||||
texture.instance = texture.createInstance();
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.TEXTURE_INSTANCE_CREATED,
|
||||
{
|
||||
texture : texture
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
GameLib.System.Linking.prototype.textureInstanceCreated = function(data) {
|
||||
|
||||
var materials = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Material]);
|
||||
|
||||
materials.map(
|
||||
|
||||
function(material) {
|
||||
|
||||
if (!material.instance) {
|
||||
console.log('No material instance for ' + material.name);
|
||||
return;
|
||||
}
|
||||
|
||||
var modified = false;
|
||||
|
||||
/**
|
||||
* We also need to check if the image of the texture is assigned -
|
||||
* if not we should disable the map
|
||||
*/
|
||||
if (material.alphaMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.alphaMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.alphaMap = null;
|
||||
}
|
||||
|
||||
modified = true;
|
||||
}
|
||||
if (material.aoMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.aoMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.aoMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.bumpMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.bumpMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.bumpMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.diffuseMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.map = data.texture.instance;
|
||||
} else {
|
||||
material.instance.map = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.displacementMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.displacementMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.displacementMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.emissiveMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.emissiveMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.emissiveMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.environmentMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.envMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.envMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.lightMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.lightMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.lightMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.metalnessMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.metalnessMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.metalnessMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.normalMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.normalMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.normalMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.roughnessMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.roughnessMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.roughnessMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.specularMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.specularMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.specularMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
material.updateInstance();
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.MATERIAL_INSTANCE_UPDATED,
|
||||
{
|
||||
material : material
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
GameLib.System.Linking.prototype.materialInstanceCreated = function(data) {
|
||||
|
||||
var meshes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Mesh]);
|
||||
|
||||
meshes.map(function(mesh){
|
||||
|
||||
if (!mesh.instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only work with materials assigned to us
|
||||
*/
|
||||
if (mesh.materials[0] !== data.material) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mesh.instance.material === data.material.instance) {
|
||||
//mesh.instance.geometry.uvsNeedUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mesh.materials[0] === data.material) {
|
||||
|
||||
if (mesh.instance.material !== data.material.instance) {
|
||||
mesh.instance.material = data.material.instance;
|
||||
}
|
||||
|
||||
//mesh.instance.geometry.uvsNeedUpdate = true;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 = this.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);
|
||||
}
|
||||
data.newScene.addObject(data.object);
|
||||
|
||||
/**
|
||||
* We inherit the parent entity of this new scene
|
||||
*/
|
||||
var originalEntity = null;
|
||||
var newEntity = null;
|
||||
|
||||
if (data.object.hasOwnProperty('parentEntity')) {
|
||||
originalEntity = data.object.parentEntity
|
||||
}
|
||||
|
||||
if (data.newScene.hasOwnProperty('parentEntity')) {
|
||||
newEntity = data.newScene.parentEntity;
|
||||
}
|
||||
|
||||
var gui = null;
|
||||
|
||||
if (originalEntity) {
|
||||
|
||||
if (originalEntity.removeComponent) {
|
||||
if (helper) {
|
||||
originalEntity.removeComponent(helper);
|
||||
}
|
||||
originalEntity.removeComponent(data.object);
|
||||
}
|
||||
|
||||
if (originalEntity.getFirstComponent) {
|
||||
gui = originalEntity.getFirstComponent(GameLib.GUI);
|
||||
if (gui) {
|
||||
gui.removeObject(data.object);
|
||||
gui.build(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newEntity) {
|
||||
|
||||
if (newEntity.addComponent) {
|
||||
if (helper) {
|
||||
newEntity.addComponent(helper);
|
||||
}
|
||||
newEntity.addComponent(data.object);
|
||||
}
|
||||
|
||||
if (newEntity.getFirstComponent) {
|
||||
gui = newEntity.getFirstComponent(GameLib.GUI);
|
||||
if (gui) {
|
||||
gui.addObject(data.object);
|
||||
gui.build(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Change parent entity
|
||||
* TODO: also change parent entity of children objects
|
||||
* @param data
|
||||
*/
|
||||
GameLib.System.Linking.prototype.onParentEntityChange = function(data) {
|
||||
|
||||
if (data.originalEntity) {
|
||||
data.originalEntity.removeComponent(data.object);
|
||||
}
|
||||
|
||||
data.newEntity.addComponent(data.object);
|
||||
|
||||
// - ok not so cool - we may have parent entities of entities -
|
||||
// - so not all children should inherit the parent entity
|
||||
// data.object.buildIdToObject();
|
||||
//
|
||||
// for (var property in data.object.idToObject) {
|
||||
// if (data.object.idToObject.hasOwnProperty(property)) {
|
||||
// if (data.object.idToObject[property].hasOwnProperty('parentEntity')) {
|
||||
// data.object.idToObject[property].parentEntity = data.newEntity;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
GameLib.System.Linking.prototype.stop = function() {
|
||||
this.register = [];
|
||||
this.componentCreatedSubscription.remove();
|
||||
this.parentSceneChangeSubscription.remove();
|
||||
this.parentEntityChangeSubscription.remove();
|
||||
this.meshInstanceCreatedSubscription.remove();
|
||||
this.lightInstanceCreatedSubscription.remove();
|
||||
this.sceneInstanceCreatedSubscription.remove();
|
||||
this.imageInstanceCreatedSubscription.remove();
|
||||
this.textureInstanceCreatedSubscription.remove();
|
||||
this.materialInstanceCreatedSubscription.remove();
|
||||
};
|
||||
|
|
@ -7,6 +7,9 @@
|
|||
* @param onImageLoaded
|
||||
* @param onImageProgress
|
||||
* @param onImageError
|
||||
* @param onComponentLoaded
|
||||
* @param onComponentProgress
|
||||
* @param onComponentError
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.System.Storage = function(
|
||||
|
@ -16,7 +19,10 @@ GameLib.System.Storage = function(
|
|||
apiUploadUrl,
|
||||
onImageLoaded,
|
||||
onImageProgress,
|
||||
onImageError
|
||||
onImageError,
|
||||
onComponentLoaded,
|
||||
onComponentProgress,
|
||||
onComponentError
|
||||
) {
|
||||
GameLib.System.call(
|
||||
this,
|
||||
|
@ -55,17 +61,25 @@ GameLib.System.Storage = function(
|
|||
}
|
||||
this.onImageError = onImageError;
|
||||
|
||||
if (GameLib.Utils.UndefinedOrNull(onComponentLoaded)) {
|
||||
onComponentLoaded = null;
|
||||
}
|
||||
this.onComponentLoaded = onComponentLoaded;
|
||||
|
||||
if (GameLib.Utils.UndefinedOrNull(onComponentProgress)) {
|
||||
onComponentProgress = null;
|
||||
}
|
||||
this.onComponentProgress = onComponentProgress;
|
||||
|
||||
if (GameLib.Utils.UndefinedOrNull(onComponentError)) {
|
||||
onComponentError = null;
|
||||
}
|
||||
this.onComponentError = onComponentError;
|
||||
|
||||
this.loginSubscription = null;
|
||||
this.saveSubscription = null;
|
||||
this.loadSubscription = null;
|
||||
this.loadImageSubscription = null;
|
||||
this.meshInstanceCreatedSubscription = null;
|
||||
this.lightInstanceCreatedSubscription = null;
|
||||
this.sceneInstanceCreatedSubscription = null;
|
||||
this.imageInstanceCreatedSubscription = null;
|
||||
this.textureInstanceCreatedSubscription = null;
|
||||
this.materialInstanceCreatedSubscription = null;
|
||||
|
||||
};
|
||||
|
||||
GameLib.System.Storage.prototype = Object.create(GameLib.System.prototype);
|
||||
|
@ -94,36 +108,6 @@ GameLib.System.Storage.prototype.start = function() {
|
|||
GameLib.Event.LOAD_IMAGE,
|
||||
this.loadImage
|
||||
);
|
||||
|
||||
this.sceneInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.SCENE_INSTANCE_CREATED,
|
||||
this.sceneInstanceCreated
|
||||
);
|
||||
|
||||
this.meshInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.MESH_INSTANCE_CREATED,
|
||||
this.meshInstanceCreated
|
||||
);
|
||||
|
||||
this.lightInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.LIGHT_INSTANCE_CREATED,
|
||||
this.lightInstanceCreated
|
||||
);
|
||||
|
||||
this.imageInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.IMAGE_INSTANCE_CREATED,
|
||||
this.imageInstanceCreated
|
||||
);
|
||||
|
||||
this.textureInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.TEXTURE_INSTANCE_CREATED,
|
||||
this.textureInstanceCreated
|
||||
);
|
||||
|
||||
this.materialInstanceCreatedSubscription = this.subscribe(
|
||||
GameLib.Event.MATERIAL_INSTANCE_CREATED,
|
||||
this.materialInstanceCreated
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -194,51 +178,231 @@ GameLib.System.Storage.prototype.load = function(data) {
|
|||
return;
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
/**
|
||||
* Load all the ids into our 'loading' list
|
||||
*/
|
||||
var loading = data.ids.reduce(
|
||||
function(result, id) {
|
||||
|
||||
xhr.open(
|
||||
'GET',
|
||||
data.url
|
||||
if (result.indexOf(id) === -1) {
|
||||
result.push(id);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
xhr.onreadystatechange = function (xhr) {
|
||||
return function () {
|
||||
if (xhr.readyState === 4) {
|
||||
var loaded = [];
|
||||
|
||||
try {
|
||||
var object = JSON.parse(xhr.responseText);
|
||||
} catch (error) {
|
||||
this.publish(
|
||||
GameLib.Event.LOAD_COMPONENT_ERROR,
|
||||
{
|
||||
error : error
|
||||
}
|
||||
);
|
||||
return;
|
||||
var includeDependencies = data.includeDependencies;
|
||||
|
||||
var onComponentLoaded = this.onComponentLoaded;
|
||||
|
||||
var onComponentProgress = this.onComponentProgress;
|
||||
|
||||
var onComponentError = this.onComponentError;
|
||||
|
||||
while (loading.length > 0) {
|
||||
|
||||
var id = loading.pop();
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.onload = function () {
|
||||
|
||||
try {
|
||||
var object = JSON.parse(this.responseText);
|
||||
} catch (error) {
|
||||
|
||||
if (onComponentError) {
|
||||
onComponentError(error);
|
||||
}
|
||||
|
||||
if (object.result !== 'success') {
|
||||
this.publish(
|
||||
GameLib.Event.LOAD_COMPONENT_ERROR,
|
||||
{
|
||||
error : object
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.publish(
|
||||
GameLib.Event.COMPONENT_LOADED,
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.LOAD_COMPONENT_ERROR,
|
||||
{
|
||||
response : object,
|
||||
includeDependencies : data.includeDependencies
|
||||
error: error
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (object.result !== 'success') {
|
||||
|
||||
if (onComponentError) {
|
||||
onComponentError(error);
|
||||
}
|
||||
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.LOAD_COMPONENT_ERROR,
|
||||
{
|
||||
error: error
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Now we need to create the runtime component - this happens systematically.
|
||||
* First, we create an API object from the Object, then a Runtime object from the API object
|
||||
* Each component has a function 'FromObject' which essentially does this for you
|
||||
*/
|
||||
var componentName = GameLib.Component.GetComponentName(object.componentType);
|
||||
|
||||
var componentClass = eval(componentName);
|
||||
|
||||
var fn = componentClass['FromObject'];
|
||||
|
||||
var runtimeComponent = null;
|
||||
|
||||
if (object.componentType === GameLib.Component.COMPONENT_ENTITY) {
|
||||
runtimeComponent = fn(object, GameLib.EntityManager.Instance);
|
||||
} else {
|
||||
runtimeComponent = fn(this.graphics, object);
|
||||
}
|
||||
|
||||
loaded.push(runtimeComponent.id);
|
||||
|
||||
if (includeDependencies) {
|
||||
/**
|
||||
* Before we announce the creation of this component, we should get
|
||||
* a list of all dependencies of this object, because once we announce
|
||||
* the creation of this object - the linking system will attempt to resolve
|
||||
* all dependencies
|
||||
*/
|
||||
var dependencies = runtimeComponent.dependencies.map(function (dependency) {
|
||||
return dependency;
|
||||
});
|
||||
|
||||
/**
|
||||
* Now - we should systematically check if we have the dependency already
|
||||
* loaded (in our runtime environment) - if we have - we just ignore loading this dependency (for now)
|
||||
* TODO: decide what to do with runtime versions of 'stale' dependencies
|
||||
*/
|
||||
var components = GameLib.EntityManager.Instance.queryComponents(componentClass);
|
||||
|
||||
dependencies = dependencies.reduce(
|
||||
function (result, dependency) {
|
||||
|
||||
var found = components.reduce(
|
||||
function (result, component) {
|
||||
if (component.id === dependency) {
|
||||
found = true;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
if (!found) {
|
||||
result.push(dependency);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* Also check if we did not already load this component quite recently
|
||||
*/
|
||||
dependencies = dependencies.reduce(
|
||||
function (result, dependency) {
|
||||
|
||||
var found = loaded.reduce(
|
||||
function (result, id) {
|
||||
if (id === dependency) {
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
if (!found) {
|
||||
result.push(dependency);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* We should now check our 'loading' list and add all dependencies which are not already in there
|
||||
*/
|
||||
dependencies.map(
|
||||
function (dependency) {
|
||||
if (loading.indexOf(dependency) === -1) {
|
||||
loading.push(dependency);
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}(xhr).bind(this);
|
||||
|
||||
xhr.send();
|
||||
/**
|
||||
* Ok - now we have a super good idea of which components still need to load -
|
||||
* they live in the 'loading' list.
|
||||
*
|
||||
* At this point - the runtime components are created, but they are not ready
|
||||
* to be used. They may have dependencies to other objects, which still need
|
||||
* to load, or may never be loaded.
|
||||
*
|
||||
* It is however safe, to announce, that we created the
|
||||
* runtime version of it, however it could still have some dependencies.
|
||||
*
|
||||
* The Linking system will then kick in and try to resolve all dependencies
|
||||
*/
|
||||
|
||||
if (onComponentLoaded) {
|
||||
onComponentLoaded(runtimeComponent);
|
||||
}
|
||||
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.COMPONENT_CREATED,
|
||||
{
|
||||
component: runtimeComponent
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
xhr.onprogress = function(__id) {
|
||||
return function (progressEvent) {
|
||||
|
||||
var progress = 0;
|
||||
|
||||
if (progressEvent.total !== 0) {
|
||||
progress = Number(progressEvent.loaded / progressEvent.total);
|
||||
progress *= 100;
|
||||
}
|
||||
|
||||
if (onComponentProgress) {
|
||||
onComponentProgress(__id, progress)
|
||||
}
|
||||
};
|
||||
}(id);
|
||||
|
||||
xhr.onerror = function(__id) {
|
||||
return function (error) {
|
||||
console.warn('component load failed for component ID ' + __id);
|
||||
if (onComponentError) {
|
||||
onComponentError(__id, error)
|
||||
}
|
||||
};
|
||||
}(id);
|
||||
|
||||
xhr.open(
|
||||
'GET',
|
||||
this.apiUrl + '/component/load/' + id
|
||||
);
|
||||
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
GameLib.System.Storage.prototype.loadImage = function(data) {
|
||||
|
@ -247,7 +411,7 @@ GameLib.System.Storage.prototype.loadImage = function(data) {
|
|||
|
||||
var onLoaded = this.onImageLoaded;
|
||||
|
||||
var onProgress = this.onImageProgress;;
|
||||
var onProgress = this.onImageProgress;
|
||||
|
||||
var onError = this.onImageError;
|
||||
|
||||
|
@ -353,303 +517,10 @@ GameLib.System.Storage.prototype.loadImage = function(data) {
|
|||
preflight.send();
|
||||
};
|
||||
|
||||
GameLib.System.Storage.prototype.meshInstanceCreated = function(data) {
|
||||
|
||||
var scenes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Scene]);
|
||||
|
||||
scenes.map(function(scene){
|
||||
if (data.mesh.parentScene === scene) {
|
||||
scene.addObject(data.mesh);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
GameLib.System.Storage.prototype.lightInstanceCreated = function(data) {
|
||||
|
||||
var scenes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Scene]);
|
||||
|
||||
scenes.map(function(scene){
|
||||
if (data.light.parentScene === scene) {
|
||||
scene.addObject(data.light);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
GameLib.System.Storage.prototype.sceneInstanceCreated = function(data) {
|
||||
|
||||
var scene = data.scene;
|
||||
|
||||
scene.images.map(
|
||||
function(image){
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.LOAD_IMAGE,
|
||||
{
|
||||
onLoaded : function(image) {
|
||||
if (this.onImageLoaded) {
|
||||
this.onImageLoaded(image);
|
||||
}
|
||||
},
|
||||
onProgress : function(image, progress) {
|
||||
if (this.onImageProgress) {
|
||||
this.onImageProgress(image, progress);
|
||||
}
|
||||
},
|
||||
onError : function(image, error) {
|
||||
if (this.onImageError) {
|
||||
this.onImageError(image, error);
|
||||
}
|
||||
},
|
||||
image : image
|
||||
}
|
||||
);
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
/**
|
||||
* Add all meshes and lights
|
||||
*/
|
||||
var object = GameLib.EntityManager.Instance.queryComponents([
|
||||
GameLib.D3.Mesh,
|
||||
GameLib.D3.Light
|
||||
]);
|
||||
object.map(function(object){
|
||||
if (
|
||||
object.parentScene === scene
|
||||
) {
|
||||
scene.addObject(object);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
GameLib.System.Storage.prototype.imageInstanceCreated = function(data) {
|
||||
|
||||
var textures = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Texture]);
|
||||
|
||||
textures.map(
|
||||
function(texture) {
|
||||
/**
|
||||
* Only work with images that belong to this texture
|
||||
*/
|
||||
if (
|
||||
texture.image === data.image
|
||||
) {
|
||||
/**
|
||||
* Update instance, if already an instance
|
||||
*/
|
||||
if (texture.instance) {
|
||||
texture.updateInstance();
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.TEXTURE_INSTANCE_UPDATED,
|
||||
{
|
||||
texture : texture
|
||||
}
|
||||
)
|
||||
} else {
|
||||
/**
|
||||
* Create a new instance
|
||||
*/
|
||||
texture.instance = texture.createInstance();
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.TEXTURE_INSTANCE_CREATED,
|
||||
{
|
||||
texture : texture
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
GameLib.System.Storage.prototype.textureInstanceCreated = function(data) {
|
||||
|
||||
var materials = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Material]);
|
||||
|
||||
materials.map(
|
||||
|
||||
function(material) {
|
||||
|
||||
if (!material.instance) {
|
||||
console.log('No material instance for ' + material.name);
|
||||
return;
|
||||
}
|
||||
|
||||
var modified = false;
|
||||
|
||||
/**
|
||||
* We also need to check if the image of the texture is assigned -
|
||||
* if not we should disable the map
|
||||
*/
|
||||
if (material.alphaMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.alphaMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.alphaMap = null;
|
||||
}
|
||||
|
||||
modified = true;
|
||||
}
|
||||
if (material.aoMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.aoMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.aoMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.bumpMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.bumpMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.bumpMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.diffuseMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.map = data.texture.instance;
|
||||
} else {
|
||||
material.instance.map = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.displacementMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.displacementMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.displacementMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.emissiveMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.emissiveMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.emissiveMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.environmentMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.envMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.envMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.lightMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.lightMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.lightMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.metalnessMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.metalnessMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.metalnessMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.normalMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.normalMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.normalMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.roughnessMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.roughnessMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.roughnessMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
if (material.specularMap === data.texture) {
|
||||
|
||||
if (data.texture.image) {
|
||||
material.instance.specularMap = data.texture.instance;
|
||||
} else {
|
||||
material.instance.specularMap = null;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
material.updateInstance();
|
||||
GameLib.Event.Emit(
|
||||
GameLib.Event.MATERIAL_INSTANCE_UPDATED,
|
||||
{
|
||||
material : material
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
GameLib.System.Storage.prototype.materialInstanceCreated = function(data) {
|
||||
|
||||
var meshes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Mesh]);
|
||||
|
||||
meshes.map(function(mesh){
|
||||
|
||||
if (!mesh.instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only work with materials assigned to us
|
||||
*/
|
||||
if (mesh.materials[0] !== data.material) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mesh.instance.material === data.material.instance) {
|
||||
//mesh.instance.geometry.uvsNeedUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mesh.materials[0] === data.material) {
|
||||
|
||||
if (mesh.instance.material !== data.material.instance) {
|
||||
mesh.instance.material = data.material.instance;
|
||||
}
|
||||
|
||||
//mesh.instance.geometry.uvsNeedUpdate = true;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
GameLib.System.Storage.prototype.stop = function() {
|
||||
this.loginSubscription.remove();
|
||||
this.loadSubscription.remove();
|
||||
this.saveSubscription.remove();
|
||||
this.loadImageSubscription.remove();
|
||||
this.meshInstanceCreatedSubscription.remove();
|
||||
this.lightInstanceCreatedSubscription.remove();
|
||||
this.sceneInstanceCreatedSubscription.remove();
|
||||
this.imageInstanceCreatedSubscription.remove();
|
||||
this.textureInstanceCreatedSubscription.remove();
|
||||
this.materialInstanceCreatedSubscription.remove();
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue