don't store clones, deep clone objects, continue loading when components fail to load, fix entity and renderer toApiObject
parent
b6bb9cb9a7
commit
b59c118ee7
|
@ -478,6 +478,16 @@ GameLib.Component.prototype.buildIdToObject = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this instanceof GameLib.D3.Scene) {
|
||||||
|
this.clones.map(
|
||||||
|
function(clone) {
|
||||||
|
if (this.idToObject.hasOwnProperty(clone.id)) {
|
||||||
|
delete this.idToObject[clone.id];
|
||||||
|
}
|
||||||
|
}.bind(this)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
this.idToObject[this.id] = this;
|
this.idToObject[this.id] = this;
|
||||||
|
|
||||||
this.building = false;
|
this.building = false;
|
||||||
|
@ -487,6 +497,8 @@ GameLib.Component.prototype.generateNewIds = function() {
|
||||||
|
|
||||||
this.buildIdToObject();
|
this.buildIdToObject();
|
||||||
|
|
||||||
|
var codeComponents = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.CustomCode);
|
||||||
|
|
||||||
for (var property in this.idToObject) {
|
for (var property in this.idToObject) {
|
||||||
if (this.idToObject.hasOwnProperty(property)) {
|
if (this.idToObject.hasOwnProperty(property)) {
|
||||||
|
|
||||||
|
@ -495,9 +507,14 @@ GameLib.Component.prototype.generateNewIds = function() {
|
||||||
|
|
||||||
this.idToObject[property].id = newId;
|
this.idToObject[property].id = newId;
|
||||||
this.idToObject[property].name = this.idToObject[property].name.replace(oldId,newId);
|
this.idToObject[property].name = this.idToObject[property].name.replace(oldId,newId);
|
||||||
|
codeComponents.map(function(codeComponent){
|
||||||
|
codeComponent.code = codeComponent.code.replace(oldId,newId);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GameLib.Component.prototype.remove = function() {
|
GameLib.Component.prototype.remove = function() {
|
||||||
|
@ -601,42 +618,42 @@ GameLib.Component.prototype.cloneInstance = function() {
|
||||||
return clone;
|
return clone;
|
||||||
};
|
};
|
||||||
|
|
||||||
GameLib.Component.prototype.getStorageDependencies = function() {
|
// GameLib.Component.prototype.getStorageDependencies = function() {
|
||||||
|
//
|
||||||
var dependencies = {};
|
// var dependencies = {};
|
||||||
|
//
|
||||||
for (var property in this.linkedObjects) {
|
// for (var property in this.linkedObjects) {
|
||||||
if (this.linkedObjects.hasOwnProperty(property)){
|
// if (this.linkedObjects.hasOwnProperty(property)){
|
||||||
if (this.hasOwnProperty(property)) {
|
// if (this.hasOwnProperty(property)) {
|
||||||
|
//
|
||||||
if (
|
// if (
|
||||||
this[property] instanceof Array &&
|
// this[property] instanceof Array &&
|
||||||
this.linkedObjects[property] instanceof Array
|
// this.linkedObjects[property] instanceof Array
|
||||||
) {
|
// ) {
|
||||||
|
//
|
||||||
if (this.linkedObjects[property].length !== 1) {
|
// if (this.linkedObjects[property].length !== 1) {
|
||||||
console.log('Invalid formed argument type');
|
// console.log('Invalid formed argument type');
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
dependencies[property] = this[property].map(
|
// dependencies[property] = this[property].map(
|
||||||
function(__constructor) {
|
// function(__constructor) {
|
||||||
return function(arrayProperty){
|
// return function(arrayProperty){
|
||||||
if (arrayProperty instanceof __constructor) {
|
// if (arrayProperty instanceof __constructor) {
|
||||||
return GameLib.Utils.IdOrNull(arrayProperty);
|
// return GameLib.Utils.IdOrNull(arrayProperty);
|
||||||
}
|
// }
|
||||||
}.bind(this)
|
// }.bind(this)
|
||||||
}(this.linkedObjects[property][0])
|
// }(this.linkedObjects[property][0])
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
} else if (this[property] instanceof this.linkedObjects[property]) {
|
// } else if (this[property] instanceof this.linkedObjects[property]) {
|
||||||
dependencies[property] = GameLib.Utils.IdOrNull(this[property]);
|
// dependencies[property] = GameLib.Utils.IdOrNull(this[property]);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return dependencies;
|
// return dependencies;
|
||||||
};
|
// };
|
||||||
|
|
||||||
GameLib.Component.prototype.saveToRemoteAPI = function() {
|
GameLib.Component.prototype.saveToRemoteAPI = function() {
|
||||||
this.save(true);
|
this.save(true);
|
||||||
|
@ -656,13 +673,13 @@ GameLib.Component.prototype.save = function(remote) {
|
||||||
|
|
||||||
apiObject.componentType = this.idToObject[property].componentType;
|
apiObject.componentType = this.idToObject[property].componentType;
|
||||||
|
|
||||||
var storageDependencies = this.idToObject[property].getStorageDependencies();
|
// var storageDependencies = this.idToObject[property].getStorageDependencies();
|
||||||
|
//
|
||||||
for (var storageProperty in storageDependencies) {
|
// for (var storageProperty in storageDependencies) {
|
||||||
if (storageDependencies.hasOwnProperty(storageProperty)) {
|
// if (storageDependencies.hasOwnProperty(storageProperty)) {
|
||||||
apiObject[storageProperty] = storageDependencies[storageProperty];
|
// apiObject[storageProperty] = storageDependencies[storageProperty];
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.publish(
|
this.publish(
|
||||||
GameLib.Event.SAVE_COMPONENT,
|
GameLib.Event.SAVE_COMPONENT,
|
||||||
|
|
|
@ -274,7 +274,7 @@ GameLib.D3.Renderer.prototype.toApiObject = function() {
|
||||||
this.width,
|
this.width,
|
||||||
this.height,
|
this.height,
|
||||||
this.preserveDrawingBuffer,
|
this.preserveDrawingBuffer,
|
||||||
this.domElement.toApiObject(),
|
GameLib.Utils.IdOrNull(this.domElement),
|
||||||
this.clearColor.toApiObject(),
|
this.clearColor.toApiObject(),
|
||||||
GameLib.Utils.IdOrNull(this.camera),
|
GameLib.Utils.IdOrNull(this.camera),
|
||||||
this.scenes.map(function(scene){
|
this.scenes.map(function(scene){
|
||||||
|
|
|
@ -290,16 +290,35 @@ GameLib.D3.Scene.prototype.updateInstance = function(property) {
|
||||||
*/
|
*/
|
||||||
GameLib.D3.Scene.prototype.toApiObject = function() {
|
GameLib.D3.Scene.prototype.toApiObject = function() {
|
||||||
|
|
||||||
var apiMeshes = this.meshes.map(
|
var apiMeshes = this.meshes.reduce(
|
||||||
function(mesh) {
|
function(result, mesh) {
|
||||||
return GameLib.Utils.IdOrNull(mesh);
|
|
||||||
}
|
/**
|
||||||
|
* Do not store any cloned meshes
|
||||||
|
*/
|
||||||
|
if (this.clones.indexOf(mesh) === -1) {
|
||||||
|
result.push(GameLib.Utils.IdOrNull(mesh));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}.bind(this),
|
||||||
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
var apiLights = this.lights.map(
|
var apiLights = this.lights.reduce(
|
||||||
function(light) {
|
function(result, light) {
|
||||||
return GameLib.Utils.IdOrNull(light);
|
|
||||||
}
|
/**
|
||||||
|
* Do not store any cloned lights
|
||||||
|
*/
|
||||||
|
if (this.clones.indexOf(light) === -1) {
|
||||||
|
result.push(GameLib.Utils.IdOrNull(light));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}.bind(this),
|
||||||
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
var apiTextures = this.textures.map(
|
var apiTextures = this.textures.map(
|
||||||
|
|
|
@ -188,16 +188,10 @@ GameLib.Entity.prototype.updateInstance = function() {
|
||||||
*/
|
*/
|
||||||
GameLib.Entity.prototype.toApiObject = function() {
|
GameLib.Entity.prototype.toApiObject = function() {
|
||||||
|
|
||||||
var apiComponents = this.components.reduce(
|
var apiComponents = this.components.map(
|
||||||
function(result, component) {
|
function(component) {
|
||||||
if (typeof component.toApiObject === 'function') {
|
return GameLib.Utils.IdOrNull(component);
|
||||||
result.push(component.toApiObject());
|
}
|
||||||
} else {
|
|
||||||
console.log('ignored runtime component : ' + component.name);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return new GameLib.API.Entity(
|
return new GameLib.API.Entity(
|
||||||
|
|
|
@ -479,7 +479,9 @@ GameLib.System.Linking.prototype.componentCloned = function(data) {
|
||||||
throw new Error('no scene parent');
|
throw new Error('no scene parent');
|
||||||
}
|
}
|
||||||
|
|
||||||
data.parent.parentScene.addClone(data.component);
|
if (data.parent.parentScene) {
|
||||||
|
data.parent.parentScene.addClone(data.component);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -362,31 +362,33 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
|
|
||||||
return function () {
|
return function () {
|
||||||
|
|
||||||
|
var error = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var object = JSON.parse(this.responseText);
|
var object = JSON.parse(this.responseText);
|
||||||
} catch (error) {
|
} catch (errorObject) {
|
||||||
|
|
||||||
if (onComponentError) {
|
if (onComponentError) {
|
||||||
onComponentError(error);
|
onComponentError(errorObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientErrorCallback) {
|
if (clientErrorCallback) {
|
||||||
clientErrorCallback({
|
clientErrorCallback({
|
||||||
message : error.message || 'JSON parse error'
|
message : errorObject.message || 'JSON parse error'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
GameLib.Event.Emit(
|
GameLib.Event.Emit(
|
||||||
GameLib.Event.LOAD_COMPONENT_ERROR,
|
GameLib.Event.LOAD_COMPONENT_ERROR,
|
||||||
{
|
{
|
||||||
error: error
|
error: errorObject
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.result !== 'success') {
|
if (!error && object.result !== 'success') {
|
||||||
|
|
||||||
if (onComponentError) {
|
if (onComponentError) {
|
||||||
onComponentError(id, object);
|
onComponentError(id, object);
|
||||||
|
@ -403,15 +405,19 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
{error : object}
|
{error : object}
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
var runtimeComponent = null;
|
||||||
* 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
|
if (!error) {
|
||||||
* Each component has a function 'FromObject' which essentially does this for you
|
|
||||||
*/
|
/**
|
||||||
object.component.map(function (component) {
|
* 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 component = object.component[0];
|
||||||
|
|
||||||
var componentName = GameLib.Component.GetComponentName(component.componentType);
|
var componentName = GameLib.Component.GetComponentName(component.componentType);
|
||||||
|
|
||||||
|
@ -419,8 +425,6 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
|
|
||||||
var fn = componentClass['FromObject'];
|
var fn = componentClass['FromObject'];
|
||||||
|
|
||||||
var runtimeComponent = null;
|
|
||||||
|
|
||||||
if (component.componentType === GameLib.Component.COMPONENT_ENTITY) {
|
if (component.componentType === GameLib.Component.COMPONENT_ENTITY) {
|
||||||
runtimeComponent = fn(component, GameLib.EntityManager.Instance);
|
runtimeComponent = fn(component, GameLib.EntityManager.Instance);
|
||||||
runtimeComponent.parentEntity = parentEntity;
|
runtimeComponent.parentEntity = parentEntity;
|
||||||
|
@ -464,146 +468,150 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!runtimeComponent) {
|
if (!runtimeComponent) {
|
||||||
if (clientErrorCallback) {
|
if (clientErrorCallback) {
|
||||||
clientErrorCallback({result : 'failure', message : 'Could not create a runtime component: ' + component.name});
|
clientErrorCallback({
|
||||||
|
result: 'failure',
|
||||||
|
message: 'Could not create a runtime component: ' + component.name
|
||||||
|
});
|
||||||
}
|
}
|
||||||
//throw new Error('Could not create a runtime component: ' + component.name);
|
//throw new Error('Could not create a runtime component: ' + component.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parentEntity !== null && runtimeComponent) {
|
if (parentEntity !== null && runtimeComponent) {
|
||||||
runtimeComponent.parentEntity = parentEntity;
|
runtimeComponent.parentEntity = parentEntity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (runtimeComponent) {
|
if (runtimeComponent) {
|
||||||
loaded.push(runtimeComponent);
|
loaded.push(runtimeComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeDependencies && runtimeComponent) {
|
if (includeDependencies && runtimeComponent) {
|
||||||
/**
|
/**
|
||||||
* Before we announce the creation of this component, we should get
|
* Before we announce the creation of this component, we should get
|
||||||
* a list of all dependencies of this component, because once we announce
|
* a list of all dependencies of this component, because once we announce
|
||||||
* the creation of this component - the linking system will attempt to resolve
|
* the creation of this component - the linking system will attempt to resolve
|
||||||
* all dependencies
|
* all dependencies
|
||||||
*/
|
*/
|
||||||
var dependencies = runtimeComponent.getDependencies();
|
var dependencies = runtimeComponent.getDependencies();
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
*
|
|
||||||
* We don't override runtime versions of the same component in the database because the user
|
|
||||||
* could be working with it and it should be the latest version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
dependencies = dependencies.reduce(
|
|
||||||
function (result, dependency) {
|
|
||||||
|
|
||||||
if (GameLib.EntityManager.Instance.findComponentById(dependency)) {
|
|
||||||
/**
|
|
||||||
* Don't add the dependency
|
|
||||||
*/
|
|
||||||
} else {
|
|
||||||
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, component) {
|
|
||||||
if (component.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ok - now we have a super good idea of which components still need to load -
|
* Now - we should systematically check if we have the dependency already
|
||||||
* they live in the 'loading' list.
|
* loaded (in our runtime environment) - if we have - we just ignore loading this dependency (for now)
|
||||||
*
|
*
|
||||||
* At this point - the runtime components are created, but they are not ready
|
* We don't override runtime versions of the same component in the database because the user
|
||||||
* to be used. They may have dependencies to other components, which still need
|
* could be working with it and it should be the latest version.
|
||||||
* 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 (runtimeComponent && onComponentLoaded) {
|
dependencies = dependencies.reduce(
|
||||||
onComponentLoaded(runtimeComponent);
|
function (result, dependency) {
|
||||||
}
|
|
||||||
|
|
||||||
if (runtimeComponent) {
|
if (GameLib.EntityManager.Instance.findComponentById(dependency)) {
|
||||||
GameLib.Event.Emit(
|
/**
|
||||||
GameLib.Event.COMPONENT_CREATED,
|
* Don't add the dependency
|
||||||
{
|
*/
|
||||||
component: runtimeComponent
|
} else {
|
||||||
|
result.push(dependency);
|
||||||
}
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var toProcess = GameLib.Utils.Difference(loaded.map(function(component){return component.id}), loading);
|
return result;
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
GameLib.Event.Emit(
|
/**
|
||||||
GameLib.Event.LOAD_PROGRESS,
|
* Also check if we did not already load this component quite recently
|
||||||
{
|
*/
|
||||||
loaded : loaded.length,
|
dependencies = dependencies.reduce(
|
||||||
toProcess : toProcess.length
|
function (result, dependency) {
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (toProcess.length === 0) {
|
var found = loaded.reduce(
|
||||||
|
function (result, component) {
|
||||||
|
if (component.id === dependency) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
if (clientCallback) {
|
if (!found) {
|
||||||
clientCallback({
|
result.push(dependency);
|
||||||
components : loaded
|
}
|
||||||
})
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
GameLib.Event.Emit(
|
/**
|
||||||
GameLib.Event.COMPONENT_DOWNLOAD_COMPLETE,
|
* Ok - now we have a super good idea of which components still need to load -
|
||||||
{
|
* they live in the 'loading' list.
|
||||||
loaded: loaded
|
*
|
||||||
}
|
* At this point - the runtime components are created, but they are not ready
|
||||||
)
|
* to be used. They may have dependencies to other components, which still need
|
||||||
} else {
|
* to load, or may never be loaded.
|
||||||
download.bind(__system)(toProcess.pop(), parentEntity);
|
*
|
||||||
|
* 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 (runtimeComponent && onComponentLoaded) {
|
||||||
|
onComponentLoaded(runtimeComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runtimeComponent) {
|
||||||
|
GameLib.Event.Emit(
|
||||||
|
GameLib.Event.COMPONENT_CREATED,
|
||||||
|
{
|
||||||
|
component: runtimeComponent
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var toProcess = GameLib.Utils.Difference(loaded.map(function(component){return component.id}), loading);
|
||||||
|
|
||||||
|
GameLib.Event.Emit(
|
||||||
|
GameLib.Event.LOAD_PROGRESS,
|
||||||
|
{
|
||||||
|
loaded : loaded.length,
|
||||||
|
toProcess : toProcess.length
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
|
if (toProcess.length === 0) {
|
||||||
|
|
||||||
|
if (clientCallback) {
|
||||||
|
clientCallback({
|
||||||
|
components : loaded
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
GameLib.Event.Emit(
|
||||||
|
GameLib.Event.COMPONENT_DOWNLOAD_COMPLETE,
|
||||||
|
{
|
||||||
|
loaded: loaded
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
download.bind(__system)(toProcess.pop(), parentEntity);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}(this);
|
}(this);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue