mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-10 16:03:15 -04:00
Make the game load required resources asynchronously, instead of rewriting --preload-file (for texture pack) and prerun (for IndexedDB)
This commit is contained in:
parent
e0658edfd5
commit
96551c620e
@ -1574,7 +1574,7 @@ static void TexturePackScreen_FilterFiles(const cc_string* path, void* obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void TexturePackScreen_LoadEntries(struct ListScreen* s) {
|
static void TexturePackScreen_LoadEntries(struct ListScreen* s) {
|
||||||
static const cc_string path = String_FromConst(TEXPACKS_DIR);
|
static const cc_string path = String_FromConst("texpacks");
|
||||||
Directory_Enum(&path, &s->entries, TexturePackScreen_FilterFiles);
|
Directory_Enum(&path, &s->entries, TexturePackScreen_FilterFiles);
|
||||||
StringsBuffer_Sort(&s->entries);
|
StringsBuffer_Sort(&s->entries);
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,6 @@ cc_uint64 Stopwatch_Measure(void) {
|
|||||||
*-----------------------------------------------------Directory/File------------------------------------------------------*
|
*-----------------------------------------------------Directory/File------------------------------------------------------*
|
||||||
*#########################################################################################################################*/
|
*#########################################################################################################################*/
|
||||||
extern void interop_InitFilesystem(void);
|
extern void interop_InitFilesystem(void);
|
||||||
extern void interop_LoadIndexedDB(void);
|
|
||||||
cc_result Directory_Create(const cc_string* path) {
|
cc_result Directory_Create(const cc_string* path) {
|
||||||
/* Web filesystem doesn't need directories */
|
/* Web filesystem doesn't need directories */
|
||||||
return 0;
|
return 0;
|
||||||
@ -354,10 +353,10 @@ cc_result Process_StartGame(const cc_string* args, int numArgs) {
|
|||||||
return ERR_NOT_SUPPORTED;
|
return ERR_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
void Process_Exit(cc_result code) {
|
void Process_Exit(cc_result code) {
|
||||||
/* Window isn't implicitly closed when process is exited */
|
/* 'Window' (i.e. the web canvas) isn't implicitly closed when process is exited */
|
||||||
if (code) Window_Close();
|
if (code) Window_Close();
|
||||||
|
/* game normally calls exit with code = 0 due to async IndexedDB loading */
|
||||||
exit(code);
|
if (code) exit(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int interop_OpenTab(const char* url);
|
extern int interop_OpenTab(const char* url);
|
||||||
@ -435,13 +434,7 @@ extern void interop_InitModule(void);
|
|||||||
void Platform_Init(void) {
|
void Platform_Init(void) {
|
||||||
interop_InitModule();
|
interop_InitModule();
|
||||||
interop_InitFilesystem();
|
interop_InitFilesystem();
|
||||||
interop_LoadIndexedDB();
|
|
||||||
interop_InitSockets();
|
interop_InitSockets();
|
||||||
|
|
||||||
/* NOTE: You must pre-load IndexedDB before main() */
|
|
||||||
/* (because pre-loading only works asynchronously) */
|
|
||||||
/* If you don't, you'll get errors later trying to sync local to remote */
|
|
||||||
/* See doc/hosting-webclient.md for example preloading IndexedDB code */
|
|
||||||
}
|
}
|
||||||
void Platform_Free(void) { }
|
void Platform_Free(void) { }
|
||||||
|
|
||||||
@ -454,7 +447,7 @@ cc_result Platform_Decrypt(const void* data, int len, cc_string* dst) { return E
|
|||||||
|
|
||||||
|
|
||||||
/*########################################################################################################################*
|
/*########################################################################################################################*
|
||||||
*-----------------------------------------------------Configuration-------------------------------------------------------*
|
*------------------------------------------------------Main driver--------------------------------------------------------*
|
||||||
*#########################################################################################################################*/
|
*#########################################################################################################################*/
|
||||||
int Platform_GetCommandLineArgs(int argc, STRING_REF char** argv, cc_string* args) {
|
int Platform_GetCommandLineArgs(int argc, STRING_REF char** argv, cc_string* args) {
|
||||||
int i, count;
|
int i, count;
|
||||||
@ -465,9 +458,40 @@ int Platform_GetCommandLineArgs(int argc, STRING_REF char** argv, cc_string* arg
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int interop_DirectorySetWorking(const char* path);
|
|
||||||
cc_result Platform_SetDefaultCurrentDirectory(int argc, char **argv) {
|
cc_result Platform_SetDefaultCurrentDirectory(int argc, char** argv) { return 0; }
|
||||||
/* returned result is negative for error */
|
static int _argc;
|
||||||
return -interop_DirectorySetWorking("/classicube");
|
static char** _argv;
|
||||||
|
|
||||||
|
extern void interop_FS_Init(void);
|
||||||
|
extern void interop_DirectorySetWorking(const char* path);
|
||||||
|
extern void interop_AsyncDownloadTexturePack(const char* path, const char* url);
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
_argc = argc; _argv = argv;
|
||||||
|
|
||||||
|
/* Game loads resources asynchronously, then actually starts itself */
|
||||||
|
/* main
|
||||||
|
/* > texture pack download (async) */
|
||||||
|
/* > load indexedDB (async) */
|
||||||
|
/* > web_main (game actually starts) */
|
||||||
|
|
||||||
|
interop_FS_Init();
|
||||||
|
interop_DirectorySetWorking("/classicube");
|
||||||
|
interop_AsyncDownloadTexturePack("texpacks/default.zip", "static/default.zip");
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void interop_LoadIndexedDB(void);
|
||||||
|
extern void interop_AsyncLoadIndexedDB(void);
|
||||||
|
/* Asynchronous callback after texture pack is downloaded */
|
||||||
|
EMSCRIPTEN_KEEPALIVE void main_phase1(void) {
|
||||||
|
interop_LoadIndexedDB(); /* legacy compatibility */
|
||||||
|
interop_AsyncLoadIndexedDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int web_main(int argc, char** argv);
|
||||||
|
/* Asynchronous callback after IndexedDB is loaded */
|
||||||
|
EMSCRIPTEN_KEEPALIVE void main_phase2(void) {
|
||||||
|
web_main(_argc, _argv);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -136,8 +136,11 @@ void android_main(void) {
|
|||||||
/* Normally, the final code produced for "main" is our "main" combined with crt's main */
|
/* Normally, the final code produced for "main" is our "main" combined with crt's main */
|
||||||
/* (mingw-w64-crt/crt/gccmain.c) - alas this immediately crashes the game on startup. */
|
/* (mingw-w64-crt/crt/gccmain.c) - alas this immediately crashes the game on startup. */
|
||||||
/* Using main_real instead and setting main_real as the entrypoint fixes the crash. */
|
/* Using main_real instead and setting main_real as the entrypoint fixes the crash. */
|
||||||
#ifdef CC_NOMAIN
|
#if defined CC_NOMAIN
|
||||||
int main_real(int argc, char** argv) {
|
int main_real(int argc, char** argv) {
|
||||||
|
#elif defined CC_BUILD_WEB
|
||||||
|
/* web does some asynchronous initialisation first, then calls actual main later */
|
||||||
|
int web_main(int argc, char** argv) {
|
||||||
#else
|
#else
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
#endif
|
#endif
|
||||||
|
@ -341,7 +341,7 @@ static cc_result ExtractFromFile(const cc_string* filename) {
|
|||||||
cc_result res;
|
cc_result res;
|
||||||
|
|
||||||
String_InitArray(path, pathBuffer);
|
String_InitArray(path, pathBuffer);
|
||||||
String_Format1(&path, TEXPACKS_DIR "/%s", filename);
|
String_Format1(&path, "texpacks/%s", filename);
|
||||||
|
|
||||||
res = Stream_OpenFile(&stream, &path);
|
res = Stream_OpenFile(&stream, &path);
|
||||||
if (res) {
|
if (res) {
|
||||||
|
@ -52,12 +52,6 @@ CC_VAR extern struct _Atlas1DData {
|
|||||||
} Atlas1D;
|
} Atlas1D;
|
||||||
|
|
||||||
extern cc_string TexturePack_Url;
|
extern cc_string TexturePack_Url;
|
||||||
#ifdef CC_BUILD_WEB
|
|
||||||
/* texpacks must be read from memory instead of the normal filesystem */
|
|
||||||
#define TEXPACKS_DIR "/texpacks"
|
|
||||||
#else
|
|
||||||
#define TEXPACKS_DIR "texpacks"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define Atlas2D_TileX(texLoc) ((texLoc) & ATLAS2D_MASK) /* texLoc % ATLAS2D_TILES_PER_ROW */
|
#define Atlas2D_TileX(texLoc) ((texLoc) & ATLAS2D_MASK) /* texLoc % ATLAS2D_TILES_PER_ROW */
|
||||||
#define Atlas2D_TileY(texLoc) ((texLoc) >> ATLAS2D_SHIFT) /* texLoc / ATLAS2D_TILES_PER_ROW */
|
#define Atlas2D_TileY(texLoc) ((texLoc) >> ATLAS2D_SHIFT) /* texLoc / ATLAS2D_TILES_PER_ROW */
|
||||||
|
@ -112,7 +112,37 @@ mergeInto(LibraryManager.library, {
|
|||||||
// TODO: This is pretty awful and should be rewritten
|
// TODO: This is pretty awful and should be rewritten
|
||||||
var name = UTF8ToString(path);
|
var name = UTF8ToString(path);
|
||||||
var data = CCFS.readFile(name);
|
var data = CCFS.readFile(name);
|
||||||
CCFS.writeFile('/texpacks/' + name.substring(1), data);
|
CCFS.writeFile('texpacks/' + name.substring(1), data);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
//########################################################################################################################
|
||||||
|
//-------------------------------------------------------Main driver------------------------------------------------------
|
||||||
|
//########################################################################################################################
|
||||||
|
interop_AsyncDownloadTexturePack: function (rawPath, rawUrl) {
|
||||||
|
var path = UTF8ToString(rawPath);
|
||||||
|
var url = UTF8ToString(rawUrl);
|
||||||
|
Module.setStatus('Downloading textures.. (1/2)');
|
||||||
|
|
||||||
|
Module.readAsync(url,
|
||||||
|
function(buffer) { // onload TODO avoid new UInt8Array
|
||||||
|
CCFS.writeFile(path, new Uint8Array(buffer), { canOwn: true });
|
||||||
|
ccall('main_phase1', 'void');
|
||||||
|
},
|
||||||
|
function() { // onerror
|
||||||
|
ccall('main_phase1', 'void');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
interop_AsyncLoadIndexedDB__deps: ['IDBFS_loadFS'],
|
||||||
|
interop_AsyncLoadIndexedDB: function() {
|
||||||
|
Module.setStatus('Loading IndexedDB filesystem.. (2/2)');
|
||||||
|
|
||||||
|
_IDBFS_loadFS(function(err) {
|
||||||
|
if (err) window.cc_idbErr = err;
|
||||||
|
Module.setStatus('');
|
||||||
|
ccall('main_phase2', 'void');
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -145,14 +175,19 @@ mergeInto(LibraryManager.library, {
|
|||||||
interop_DirectorySetWorking: function (raw) {
|
interop_DirectorySetWorking: function (raw) {
|
||||||
var path = UTF8ToString(raw);
|
var path = UTF8ToString(raw);
|
||||||
CCFS.chdir(path);
|
CCFS.chdir(path);
|
||||||
return 0;
|
|
||||||
},
|
},
|
||||||
interop_DirectoryIter: function(raw) {
|
interop_DirectoryIter: function(raw) {
|
||||||
var path = UTF8ToString(raw);
|
var path = UTF8ToString(raw);
|
||||||
try {
|
try {
|
||||||
var entries = CCFS.readdir(path);
|
var entries = CCFS.readdir(path);
|
||||||
for (var i = 0; i < entries.length; i++) {
|
for (var i = 0; i < entries.length; i++)
|
||||||
ccall('Directory_IterCallback', 'void', ['string'], [entries[i]]);
|
{
|
||||||
|
var path = entries[i];
|
||||||
|
// absolute path to root relative path
|
||||||
|
if (path.indexOf(CCFS.currentPath) === 0) {
|
||||||
|
path = path.substring(CCFS.currentPath.length + 1);
|
||||||
|
}
|
||||||
|
ccall('Directory_IterCallback', 'void', ['string'], [path]);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -236,18 +271,12 @@ mergeInto(LibraryManager.library, {
|
|||||||
var msg = 'Error preloading IndexedDB:' + window.cc_idbErr + '\n\nPreviously saved settings/maps will be lost';
|
var msg = 'Error preloading IndexedDB:' + window.cc_idbErr + '\n\nPreviously saved settings/maps will be lost';
|
||||||
ccall('Platform_LogError', 'void', ['string'], [msg]);
|
ccall('Platform_LogError', 'void', ['string'], [msg]);
|
||||||
},
|
},
|
||||||
interop_LoadIndexedDB__deps: ['IDBFS_loadFS', 'FS_Init'],
|
|
||||||
interop_LoadIndexedDB: function() {
|
interop_LoadIndexedDB: function() {
|
||||||
_FS_Init();
|
// previously you were required to add interop_LoadIndexedDB to Module.preRun array
|
||||||
// already loaded IndexDB? do nothing then
|
// to load the indexedDB asynchronously *before* starting ClassiCube, because it
|
||||||
if (CCFS.preloaded) return;
|
// could not load indexedDB asynchronously
|
||||||
CCFS.preloaded = true;
|
// however, as ClassiCube now loads IndexedDB asynchronously itself, this is no longer
|
||||||
|
// necessary, but is kept arounf foe backwards compatibility
|
||||||
addRunDependency('load-idb');
|
|
||||||
_IDBFS_loadFS(function(err) {
|
|
||||||
if (err) window.cc_idbErr = err;
|
|
||||||
removeRunDependency('load-idb');
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
interop_SaveNode__deps: ['IDBFS_getDB', 'IDBFS_storeRemoteEntry'],
|
interop_SaveNode__deps: ['IDBFS_getDB', 'IDBFS_storeRemoteEntry'],
|
||||||
interop_SaveNode: function(path) {
|
interop_SaveNode: function(path) {
|
||||||
@ -822,7 +851,7 @@ mergeInto(LibraryManager.library, {
|
|||||||
|
|
||||||
reader.onload = function(e) {
|
reader.onload = function(e) {
|
||||||
var data = new Uint8Array(e.target.result);
|
var data = new Uint8Array(e.target.result);
|
||||||
CCFS.createDataFile('/' + name, data, true);
|
CCFS.writeFile('/' + name, data, { canOwn: true });
|
||||||
ccall('Window_OnFileUploaded', 'void', ['string'], ['/' + name]);
|
ccall('Window_OnFileUploaded', 'void', ['string'], ['/' + name]);
|
||||||
CCFS.unlink('/' + name);
|
CCFS.unlink('/' + name);
|
||||||
};
|
};
|
||||||
@ -1050,10 +1079,10 @@ mergeInto(LibraryManager.library, {
|
|||||||
//########################################################################################################################
|
//########################################################################################################################
|
||||||
//------------------------------------------------------------FS----------------------------------------------------------
|
//------------------------------------------------------------FS----------------------------------------------------------
|
||||||
//########################################################################################################################
|
//########################################################################################################################
|
||||||
FS_Init: function() {
|
interop_FS_Init: function() {
|
||||||
if (window.CCFS) return;
|
if (window.CCFS) return;
|
||||||
|
|
||||||
window.MEMFS={
|
window.MEMFS={
|
||||||
createNode:function(path) {
|
createNode:function(path) {
|
||||||
var node = CCFS.createNode(path);
|
var node = CCFS.createNode(path);
|
||||||
node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity.
|
node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity.
|
||||||
@ -1171,11 +1200,10 @@ mergeInto(LibraryManager.library, {
|
|||||||
return (mode & 61440) === CCFS.MODE_TYPE_FILE;
|
return (mode & 61440) === CCFS.MODE_TYPE_FILE;
|
||||||
},
|
},
|
||||||
nextfd:function() {
|
nextfd:function() {
|
||||||
// max 4096 open files
|
// max 4096 open files
|
||||||
for (var fd = 0; fd <= 4096; fd++) {
|
for (var fd = 0; fd <= 4096; fd++)
|
||||||
if (!CCFS.streams[fd]) {
|
{
|
||||||
return fd;
|
if (!CCFS.streams[fd]) return fd;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw new CCFS.ErrnoError(24);
|
throw new CCFS.ErrnoError(24);
|
||||||
},
|
},
|
||||||
@ -1367,35 +1395,6 @@ mergeInto(LibraryManager.library, {
|
|||||||
};
|
};
|
||||||
CCFS.ErrnoError.prototype = new Error();
|
CCFS.ErrnoError.prototype = new Error();
|
||||||
CCFS.ErrnoError.prototype.constructor = CCFS.ErrnoError;
|
CCFS.ErrnoError.prototype.constructor = CCFS.ErrnoError;
|
||||||
},
|
|
||||||
createDataFile:function(path, data, canOwn) {
|
|
||||||
if (!data) return;
|
|
||||||
|
|
||||||
if (typeof data === 'string') {
|
|
||||||
var arr = new Array(data.length);
|
|
||||||
for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
|
|
||||||
data = arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
var stream = CCFS.open(path, 577); // O_WRONLY | O_CREAT | O_TRUNC
|
|
||||||
CCFS.write(stream, data, 0, data.length, 0, canOwn);
|
|
||||||
CCFS.close(stream);
|
|
||||||
},
|
|
||||||
createPreloadedFile:function(path, url, onload, onerror, canOwn, preFinish) {
|
|
||||||
Browser.init(); // XXX perhaps this method should move onto Browser?
|
|
||||||
var dep = getUniqueRunDependency('cp ' + name);
|
|
||||||
|
|
||||||
function processData(byteArray) {
|
|
||||||
if (preFinish) preFinish();
|
|
||||||
CCFS.createDataFile(path, byteArray, canOwn);
|
|
||||||
if (onload) onload();
|
|
||||||
removeRunDependency(dep)
|
|
||||||
}
|
|
||||||
|
|
||||||
addRunDependency(dep);
|
|
||||||
Browser.asyncLoad(url, function(byteArray) {
|
|
||||||
processData(byteArray);
|
|
||||||
}, onerror);
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
CCFS.ensureErrnoError();
|
CCFS.ensureErrnoError();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user