Change HTML5 start-up API

Rename engine.start() to startGame(), new start() takes string arguments
handed directly to main(). Rename Engine.loadEngine() to load().

Add setLocale(), setResizeCanvasOnStart(), setExecutableName() and
preloadFile().
This commit is contained in:
Leon Krause 2017-11-19 15:30:09 +01:00
parent 9107357c8d
commit 35adf718cf
5 changed files with 137 additions and 94 deletions

View file

@ -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) {
this.init = function(newBasePath) {
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);
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) {
return this.initGame(mainPack).then(synchronousStart.bind(this));
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");
}
};
function synchronousStart(pckView) {
// TODO don't expect canvas when runninng as cli tool
this.start = function() {
return this.init().then(
Function.prototype.apply.bind(synchronousStart, this, arguments)
);
};
this.startGame = function(mainPack) {
executableName = getBaseName(mainPack);
return Promise.all([this.init(getBasePath(mainPack)), this.preloadFile(mainPack)]).then(
Function.prototype.apply.bind(synchronousStart, this, [])
);
};
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;