mirror of
https://gitee.com/freeyz/godot-mota.git
synced 2024-12-23 07:19:19 +08:00
420 lines
300 KiB
JavaScript
420 lines
300 KiB
JavaScript
|
var Engine = {
|
||
|
RuntimeEnvironment: function(Module, exposedLibs) {
|
||
|
// The above is concatenated with generated code, and acts as the start of
|
||
|
// a wrapper for said code. See engine.js for the other part of the
|
||
|
// wrapper.
|
||
|
|
||
|
var Module=typeof Module!=="undefined"?Module:{};var IDHandler=function(){var ids={};var size=0;this.has=function(id){return ids.hasOwnProperty(id)};this.add=function(obj){size+=1;var id=crypto.getRandomValues(new Int32Array(32))[0];ids[id]=obj;return id};this.get=function(id){return ids[id]};this.remove=function(id){size-=1;delete ids[id]};this.size=function(){return size};this.ids=ids};Module.IDHandler=new IDHandler;var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var STACK_ALIGN=16;function alignMemory(size,factor){if(!factor)factor=STACK_ALIGN;return Math.ceil(size/factor)*factor}function warnOnce(text){if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;err(text)}}var tempRet0=0;var setTempRet0=function(value){tempRet0=value};var getTempRet0=function(){return tempRet0};var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(typeof WebAssembly!=="object"){abort("no native wasm support detected")}function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}function getValue(ptr,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":return HEAP8[ptr>>0];case"i8":return HEAP8[ptr>>0];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP32[ptr>>2];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];default:abort("invalid type for getValue: "+type)}return null}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":26015,"maximum":26015+0,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;functio
|
||
|
|
||
|
// The following is concatenated with generated code, and acts as the end
|
||
|
// of a wrapper for said code. See pre.js for the other part of the
|
||
|
// wrapper.
|
||
|
exposedLibs['PATH'] = PATH;
|
||
|
exposedLibs['FS'] = FS;
|
||
|
return Module;
|
||
|
},
|
||
|
};
|
||
|
|
||
|
(function() {
|
||
|
var engine = Engine;
|
||
|
|
||
|
var DOWNLOAD_ATTEMPTS_MAX = 4;
|
||
|
|
||
|
var basePath = null;
|
||
|
var wasmFilenameExtensionOverride = null;
|
||
|
var engineLoadPromise = null;
|
||
|
|
||
|
var loadingFiles = {};
|
||
|
|
||
|
function getPathLeaf(path) {
|
||
|
|
||
|
while (path.endsWith('/'))
|
||
|
path = path.slice(0, -1);
|
||
|
return path.slice(path.lastIndexOf('/') + 1);
|
||
|
}
|
||
|
|
||
|
function getBasePath(path) {
|
||
|
|
||
|
if (path.endsWith('/'))
|
||
|
path = path.slice(0, -1);
|
||
|
if (path.lastIndexOf('.') > path.lastIndexOf('/'))
|
||
|
path = path.slice(0, path.lastIndexOf('.'));
|
||
|
return path;
|
||
|
}
|
||
|
|
||
|
function getBaseName(path) {
|
||
|
|
||
|
return getPathLeaf(getBasePath(path));
|
||
|
}
|
||
|
|
||
|
Engine = function Engine() {
|
||
|
|
||
|
this.rtenv = null;
|
||
|
|
||
|
var LIBS = {};
|
||
|
|
||
|
var initPromise = null;
|
||
|
var unloadAfterInit = true;
|
||
|
|
||
|
var preloadedFiles = [];
|
||
|
|
||
|
var resizeCanvasOnStart = true;
|
||
|
var progressFunc = null;
|
||
|
var preloadProgressTracker = {};
|
||
|
var lastProgress = { loaded: 0, total: 0 };
|
||
|
|
||
|
var canvas = null;
|
||
|
var executableName = null;
|
||
|
var locale = null;
|
||
|
var stdout = null;
|
||
|
var stderr = null;
|
||
|
|
||
|
this.init = function(newBasePath) {
|
||
|
|
||
|
if (!initPromise) {
|
||
|
initPromise = Engine.load(newBasePath).then(
|
||
|
instantiate.bind(this)
|
||
|
);
|
||
|
requestAnimationFrame(animateProgress);
|
||
|
if (unloadAfterInit)
|
||
|
initPromise.then(Engine.unloadEngine);
|
||
|
}
|
||
|
return initPromise;
|
||
|
};
|
||
|
|
||
|
function instantiate(wasmBuf) {
|
||
|
|
||
|
var rtenvProps = {
|
||
|
engine: this,
|
||
|
ENV: {},
|
||
|
};
|
||
|
if (typeof stdout === 'function')
|
||
|
rtenvProps.print = stdout;
|
||
|
if (typeof stderr === 'function')
|
||
|
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) {
|
||
|
rtenvProps.onRuntimeInitialized = resolve;
|
||
|
rtenvProps.onAbort = reject;
|
||
|
rtenvProps.thisProgram = executableName;
|
||
|
rtenvProps.engine.rtenv = Engine.RuntimeEnvironment(rtenvProps, LIBS);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
this.preloadFile = function(pathOrBuffer, destPath) {
|
||
|
|
||
|
if (pathOrBuffer instanceof ArrayBuffer) {
|
||
|
pathOrBuffer = new Uint8Array(pathOrBuffer);
|
||
|
} else if (ArrayBuffer.isView(pathOrBuffer)) {
|
||
|
pathOrBuffer = new Uint8Array(pathOrBuffer.buffer);
|
||
|
}
|
||
|
if (pathOrBuffer instanceof Uint8Array) {
|
||
|
preloadedFiles.push({
|
||
|
path: destPath,
|
||
|
buffer: pathOrBuffer
|
||
|
});
|
||
|
return Promise.resolve();
|
||
|
} else if (typeof pathOrBuffer === 'string') {
|
||
|
return loadPromise(pathOrBuffer, preloadProgressTracker).then(function(xhr) {
|
||
|
preloadedFiles.push({
|
||
|
path: destPath || 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(execName, mainPack) {
|
||
|
|
||
|
executableName = execName;
|
||
|
var mainArgs = [ '--main-pack', getPathLeaf(mainPack) ];
|
||
|
|
||
|
return Promise.all([
|
||
|
this.init(getBasePath(execName)),
|
||
|
this.preloadFile(mainPack, getPathLeaf(mainPack))
|
||
|
]).then(
|
||
|
Function.prototype.apply.bind(synchronousStart, this, mainArgs)
|
||
|
);
|
||
|
};
|
||
|
|
||
|
function synchronousStart() {
|
||
|
|
||
|
if (canvas instanceof HTMLCanvasElement) {
|
||
|
this.rtenv.canvas = canvas;
|
||
|
} else {
|
||
|
var firstCanvas = document.getElementsByTagName('canvas')[0];
|
||
|
if (firstCanvas instanceof HTMLCanvasElement) {
|
||
|
this.rtenv.canvas = firstCanvas;
|
||
|
} else {
|
||
|
throw new Error("No canvas found");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var actualCanvas = this.rtenv.canvas;
|
||
|
// canvas can grab focus on click
|
||
|
if (actualCanvas.tabIndex < 0) {
|
||
|
actualCanvas.tabIndex = 0;
|
||
|
}
|
||
|
// necessary to calculate cursor coordinates correctly
|
||
|
actualCanvas.style.padding = 0;
|
||
|
actualCanvas.style.borderWidth = 0;
|
||
|
actualCanvas.style.borderStyle = 'none';
|
||
|
// disable right-click context menu
|
||
|
actualCanvas.addEventListener('contextmenu', function(ev) {
|
||
|
ev.preventDefault();
|
||
|
}, false);
|
||
|
// until context restoration is implemented
|
||
|
actualCanvas.addEventListener('webglcontextlost', function(ev) {
|
||
|
alert("WebGL context lost, please reload the page");
|
||
|
ev.preventDefault();
|
||
|
}, false);
|
||
|
|
||
|
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;
|
||
|
|
||
|
preloadedFiles.forEach(function(file) {
|
||
|
var dir = LIBS.PATH.dirname(file.path);
|
||
|
try {
|
||
|
LIBS.FS.stat(dir);
|
||
|
} catch (e) {
|
||
|
if (e.code !== 'ENOENT') {
|
||
|
throw e;
|
||
|
}
|
||
|
LIBS.FS.mkdirTree(dir);
|
||
|
}
|
||
|
// With memory growth, canOwn should be false.
|
||
|
LIBS.FS.createDataFile(file.path, null, new Uint8Array(file.buffer), true, true, false);
|
||
|
}, 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;
|
||
|
var total = 0;
|
||
|
var totalIsValid = true;
|
||
|
var progressIsFinal = true;
|
||
|
|
||
|
[loadingFiles, preloadProgressTracker].forEach(function(tracker) {
|
||
|
Object.keys(tracker).forEach(function(file) {
|
||
|
if (!tracker[file].final)
|
||
|
progressIsFinal = false;
|
||
|
if (!totalIsValid || tracker[file].total === 0) {
|
||
|
totalIsValid = false;
|
||
|
total = 0;
|
||
|
} else {
|
||
|
total += tracker[file].total;
|
||
|
}
|
||
|
loaded += tracker[file].loaded;
|
||
|
});
|
||
|
});
|
||
|
if (loaded !== lastProgress.loaded || total !== lastProgress.total) {
|
||
|
lastProgress.loaded = loaded;
|
||
|
lastProgress.total = total;
|
||
|
if (typeof progressFunc === 'function')
|
||
|
progressFunc(loaded, total);
|
||
|
}
|
||
|
if (!progressIsFinal)
|
||
|
requestAnimationFrame(animateProgress);
|
||
|
}
|
||
|
|
||
|
this.setCanvas = function(elem) {
|
||
|
canvas = elem;
|
||
|
};
|
||
|
|
||
|
this.setExecutableName = function(newName) {
|
||
|
|
||
|
executableName = newName;
|
||
|
};
|
||
|
|
||
|
this.setLocale = function(newLocale) {
|
||
|
|
||
|
locale = newLocale;
|
||
|
};
|
||
|
|
||
|
this.setUnloadAfterInit = function(enabled) {
|
||
|
|
||
|
if (enabled && !unloadAfterInit && initPromise) {
|
||
|
initPromise.then(Engine.unloadEngine);
|
||
|
}
|
||
|
unloadAfterInit = enabled;
|
||
|
};
|
||
|
|
||
|
this.setStdoutFunc = function(func) {
|
||
|
|
||
|
var print = function(text) {
|
||
|
if (arguments.length > 1) {
|
||
|
text = Array.prototype.slice.call(arguments).join(" ");
|
||
|
}
|
||
|
func(text);
|
||
|
};
|
||
|
if (this.rtenv)
|
||
|
this.rtenv.print = print;
|
||
|
stdout = print;
|
||
|
};
|
||
|
|
||
|
this.setStderrFunc = function(func) {
|
||
|
|
||
|
var printErr = function(text) {
|
||
|
if (arguments.length > 1)
|
||
|
text = Array.prototype.slice.call(arguments).join(" ");
|
||
|
func(text);
|
||
|
};
|
||
|
if (this.rtenv)
|
||
|
this.rtenv.printErr = printErr;
|
||
|
stderr = printErr;
|
||
|
};
|
||
|
|
||
|
|
||
|
}; // Engine()
|
||
|
|
||
|
Engine.RuntimeEnvironment = engine.RuntimeEnvironment;
|
||
|
|
||
|
Engine.isWebGLAvailable = function(majorVersion = 1) {
|
||
|
|
||
|
var testContext = false;
|
||
|
try {
|
||
|
var testCanvas = document.createElement('canvas');
|
||
|
if (majorVersion === 1) {
|
||
|
testContext = testCanvas.getContext('webgl') || testCanvas.getContext('experimental-webgl');
|
||
|
} else if (majorVersion === 2) {
|
||
|
testContext = testCanvas.getContext('webgl2') || testCanvas.getContext('experimental-webgl2');
|
||
|
}
|
||
|
} catch (e) {}
|
||
|
return !!testContext;
|
||
|
};
|
||
|
|
||
|
Engine.setWebAssemblyFilenameExtension = function(override) {
|
||
|
|
||
|
if (String(override).length === 0) {
|
||
|
throw new Error('Invalid WebAssembly filename extension override');
|
||
|
}
|
||
|
wasmFilenameExtensionOverride = String(override);
|
||
|
}
|
||
|
|
||
|
Engine.load = function(newBasePath) {
|
||
|
|
||
|
if (newBasePath !== undefined) basePath = getBasePath(newBasePath);
|
||
|
if (engineLoadPromise === null) {
|
||
|
if (typeof WebAssembly !== 'object')
|
||
|
return Promise.reject(new Error("Browser doesn't support WebAssembly"));
|
||
|
// TODO cache/retrieve module to/from idb
|
||
|
engineLoadPromise = loadPromise(basePath + '.' + (wasmFilenameExtensionOverride || 'wasm')).then(function(xhr) {
|
||
|
return xhr.response;
|
||
|
});
|
||
|
engineLoadPromise = engineLoadPromise.catch(function(err) {
|
||
|
engineLoadPromise = null;
|
||
|
throw err;
|
||
|
});
|
||
|
}
|
||
|
return engineLoadPromise;
|
||
|
};
|
||
|
|
||
|
Engine.unload = function() {
|
||
|
engineLoadPromise = null;
|
||
|
};
|
||
|
|
||
|
function loadPromise(file, tracker) {
|
||
|
if (tracker === undefined)
|
||
|
tracker = loadingFiles;
|
||
|
return new Promise(function(resolve, reject) {
|
||
|
loadXHR(resolve, reject, file, tracker);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function loadXHR(resolve, reject, file, tracker) {
|
||
|
|
||
|
var xhr = new XMLHttpRequest;
|
||
|
xhr.open('GET', file);
|
||
|
if (!file.endsWith('.js')) {
|
||
|
xhr.responseType = 'arraybuffer';
|
||
|
}
|
||
|
['loadstart', 'progress', 'load', 'error', 'abort'].forEach(function(ev) {
|
||
|
xhr.addEventListener(ev, onXHREvent.bind(xhr, resolve, reject, file, tracker));
|
||
|
});
|
||
|
xhr.send();
|
||
|
}
|
||
|
|
||
|
function onXHREvent(resolve, reject, file, tracker, ev) {
|
||
|
|
||
|
if (this.status >= 400) {
|
||
|
|
||
|
if (this.status < 500 || ++tracker[file].attempts >= DOWNLOAD_ATTEMPTS_MAX) {
|
||
|
reject(new Error("Failed loading file '" + file + "': " + this.statusText));
|
||
|
this.abort();
|
||
|
return;
|
||
|
} else {
|
||
|
setTimeout(loadXHR.bind(null, resolve, reject, file, tracker), 1000);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (ev.type) {
|
||
|
case 'loadstart':
|
||
|
if (tracker[file] === undefined) {
|
||
|
tracker[file] = {
|
||
|
total: ev.total,
|
||
|
loaded: ev.loaded,
|
||
|
attempts: 0,
|
||
|
final: false,
|
||
|
};
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'progress':
|
||
|
tracker[file].loaded = ev.loaded;
|
||
|
tracker[file].total = ev.total;
|
||
|
break;
|
||
|
|
||
|
case 'load':
|
||
|
tracker[file].final = true;
|
||
|
resolve(this);
|
||
|
break;
|
||
|
|
||
|
case 'error':
|
||
|
if (++tracker[file].attempts >= DOWNLOAD_ATTEMPTS_MAX) {
|
||
|
tracker[file].final = true;
|
||
|
reject(new Error("Failed loading file '" + file + "'"));
|
||
|
} else {
|
||
|
setTimeout(loadXHR.bind(null, resolve, reject, file, tracker), 1000);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'abort':
|
||
|
tracker[file].final = true;
|
||
|
reject(new Error("Loading file '" + file + "' was aborted."));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
})();
|