r3-legacy/src/game-lib-system-storage.js

656 lines
18 KiB
JavaScript
Raw Normal View History

2017-06-13 14:09:18 +02:00
/**
* Storage System takes care loading and linking components and dependencies
2017-06-13 14:09:18 +02:00
* @param apiSystem GameLib.API.System
* @param apiUrl
* @param token
* @param apiUploadUrl
* @param onImageLoaded
* @param onImageProgress
* @param onImageError
2017-06-13 14:09:18 +02:00
* @constructor
*/
GameLib.System.Storage = function(
apiSystem,
apiUrl,
token,
apiUploadUrl,
onImageLoaded,
onImageProgress,
onImageError
2017-06-13 14:09:18 +02:00
) {
GameLib.System.call(
this,
apiSystem
);
2017-06-13 14:09:18 +02:00
if (GameLib.Utils.UndefinedOrNull(apiUrl)) {
console.warn('Need an API URL for a storage system');
apiUrl = '';
2017-06-13 14:09:18 +02:00
}
this.apiUrl = apiUrl;
if (GameLib.Utils.UndefinedOrNull(token)) {
token = null;
}
this.token = token;
if (GameLib.Utils.UndefinedOrNull(apiUploadUrl)) {
console.warn('Need an API Upload URL for a storage system');
apiUploadUrl = '';
}
this.apiUploadUrl = apiUploadUrl;
if (GameLib.Utils.UndefinedOrNull(onImageLoaded)) {
onImageLoaded = null;
}
this.onImageLoaded = onImageLoaded;
if (GameLib.Utils.UndefinedOrNull(onImageProgress)) {
onImageProgress = null;
}
this.onImageProgress = onImageProgress;
if (GameLib.Utils.UndefinedOrNull(onImageError)) {
onImageError = null;
}
this.onImageError = onImageError;
2017-06-19 15:54:02 +02:00
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;
2017-06-13 14:09:18 +02:00
};
GameLib.System.Storage.prototype = Object.create(GameLib.System.prototype);
GameLib.System.Storage.prototype.constructor = GameLib.System.Storage;
2017-06-19 15:54:02 +02:00
GameLib.System.Storage.prototype.start = function() {
this.loginSubscription = this.subscribe(
GameLib.Event.LOGGED_IN,
function(data) {
this.token = data.token;
}
);
this.saveSubscription = this.subscribe(
2017-06-19 21:35:51 +02:00
GameLib.Event.SAVE_COMPONENT,
2017-06-19 15:54:02 +02:00
this.save
);
this.loadSubscription = this.subscribe(
2017-06-19 21:35:51 +02:00
GameLib.Event.LOAD_COMPONENT,
2017-06-19 15:54:02 +02:00
this.load
);
this.loadImageSubscription = this.subscribe(
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
);
2017-06-19 15:54:02 +02:00
};
2017-06-13 14:09:18 +02:00
/**
* 'Saves' data to baseURL
*/
GameLib.System.Storage.prototype.save = function(data) {
if (typeof XMLHttpRequest === 'undefined') {
console.log('Implement server side save here');
return;
}
var xhr = new XMLHttpRequest();
xhr.open(
'POST',
this.apiUrl + '/component/create'
);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
try {
var response = JSON.parse(this.responseText)
} catch (error) {
GameLib.Event.Emit(
2017-06-19 21:35:51 +02:00
GameLib.Event.SAVE_COMPONENT_ERROR,
2017-06-13 14:09:18 +02:00
{
message: this.responseText
}
)
}
if (response.result === 'success') {
GameLib.Event.Emit(
2017-06-19 21:35:51 +02:00
GameLib.Event.COMPONENT_SAVED,
2017-06-13 14:09:18 +02:00
{
message: response.message || 'Successfully saved the component'
}
)
} else {
GameLib.Event.Emit(
2017-06-19 21:35:51 +02:00
GameLib.Event.SAVE_COMPONENT_ERROR,
2017-06-13 14:09:18 +02:00
{
message: response.message || 'The server responded but failed to save the component'
}
)
}
}
};
xhr.send(JSON.stringify({
component : data,
session : this.token
}));
};
/**
2017-06-19 21:35:51 +02:00
* 'Loads' data from a url
2017-06-13 14:09:18 +02:00
*/
GameLib.System.Storage.prototype.load = function(data) {
2017-06-13 16:35:19 +02:00
2017-06-13 14:09:18 +02:00
if (typeof XMLHttpRequest === 'undefined') {
console.log('Implement server side load here');
return;
}
var xhr = new XMLHttpRequest();
xhr.open(
'GET',
2017-06-19 21:35:51 +02:00
data.url
2017-06-13 14:09:18 +02:00
);
xhr.onreadystatechange = function (xhr) {
return function () {
if (xhr.readyState === 4) {
2017-06-19 21:35:51 +02:00
try {
var object = JSON.parse(xhr.responseText);
} catch (error) {
this.publish(
GameLib.Event.LOAD_COMPONENT_ERROR,
{
error : error
}
);
return;
}
if (object.result !== 'success') {
this.publish(
GameLib.Event.LOAD_COMPONENT_ERROR,
{
error : object
}
);
return;
}
2017-06-13 14:09:18 +02:00
this.publish(
2017-06-19 21:35:51 +02:00
GameLib.Event.COMPONENT_LOADED,
2017-06-13 14:09:18 +02:00
{
2017-06-21 12:22:39 +02:00
response : object,
includeDependencies : data.includeDependencies
2017-06-13 14:09:18 +02:00
}
)
}
}
}(xhr).bind(this);
xhr.send();
2017-06-19 15:54:02 +02:00
};
GameLib.System.Storage.prototype.loadImage = function(data) {
console.log('loading image : ' + data.image.name);
var onLoaded = this.onImageLoaded;
var onProgress = this.onImageProgress;;
var onError = this.onImageError;
var image = data.image;
var url = this.apiUploadUrl + image.path + '?ts=' + Date.now();
var preflight = new XMLHttpRequest();
preflight.withCredentials = true;
preflight.open(
'OPTIONS',
url
);
preflight.setRequestHeader('Content-Type', 'application/json');
preflight.onload = function() {
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open('GET', url);
xhr.setRequestHeader('Content-Type', image.contentType);
xhr.responseType = 'blob';
xhr.onload = function() {
try {
if (this.response.type !== 'application/json') {
var url = window.URL.createObjectURL(this.response);
} else {
if (onError) {
onError(image, {message:'Image not found'});
return;
}
}
} catch (error) {
if (onError) {
onError(image, {message:'Image not found'});
return;
}
}
var img = document.createElement('img');
img.onload = function() {
window.URL.revokeObjectURL(url);
image.instance = img;
image.publish(
GameLib.Event.IMAGE_INSTANCE_CREATED,
{
image: image
}
);
if (onLoaded) {
onLoaded(image);
}
};
img.src = url;
};
xhr.onprogress = function(progressEvent) {
var progress = 0;
if (progressEvent.total !== 0) {
progress = Number(progressEvent.loaded / progressEvent.total);
progress *= 100;
}
if (onProgress) {
onProgress(image, progress);
}
image.size = progressEvent.total;
};
xhr.onerror = function(error) {
console.warn('image load failed for image ' + image.name);
if (onError) {
onError(image, error)
}
};
xhr.send();
};
preflight.onerror = function(error) {
console.warn('image pre-flight request failed for image ' + image.name);
if (onError) {
onError(image, error);
}
};
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;
}
});
};
2017-06-19 15:54:02 +02:00
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();
2017-06-19 15:54:02 +02:00
};