attempt 1
parent
dcfeca57d7
commit
7990601fe7
|
@ -70,6 +70,11 @@ GameLib.System.Storage = function(
|
||||||
}
|
}
|
||||||
this.onComponentError = onComponentError;
|
this.onComponentError = onComponentError;
|
||||||
|
|
||||||
|
this.loaded = [];
|
||||||
|
this.loading = [];
|
||||||
|
this.failed = [];
|
||||||
|
this.otherDependencies = [];
|
||||||
|
|
||||||
this.loginSubscription = null;
|
this.loginSubscription = null;
|
||||||
this.saveSubscription = null;
|
this.saveSubscription = null;
|
||||||
this.loadSubscription = null;
|
this.loadSubscription = null;
|
||||||
|
@ -318,58 +323,14 @@ GameLib.System.Storage.prototype.save = function(data) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, includeDependencies, clientCallback, clientErrorCallback) {
|
GameLib.System.Storage.prototype.createRuntimeObject = function(responseText, clientErrorCallback) {
|
||||||
|
|
||||||
var loaded = [];
|
|
||||||
|
|
||||||
var loading = [];
|
|
||||||
|
|
||||||
toProcess.map(function(id) {
|
|
||||||
if (loading.indexOf(id) === -1) {
|
|
||||||
loading.push(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We just do an initial check if these components to process are already in the register -
|
|
||||||
* if so we remove them since we probably want to overwrite them with stale DB versions.
|
|
||||||
*
|
|
||||||
* We don't override runtime versions of the dependencies of the loading components - since they could be later.
|
|
||||||
* But we do override runtime versions of the loading component since the user actually selected them and clicked 'load'
|
|
||||||
*/
|
|
||||||
loading.map(
|
|
||||||
function(id) {
|
|
||||||
|
|
||||||
var component = GameLib.EntityManager.Instance.findComponentById(id);
|
|
||||||
|
|
||||||
if (component) {
|
|
||||||
component.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return function download(id, parentEntity) {
|
|
||||||
|
|
||||||
var onComponentLoaded = this.onComponentLoaded;
|
|
||||||
|
|
||||||
var onComponentProgress = this.onComponentProgress;
|
|
||||||
|
|
||||||
var onComponentError = this.onComponentError;
|
|
||||||
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
|
|
||||||
xhr.onload = function(__system) {
|
|
||||||
|
|
||||||
return function () {
|
|
||||||
|
|
||||||
var error = false;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var object = JSON.parse(this.responseText);
|
var object = JSON.parse(responseText);
|
||||||
} catch (errorObject) {
|
} catch (errorObject) {
|
||||||
|
|
||||||
if (onComponentError) {
|
if (this.onComponentError) {
|
||||||
onComponentError(errorObject);
|
this.onComponentError(errorObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientErrorCallback) {
|
if (clientErrorCallback) {
|
||||||
|
@ -380,18 +341,16 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
|
|
||||||
GameLib.Event.Emit(
|
GameLib.Event.Emit(
|
||||||
GameLib.Event.LOAD_COMPONENT_ERROR,
|
GameLib.Event.LOAD_COMPONENT_ERROR,
|
||||||
{
|
{error: errorObject}
|
||||||
error: errorObject
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
error = true;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error && object.result !== 'success') {
|
if (object.result !== 'success') {
|
||||||
|
|
||||||
if (onComponentError) {
|
if (this.onComponentError) {
|
||||||
onComponentError(id, object);
|
this.onComponentError(id, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientErrorCallback) {
|
if (clientErrorCallback) {
|
||||||
|
@ -405,13 +364,11 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
{error : object}
|
{error : object}
|
||||||
);
|
);
|
||||||
|
|
||||||
error = true;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var runtimeComponent = null;
|
var runtimeComponent = null;
|
||||||
|
|
||||||
if (!error) {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Now we need to create the runtime component - this happens systematically.
|
* 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
|
* First, we create an API object from the Object, then a Runtime object from the API object
|
||||||
|
@ -426,9 +383,9 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
var fn = componentClass['FromObject'];
|
var fn = componentClass['FromObject'];
|
||||||
|
|
||||||
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;
|
|
||||||
parentEntity = runtimeComponent;
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -437,27 +394,27 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
||||||
if (__system.coder) {
|
if (this.coder) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
runtimeComponent = fn(__system.coder, component);
|
runtimeComponent = fn(this.coder, component);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!runtimeComponent && __system.graphics) {
|
if (!runtimeComponent && this.graphics) {
|
||||||
try {
|
try {
|
||||||
runtimeComponent = fn(__system.graphics, component);
|
runtimeComponent = fn(this.graphics, component);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!runtimeComponent && __system.physics) {
|
if (!runtimeComponent && this.physics) {
|
||||||
try {
|
try {
|
||||||
runtimeComponent = fn(__system.physics, component);
|
runtimeComponent = fn(this.physics, component);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
/**
|
/**
|
||||||
* ok - we don't cannot create this component
|
* ok - we don't cannot create this component
|
||||||
|
@ -474,20 +431,56 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
message: 'Could not create a runtime component: ' + component.name
|
message: '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) {
|
return runtimeComponent;
|
||||||
loaded.push(runtimeComponent);
|
};
|
||||||
|
|
||||||
|
GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, includeDependencies, clientCallback, clientErrorCallback) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We just do an initial check if these components to process are already in the register -
|
||||||
|
* if so we remove them since we probably want to overwrite them with stale DB versions.
|
||||||
|
*
|
||||||
|
* We don't override runtime versions of the dependencies of the loading components - since they could be later.
|
||||||
|
* But we do override runtime versions of the loading component since the user actually selected them and clicked 'load'
|
||||||
|
*/
|
||||||
|
toProcess.map(
|
||||||
|
function(id) {
|
||||||
|
|
||||||
|
GameLib.Utils.PushUnique(this.loading, id);
|
||||||
|
|
||||||
|
var component = GameLib.EntityManager.Instance.findComponentById(id);
|
||||||
|
|
||||||
|
if (component) {
|
||||||
|
component.remove();
|
||||||
|
}
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.loading = this.loading.reduce(
|
||||||
|
|
||||||
|
function(result, id) {
|
||||||
|
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
|
xhr.onload = function(__system) {
|
||||||
|
|
||||||
|
return function () {
|
||||||
|
|
||||||
|
var runtimeComponent = __system.createRuntimeObject.bind(__system)(this.responseText);
|
||||||
|
|
||||||
|
if (!runtimeComponent) {
|
||||||
|
__system.failed.push(id);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeDependencies && runtimeComponent) {
|
__system.loaded.push(runtimeComponent.id);
|
||||||
|
|
||||||
|
if (includeDependencies) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
@ -496,6 +489,38 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
*/
|
*/
|
||||||
var dependencies = runtimeComponent.getDependencies();
|
var dependencies = runtimeComponent.getDependencies();
|
||||||
|
|
||||||
|
__system.otherDependencies.map(
|
||||||
|
function(id) {
|
||||||
|
|
||||||
|
var index = dependencies.indexOf(id);
|
||||||
|
|
||||||
|
if (index === -1) {
|
||||||
|
dependencies.splice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
dependencies.map(
|
||||||
|
function(id) {
|
||||||
|
GameLib.Utils.PushUnique(this.otherDependencies, id);
|
||||||
|
}.bind(__system)
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't try to download failed components again
|
||||||
|
*/
|
||||||
|
dependencies = dependencies.reduce(
|
||||||
|
function(result, id) {
|
||||||
|
if (__system.failed.indexOf(id) === -1) {
|
||||||
|
result.push(id);
|
||||||
|
} else {
|
||||||
|
console.log('ignoring failed component : ' + id);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}.bind(__system),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Now - we should systematically check if we have the dependency already
|
* 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)
|
* loaded (in our runtime environment) - if we have - we just ignore loading this dependency (for now)
|
||||||
|
@ -503,8 +528,8 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
* We don't override runtime versions of the same component in the database because the user
|
* 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.
|
* could be working with it and it should be the latest version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dependencies = dependencies.reduce(
|
dependencies = dependencies.reduce(
|
||||||
|
|
||||||
function (result, dependency) {
|
function (result, dependency) {
|
||||||
|
|
||||||
if (GameLib.EntityManager.Instance.findComponentById(dependency)) {
|
if (GameLib.EntityManager.Instance.findComponentById(dependency)) {
|
||||||
|
@ -521,27 +546,17 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Also check if we did not already load this component quite recently
|
* Also check if this dependency is not already in our loaded
|
||||||
*/
|
*/
|
||||||
dependencies = dependencies.reduce(
|
dependencies = dependencies.reduce(
|
||||||
function (result, dependency) {
|
function (result, dependency) {
|
||||||
|
|
||||||
var found = loaded.reduce(
|
if (this.loaded.indexOf(dependency) === -1) {
|
||||||
function (result, component) {
|
|
||||||
if (component.id === dependency) {
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
result.push(dependency);
|
result.push(dependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
}.bind(__system),
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -550,80 +565,40 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
*/
|
*/
|
||||||
dependencies.map(
|
dependencies.map(
|
||||||
function (dependency) {
|
function (dependency) {
|
||||||
if (loading.indexOf(dependency) === -1) {
|
GameLib.Utils.PushUnique(this.loading, dependency);
|
||||||
loading.push(dependency);
|
}.bind(__system)
|
||||||
}
|
);
|
||||||
}
|
|
||||||
)
|
if (__system.onComponentLoaded) {
|
||||||
|
__system.onComponentLoaded(runtimeComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.Emit(
|
||||||
GameLib.Event.COMPONENT_CREATED,
|
GameLib.Event.COMPONENT_CREATED,
|
||||||
{
|
{
|
||||||
component: runtimeComponent
|
component: runtimeComponent
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
var toProcess = GameLib.Utils.Difference(loaded.map(function(component){return component.id}), loading);
|
|
||||||
|
|
||||||
if (!runtimeComponent) {
|
|
||||||
/**
|
|
||||||
* Make sure we don't try to download this component again, it failed
|
|
||||||
*/
|
|
||||||
var index = toProcess.indexOf(component.id);
|
|
||||||
|
|
||||||
if (index !== -1) {
|
|
||||||
toProcess.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GameLib.Event.Emit(
|
GameLib.Event.Emit(
|
||||||
GameLib.Event.LOAD_PROGRESS,
|
GameLib.Event.LOAD_PROGRESS,
|
||||||
{
|
{
|
||||||
loaded : loaded.length,
|
loaded : __system.loaded.length,
|
||||||
toProcess : toProcess.length
|
toProcess : dependencies.length
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (toProcess.length === 0) {
|
__system.loadComponent(apiUrl, dependencies,includeDependencies, clientCallback, clientErrorCallback);
|
||||||
|
|
||||||
if (clientCallback) {
|
// GameLib.Event.Emit(
|
||||||
clientCallback({
|
// GameLib.Event.COMPONENT_DOWNLOAD_COMPLETE,
|
||||||
components : loaded
|
// {
|
||||||
})
|
// loaded: __system.loaded
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GameLib.Event.Emit(
|
|
||||||
GameLib.Event.COMPONENT_DOWNLOAD_COMPLETE,
|
|
||||||
{
|
|
||||||
loaded: loaded
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
download.bind(__system)(toProcess.pop(), parentEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}(this);
|
}(this);
|
||||||
|
|
||||||
xhr.onprogress = function(__id) {
|
xhr.onprogress = function(__id) {
|
||||||
|
@ -635,18 +610,18 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
progress = Math.round(Number(progressEvent.loaded / progressEvent.total) * 100);
|
progress = Math.round(Number(progressEvent.loaded / progressEvent.total) * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onComponentProgress) {
|
if (this.onComponentProgress) {
|
||||||
onComponentProgress(__id, progress)
|
this.onComponentProgress(__id, progress)
|
||||||
}
|
}
|
||||||
};
|
}.bind(this);
|
||||||
}(id);
|
}(id);
|
||||||
|
|
||||||
xhr.onerror = function(__id) {
|
xhr.onerror = function(__id) {
|
||||||
return function (error) {
|
return function (error) {
|
||||||
console.warn('component load failed for component ID ' + __id);
|
console.warn('component load failed for component ID ' + __id);
|
||||||
|
|
||||||
if (onComponentError) {
|
if (this.onComponentError) {
|
||||||
onComponentError(__id, error)
|
this.onComponentError(__id, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientErrorCallback) {
|
if (clientErrorCallback) {
|
||||||
|
@ -654,8 +629,7 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
message : 'xhr request failure'
|
message : 'xhr request failure'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}.bind(this);
|
||||||
};
|
|
||||||
}(id);
|
}(id);
|
||||||
|
|
||||||
xhr.open(
|
xhr.open(
|
||||||
|
@ -664,7 +638,12 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc
|
||||||
);
|
);
|
||||||
|
|
||||||
xhr.send();
|
xhr.send();
|
||||||
}.bind(this);
|
|
||||||
|
return result;
|
||||||
|
}.bind(this),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -689,7 +668,7 @@ GameLib.System.Storage.prototype.load = function(data, clientCallback, clientErr
|
||||||
data.includeDependencies,
|
data.includeDependencies,
|
||||||
clientCallback,
|
clientCallback,
|
||||||
clientErrorCallback
|
clientErrorCallback
|
||||||
)(data.ids[0], null);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log('No components selected');
|
console.log('No components selected');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue