don't store clones, deep clone objects, continue loading when components fail to load, fix entity and renderer toApiObject

beta.r3js.org
-=yb4f310 2017-11-09 00:47:23 +01:00
parent b6bb9cb9a7
commit b59c118ee7
6 changed files with 235 additions and 195 deletions

View File

@ -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,

View File

@ -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){

View File

@ -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(

View File

@ -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(

View File

@ -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);
}
} }
}; };

View File

@ -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);