From b59c118ee7e0c2129ed002f1b18c6206107d7a17 Mon Sep 17 00:00:00 2001 From: -=yb4f310 Date: Thu, 9 Nov 2017 00:47:23 +0100 Subject: [PATCH] don't store clones, deep clone objects, continue loading when components fail to load, fix entity and renderer toApiObject --- src/game-lib-a-component-a.js | 103 +++++++------ src/game-lib-d3-renderer.js | 2 +- src/game-lib-d3-scene.js | 35 ++++- src/game-lib-entity.js | 14 +- src/game-lib-system-linking.js | 4 +- src/game-lib-system-storage.js | 272 +++++++++++++++++---------------- 6 files changed, 235 insertions(+), 195 deletions(-) diff --git a/src/game-lib-a-component-a.js b/src/game-lib-a-component-a.js index f0914ca..32c481b 100644 --- a/src/game-lib-a-component-a.js +++ b/src/game-lib-a-component-a.js @@ -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.building = false; @@ -487,6 +497,8 @@ GameLib.Component.prototype.generateNewIds = function() { this.buildIdToObject(); + var codeComponents = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.CustomCode); + for (var property in this.idToObject) { if (this.idToObject.hasOwnProperty(property)) { @@ -495,9 +507,14 @@ GameLib.Component.prototype.generateNewIds = function() { this.idToObject[property].id = 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() { @@ -601,42 +618,42 @@ GameLib.Component.prototype.cloneInstance = function() { return clone; }; -GameLib.Component.prototype.getStorageDependencies = function() { - - var dependencies = {}; - - for (var property in this.linkedObjects) { - if (this.linkedObjects.hasOwnProperty(property)){ - if (this.hasOwnProperty(property)) { - - if ( - this[property] instanceof Array && - this.linkedObjects[property] instanceof Array - ) { - - if (this.linkedObjects[property].length !== 1) { - console.log('Invalid formed argument type'); - } - - dependencies[property] = this[property].map( - function(__constructor) { - return function(arrayProperty){ - if (arrayProperty instanceof __constructor) { - return GameLib.Utils.IdOrNull(arrayProperty); - } - }.bind(this) - }(this.linkedObjects[property][0]) - ); - - } else if (this[property] instanceof this.linkedObjects[property]) { - dependencies[property] = GameLib.Utils.IdOrNull(this[property]); - } - } - } - } - - return dependencies; -}; +// GameLib.Component.prototype.getStorageDependencies = function() { +// +// var dependencies = {}; +// +// for (var property in this.linkedObjects) { +// if (this.linkedObjects.hasOwnProperty(property)){ +// if (this.hasOwnProperty(property)) { +// +// if ( +// this[property] instanceof Array && +// this.linkedObjects[property] instanceof Array +// ) { +// +// if (this.linkedObjects[property].length !== 1) { +// console.log('Invalid formed argument type'); +// } +// +// dependencies[property] = this[property].map( +// function(__constructor) { +// return function(arrayProperty){ +// if (arrayProperty instanceof __constructor) { +// return GameLib.Utils.IdOrNull(arrayProperty); +// } +// }.bind(this) +// }(this.linkedObjects[property][0]) +// ); +// +// } else if (this[property] instanceof this.linkedObjects[property]) { +// dependencies[property] = GameLib.Utils.IdOrNull(this[property]); +// } +// } +// } +// } +// +// return dependencies; +// }; GameLib.Component.prototype.saveToRemoteAPI = function() { this.save(true); @@ -656,13 +673,13 @@ GameLib.Component.prototype.save = function(remote) { apiObject.componentType = this.idToObject[property].componentType; - var storageDependencies = this.idToObject[property].getStorageDependencies(); - - for (var storageProperty in storageDependencies) { - if (storageDependencies.hasOwnProperty(storageProperty)) { - apiObject[storageProperty] = storageDependencies[storageProperty]; - } - } + // var storageDependencies = this.idToObject[property].getStorageDependencies(); + // + // for (var storageProperty in storageDependencies) { + // if (storageDependencies.hasOwnProperty(storageProperty)) { + // apiObject[storageProperty] = storageDependencies[storageProperty]; + // } + // } this.publish( GameLib.Event.SAVE_COMPONENT, diff --git a/src/game-lib-d3-renderer.js b/src/game-lib-d3-renderer.js index 4ce2113..4b09646 100644 --- a/src/game-lib-d3-renderer.js +++ b/src/game-lib-d3-renderer.js @@ -274,7 +274,7 @@ GameLib.D3.Renderer.prototype.toApiObject = function() { this.width, this.height, this.preserveDrawingBuffer, - this.domElement.toApiObject(), + GameLib.Utils.IdOrNull(this.domElement), this.clearColor.toApiObject(), GameLib.Utils.IdOrNull(this.camera), this.scenes.map(function(scene){ diff --git a/src/game-lib-d3-scene.js b/src/game-lib-d3-scene.js index cf5ce72..ba6714b 100644 --- a/src/game-lib-d3-scene.js +++ b/src/game-lib-d3-scene.js @@ -290,16 +290,35 @@ GameLib.D3.Scene.prototype.updateInstance = function(property) { */ GameLib.D3.Scene.prototype.toApiObject = function() { - var apiMeshes = this.meshes.map( - function(mesh) { - return GameLib.Utils.IdOrNull(mesh); - } + var apiMeshes = this.meshes.reduce( + function(result, 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( - function(light) { - return GameLib.Utils.IdOrNull(light); - } + var apiLights = this.lights.reduce( + function(result, 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( diff --git a/src/game-lib-entity.js b/src/game-lib-entity.js index 06e813c..b25a41c 100644 --- a/src/game-lib-entity.js +++ b/src/game-lib-entity.js @@ -188,16 +188,10 @@ GameLib.Entity.prototype.updateInstance = function() { */ GameLib.Entity.prototype.toApiObject = function() { - var apiComponents = this.components.reduce( - function(result, component) { - if (typeof component.toApiObject === 'function') { - result.push(component.toApiObject()); - } else { - console.log('ignored runtime component : ' + component.name); - } - return result; - }, - [] + var apiComponents = this.components.map( + function(component) { + return GameLib.Utils.IdOrNull(component); + } ); return new GameLib.API.Entity( diff --git a/src/game-lib-system-linking.js b/src/game-lib-system-linking.js index cf398d4..2a0d235 100644 --- a/src/game-lib-system-linking.js +++ b/src/game-lib-system-linking.js @@ -479,7 +479,9 @@ GameLib.System.Linking.prototype.componentCloned = function(data) { throw new Error('no scene parent'); } - data.parent.parentScene.addClone(data.component); + if (data.parent.parentScene) { + data.parent.parentScene.addClone(data.component); + } } }; diff --git a/src/game-lib-system-storage.js b/src/game-lib-system-storage.js index 20c9225..ea8b9ae 100644 --- a/src/game-lib-system-storage.js +++ b/src/game-lib-system-storage.js @@ -362,31 +362,33 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc return function () { + var error = false; + try { var object = JSON.parse(this.responseText); - } catch (error) { + } catch (errorObject) { if (onComponentError) { - onComponentError(error); + onComponentError(errorObject); } if (clientErrorCallback) { clientErrorCallback({ - message : error.message || 'JSON parse error' + message : errorObject.message || 'JSON parse error' }) } GameLib.Event.Emit( GameLib.Event.LOAD_COMPONENT_ERROR, { - error: error + error: errorObject } ); - return; + error = true; } - if (object.result !== 'success') { + if (!error && object.result !== 'success') { if (onComponentError) { onComponentError(id, object); @@ -403,15 +405,19 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc {error : object} ); - return; + error = true; } - /** - * 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 - */ - object.component.map(function (component) { + var runtimeComponent = null; + + if (!error) { + + /** + * 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); @@ -419,8 +425,6 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc var fn = componentClass['FromObject']; - var runtimeComponent = null; - if (component.componentType === GameLib.Component.COMPONENT_ENTITY) { runtimeComponent = fn(component, GameLib.EntityManager.Instance); runtimeComponent.parentEntity = parentEntity; @@ -464,146 +468,150 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc } if (!runtimeComponent) { - if (clientErrorCallback) { - clientErrorCallback({result : 'failure', message : 'Could not create a runtime component: ' + component.name}); + if (clientErrorCallback) { + 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) { runtimeComponent.parentEntity = parentEntity; } } + } - if (runtimeComponent) { - loaded.push(runtimeComponent); - } + if (runtimeComponent) { + loaded.push(runtimeComponent); + } - if (includeDependencies && runtimeComponent) { - /** - * Before we announce the creation of this component, we should get - * a list of all dependencies of this component, because once we announce - * the creation of this component - the linking system will attempt to resolve - * all dependencies - */ - 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); - } - } - ) - } + if (includeDependencies && runtimeComponent) { + /** + * Before we announce the creation of this component, we should get + * a list of all dependencies of this component, because once we announce + * the creation of this component - the linking system will attempt to resolve + * all dependencies + */ + var dependencies = runtimeComponent.getDependencies(); /** - * Ok - now we have a super good idea of which components still need to load - - * they live in the 'loading' list. + * 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) * - * 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 - * 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 + * 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. */ - if (runtimeComponent && onComponentLoaded) { - onComponentLoaded(runtimeComponent); - } + dependencies = dependencies.reduce( + function (result, dependency) { - if (runtimeComponent) { - GameLib.Event.Emit( - GameLib.Event.COMPONENT_CREATED, - { - component: runtimeComponent + if (GameLib.EntityManager.Instance.findComponentById(dependency)) { + /** + * Don't add the dependency + */ + } 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, - { - loaded : loaded.length, - toProcess : toProcess.length - } - ); + /** + * Also check if we did not already load this component quite recently + */ + dependencies = dependencies.reduce( + 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) { - clientCallback({ - components : loaded - }) + 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); + } } + ) + } - GameLib.Event.Emit( - GameLib.Event.COMPONENT_DOWNLOAD_COMPLETE, - { - loaded: loaded - } - ) - } else { - download.bind(__system)(toProcess.pop(), parentEntity); + /** + * 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 components, 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 (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);