|
@@ -31,82 +31,101 @@
|
|
|
|
|
|
this.rtenv = null;
|
|
|
|
|
|
- var gameInitPromise = null;
|
|
|
+ var initPromise = null;
|
|
|
var unloadAfterInit = true;
|
|
|
|
|
|
+ var preloadedFiles = [];
|
|
|
+
|
|
|
+ var resizeCanvasOnStart = true;
|
|
|
var progressFunc = null;
|
|
|
- var pckProgressTracker = {};
|
|
|
+ var preloadProgressTracker = {};
|
|
|
var lastProgress = { loaded: 0, total: 0 };
|
|
|
|
|
|
var canvas = null;
|
|
|
+ var executableName = null;
|
|
|
+ var locale = null;
|
|
|
var stdout = null;
|
|
|
var stderr = null;
|
|
|
|
|
|
- this.initGame = function(mainPack) {
|
|
|
-
|
|
|
- if (!gameInitPromise) {
|
|
|
-
|
|
|
- if (mainPack === undefined) {
|
|
|
- if (basePath !== null) {
|
|
|
- mainPack = basePath + '.pck';
|
|
|
- } else {
|
|
|
- return Promise.reject(new Error("No main pack to load specified"));
|
|
|
- }
|
|
|
- }
|
|
|
- if (basePath === null)
|
|
|
- basePath = getBasePath(mainPack);
|
|
|
+ this.init = function(newBasePath) {
|
|
|
|
|
|
- gameInitPromise = Engine.initEngine().then(
|
|
|
+ if (!initPromise) {
|
|
|
+ initPromise = Engine.load(newBasePath).then(
|
|
|
instantiate.bind(this)
|
|
|
);
|
|
|
- var gameLoadPromise = loadPromise(mainPack, pckProgressTracker).then(function(xhr) { return xhr.response; });
|
|
|
- gameInitPromise = Promise.all([gameLoadPromise, gameInitPromise]).then(function(values) {
|
|
|
- // resolve with pck
|
|
|
- return new Uint8Array(values[0]);
|
|
|
- });
|
|
|
- if (unloadAfterInit)
|
|
|
- gameInitPromise.then(Engine.unloadEngine);
|
|
|
requestAnimationFrame(animateProgress);
|
|
|
+ if (unloadAfterInit)
|
|
|
+ initPromise.then(Engine.unloadEngine);
|
|
|
}
|
|
|
- return gameInitPromise;
|
|
|
+ return initPromise;
|
|
|
};
|
|
|
|
|
|
- function instantiate(initializer) {
|
|
|
+ function instantiate(wasmBuf) {
|
|
|
|
|
|
- var rtenvOpts = {
|
|
|
- noInitialRun: true,
|
|
|
- thisProgram: getBaseName(basePath),
|
|
|
+ var rtenvProps = {
|
|
|
engine: this,
|
|
|
+ ENV: {},
|
|
|
};
|
|
|
if (typeof stdout === 'function')
|
|
|
- rtenvOpts.print = stdout;
|
|
|
+ rtenvProps.print = stdout;
|
|
|
if (typeof stderr === 'function')
|
|
|
- rtenvOpts.printErr = stderr;
|
|
|
- if (typeof WebAssembly === 'object' && initializer instanceof ArrayBuffer) {
|
|
|
- rtenvOpts.instantiateWasm = function(imports, onSuccess) {
|
|
|
- WebAssembly.instantiate(initializer, imports).then(function(result) {
|
|
|
- onSuccess(result.instance);
|
|
|
- });
|
|
|
- return {};
|
|
|
- };
|
|
|
- } else {
|
|
|
- throw new Error("Invalid initializer");
|
|
|
- }
|
|
|
+ rtenvProps.printErr = stderr;
|
|
|
+ rtenvProps.instantiateWasm = function(imports, onSuccess) {
|
|
|
+ WebAssembly.instantiate(wasmBuf, imports).then(function(result) {
|
|
|
+ onSuccess(result.instance);
|
|
|
+ });
|
|
|
+ return {};
|
|
|
+ };
|
|
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
- rtenvOpts.onRuntimeInitialized = resolve;
|
|
|
- rtenvOpts.onAbort = reject;
|
|
|
- rtenvOpts.engine.rtenv = Engine.RuntimeEnvironment(rtenvOpts);
|
|
|
+ rtenvProps.onRuntimeInitialized = resolve;
|
|
|
+ rtenvProps.onAbort = reject;
|
|
|
+ rtenvProps.engine.rtenv = Engine.RuntimeEnvironment(rtenvProps);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- this.start = function(mainPack) {
|
|
|
+ this.preloadFile = function(pathOrBuffer, bufferFilename) {
|
|
|
+
|
|
|
+ if (pathOrBuffer instanceof ArrayBuffer) {
|
|
|
+ pathOrBuffer = new Uint8Array(pathOrBuffer);
|
|
|
+ } else if (ArrayBuffer.isView(pathOrBuffer)) {
|
|
|
+ pathOrBuffer = new Uint8Array(pathOrBuffer.buffer);
|
|
|
+ }
|
|
|
+ if (pathOrBuffer instanceof Uint8Array) {
|
|
|
+ preloadedFiles.push({
|
|
|
+ name: bufferFilename,
|
|
|
+ buffer: pathOrBuffer
|
|
|
+ });
|
|
|
+ return Promise.resolve();
|
|
|
+ } else if (typeof pathOrBuffer === 'string') {
|
|
|
+ return loadPromise(pathOrBuffer, preloadProgressTracker).then(function(xhr) {
|
|
|
+ preloadedFiles.push({
|
|
|
+ name: pathOrBuffer,
|
|
|
+ buffer: xhr.response
|
|
|
+ });
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ throw Promise.reject("Invalid object for preloading");
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ this.start = function() {
|
|
|
+
|
|
|
+ return this.init().then(
|
|
|
+ Function.prototype.apply.bind(synchronousStart, this, arguments)
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
+ this.startGame = function(mainPack) {
|
|
|
|
|
|
- return this.initGame(mainPack).then(synchronousStart.bind(this));
|
|
|
+ executableName = getBaseName(mainPack);
|
|
|
+ return Promise.all([this.init(getBasePath(mainPack)), this.preloadFile(mainPack)]).then(
|
|
|
+ Function.prototype.apply.bind(synchronousStart, this, [])
|
|
|
+ );
|
|
|
};
|
|
|
|
|
|
- function synchronousStart(pckView) {
|
|
|
- // TODO don't expect canvas when runninng as cli tool
|
|
|
+ function synchronousStart() {
|
|
|
+
|
|
|
if (canvas instanceof HTMLCanvasElement) {
|
|
|
this.rtenv.canvas = canvas;
|
|
|
} else {
|
|
@@ -141,15 +160,33 @@
|
|
|
ev.preventDefault();
|
|
|
}, false);
|
|
|
|
|
|
- this.rtenv.FS.createDataFile('/', this.rtenv.thisProgram + '.pck', pckView, true, true, true);
|
|
|
- gameInitPromise = null;
|
|
|
- this.rtenv.callMain();
|
|
|
+ if (locale) {
|
|
|
+ this.rtenv.locale = locale;
|
|
|
+ } else {
|
|
|
+ this.rtenv.locale = navigator.languages ? navigator.languages[0] : navigator.language;
|
|
|
+ }
|
|
|
+ this.rtenv.locale = this.rtenv.locale.split('.')[0];
|
|
|
+ this.rtenv.resizeCanvasOnStart = resizeCanvasOnStart;
|
|
|
+
|
|
|
+ this.rtenv.thisProgram = executableName || getBaseName(basePath);
|
|
|
+
|
|
|
+ preloadedFiles.forEach(function(file) {
|
|
|
+ this.rtenv.FS.createDataFile('/', file.name, new Uint8Array(file.buffer), true, true, true);
|
|
|
+ }, this);
|
|
|
+
|
|
|
+ preloadedFiles = null;
|
|
|
+ initPromise = null;
|
|
|
+ this.rtenv.callMain(arguments);
|
|
|
}
|
|
|
|
|
|
this.setProgressFunc = function(func) {
|
|
|
progressFunc = func;
|
|
|
};
|
|
|
|
|
|
+ this.setResizeCanvasOnStart = function(enabled) {
|
|
|
+ resizeCanvasOnStart = enabled;
|
|
|
+ };
|
|
|
+
|
|
|
function animateProgress() {
|
|
|
|
|
|
var loaded = 0;
|
|
@@ -157,7 +194,7 @@
|
|
|
var totalIsValid = true;
|
|
|
var progressIsFinal = true;
|
|
|
|
|
|
- [loadingFiles, pckProgressTracker].forEach(function(tracker) {
|
|
|
+ [loadingFiles, preloadProgressTracker].forEach(function(tracker) {
|
|
|
Object.keys(tracker).forEach(function(file) {
|
|
|
if (!tracker[file].final)
|
|
|
progressIsFinal = false;
|
|
@@ -184,10 +221,20 @@
|
|
|
canvas = elem;
|
|
|
};
|
|
|
|
|
|
+ this.setExecutableName = function(newName) {
|
|
|
+
|
|
|
+ executableName = newName;
|
|
|
+ };
|
|
|
+
|
|
|
+ this.setLocale = function(newLocale) {
|
|
|
+
|
|
|
+ locale = newLocale;
|
|
|
+ };
|
|
|
+
|
|
|
this.setUnloadAfterInit = function(enabled) {
|
|
|
|
|
|
- if (enabled && !unloadAfterInit && gameInitPromise) {
|
|
|
- gameInitPromise.then(Engine.unloadEngine);
|
|
|
+ if (enabled && !unloadAfterInit && initPromise) {
|
|
|
+ initPromise.then(Engine.unloadEngine);
|
|
|
}
|
|
|
unloadAfterInit = enabled;
|
|
|
};
|
|
@@ -222,7 +269,7 @@
|
|
|
|
|
|
Engine.RuntimeEnvironment = engine.RuntimeEnvironment;
|
|
|
|
|
|
- Engine.initEngine = function(newBasePath) {
|
|
|
+ Engine.load = function(newBasePath) {
|
|
|
|
|
|
if (newBasePath !== undefined) basePath = getBasePath(newBasePath);
|
|
|
if (engineLoadPromise === null) {
|
|
@@ -240,7 +287,7 @@
|
|
|
return engineLoadPromise;
|
|
|
};
|
|
|
|
|
|
- Engine.unloadEngine = function() {
|
|
|
+ Engine.unload = function() {
|
|
|
engineLoadPromise = null;
|
|
|
};
|
|
|
|
|
@@ -259,7 +306,7 @@
|
|
|
if (!file.endsWith('.js')) {
|
|
|
xhr.responseType = 'arraybuffer';
|
|
|
}
|
|
|
- ['loadstart', 'progress', 'load', 'error', 'timeout', 'abort'].forEach(function(ev) {
|
|
|
+ ['loadstart', 'progress', 'load', 'error', 'abort'].forEach(function(ev) {
|
|
|
xhr.addEventListener(ev, onXHREvent.bind(xhr, resolve, reject, file, tracker));
|
|
|
});
|
|
|
xhr.send();
|
|
@@ -274,7 +321,7 @@
|
|
|
this.abort();
|
|
|
return;
|
|
|
} else {
|
|
|
- loadXHR(resolve, reject, file);
|
|
|
+ setTimeout(loadXHR.bind(null, resolve, reject, file, tracker), 1000);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -301,12 +348,11 @@
|
|
|
break;
|
|
|
|
|
|
case 'error':
|
|
|
- case 'timeout':
|
|
|
if (++tracker[file].attempts >= DOWNLOAD_ATTEMPTS_MAX) {
|
|
|
tracker[file].final = true;
|
|
|
reject(new Error("Failed loading file '" + file + "'"));
|
|
|
} else {
|
|
|
- loadXHR(resolve, reject, file);
|
|
|
+ setTimeout(loadXHR.bind(null, resolve, reject, file, tracker), 1000);
|
|
|
}
|
|
|
break;
|
|
|
|