Memory is cleared / released when a server or client begins, not when they end.
*/
+#ifdef __EMSCRIPTEN__
+
+EM_JS(bool,syncFS,(bool x),{
+ FS.syncfs(x,function(e){
+ if(e){
+ alert("FileSystem Save Error: "+e);
+ return false;
+ } else{
+ console.log("Filesystem Saved!");
+ return true;
+ }
+ })});
+
+EM_JS(void,emshutdown,(),{
+ FS.syncfs(false,function(e){
+ if(e){
+ alert("FileSystem Save Error: "+e+" while shutting down.");
+ return false;
+ } else{
+ console.log("Filesystem Saved!");
+ return true;
+ }
+ });
+ window.close();
+})
+
+EM_JS(char*,rm,(char* x),{
+ const mode = FS.lookupPath(UTF8ToString(x)).node.mode;
+ if(FS.isFile(mode)){
+ FS.unlink(UTF8ToString(x));
+ return stringToNewUTF8("File removed");
+ }
+ else {
+ return stringToNewUTF8(x+" is not a File.");
+ }
+ });
+
+EM_JS(char*,rmdir,(char* x),{
+ const mode = FS.lookupPath(UTF8ToString(x)).node.mode;
+ if(FS.isDir(mode)){
+ try{FS.rmdir(UTF8ToString(x));} catch (error) {return stringToNewUTF8("Unable to remove directory. Is it not empty?");}
+
+ return stringToNewUTF8("Directory removed");
+ }
+ else {
+ return stringToNewUTF8(x+" is not a directory.");
+ }
+ });
+
+EM_JS(void,readyup,(),{
+ if (isready() == 0) {
+ alert("No GameData Found. Please upload all GameData using the \"em_upload\" command, save with \"em_save\" and restart the game!");
+ //straight off stackoverflow(well, slightly changed). Thanks, Riot!
+ FS.mkdir("/save/data");
+ }
+});
+
+EM_JS(char*,upload,(char* todirectory),{
+ if(UTF8ToString(todirectory).slice(-1) != "/"){
+ currentname = UTF8ToString(todirectory) + "/";
+ }
+ else{
+ currentname = UTF8ToString(todirectory);
+ }
+
+ file_selector.click();
+ return stringToNewUTF8("Upload started");
+
+});
+
+EM_JS(char*, listfiles,(char* directory),{ if(UTF8ToString(directory) == ""){
+ console.log("listing cwd");
+ return stringToNewUTF8(FS.readdir(FS.cwd()).toString())
+}
+try{
+return stringToNewUTF8(FS.readdir(UTF8ToString(directory)).toString());
+} catch(error){
+ return stringToNewUTF8("directory not found");
+}
+});
+
+void listfiles_f(cmd_state_t *cmd){
+ if(Cmd_Argc(cmd) != 2){
+
+ Con_Printf(listfiles(""));
+ Con_Printf("\n");
+ }
+ else{
+ Con_Printf(listfiles(Cmd_Argv(cmd,1)) );
+ Con_Printf("\n");
+ }
+}
+void savefs_f(cmd_state_t *cmd){
+ Con_Printf("Saving Files\n");
+ if(syncFS(false)){
+ Con_Printf("Files Saved to Browser Storage\n");
+ } else{
+ Con_Printf("File Save failed.\n");
+ }
+}
+
+void upload_f(cmd_state_t *cmd){
+ if(Cmd_Argc(cmd) != 2){
+ Con_Printf(upload("/save/data"));
+ Con_Printf("\n");
+ }
+ else{
+ Con_Printf(upload(Cmd_Argv(cmd,1)));
+ Con_Printf("\n");
+ }
+}
+
+void rm_f(cmd_state_t *cmd){
+ if(Cmd_Argc(cmd) != 2){
+ Con_Printf("No file to remove");
+ }
+ else{
+ Con_Printf(rm(Cmd_Argv(cmd,1)));
+ Con_Printf("\n");
+ }
+}
+
+void rmdir_f(cmd_state_t *cmd){
+ if(Cmd_Argc(cmd) != 2){
+ Con_Printf("No directory to remove");
+ }
+ else{
+ Con_Printf(rmdir(Cmd_Argv(cmd,1)));
+ Con_Printf("\n");
+ }
+}
+bool engineup = false;
+
+void fillcanvas(){
+ EmscriptenFullscreenStrategy strat;
+ strat.scaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
+ strat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
+ strat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
+ emscripten_enter_soft_fullscreen("canvas",&strat);
+}
+
+#endif
host_static_t host;
cvar_t host_isclient = {CF_SHARED | CF_READONLY, "_host_isclient", "0", "If 1, clientside is active."};
+
+
/*
================
Host_AbortCurrentFrame
FS_Close (f);
}
- EM_ASM(FS.syncfs());
+ syncFS(false);
}
static void Host_SaveConfig_f(cmd_state_t *cmd)
*/
static void Host_LoadConfig_f(cmd_state_t *cmd)
{
+ #ifdef __EMSCRIPTEN__
+ syncFS(true);
+ #endif
// reset all cvars, commands and aliases to init values
Cmd_RestoreInitState();
#ifdef CONFIG_MENU
Cmd_AddCommand(CF_SHARED, "saveconfig", Host_SaveConfig_f, "save settings to config.cfg (or a specified filename) immediately (also automatic when quitting)");
Cmd_AddCommand(CF_SHARED, "loadconfig", Host_LoadConfig_f, "reset everything and reload configs");
Cmd_AddCommand(CF_SHARED, "sendcvar", SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
+ #ifdef __EMSCRIPTEN__
+ Cmd_AddCommand(CF_SHARED, "em_ls", listfiles_f, "Lists Files in specified directory defaulting to the current working directory (Emscripten Only)");
+ Cmd_AddCommand(CF_SHARED, "em_upload", upload_f, "Upload file to specified directory defaulting to /save/data (Emscripten Only)");
+ Cmd_AddCommand(CF_SHARED, "em_save", savefs_f, "Save file changes to browser (Emscripten Only)");
+ Cmd_AddCommand(CF_SHARED, "em_rm", rm_f, "Remove a file from game Filesystem (Emscripten Only)");
+ Cmd_AddCommand(CF_SHARED, "em_rmdir", rmdir_f, "Remove a directory from game Filesystem (Emscripten Only)");
+ #endif
Cvar_RegisterVariable (&host_framerate);
Cvar_RegisterCallback (&host_framerate, Host_Framerate_c);
Cvar_RegisterVariable (&host_speeds);
*/
static void Host_Init (void)
{
+ #ifdef __EMSCRIPTEN__
+ readyup();
+ fillcanvas();
+ #endif
int i;
const char* os;
char vabuf[1024];
FS_Init();
// construct a version string for the corner of the console
- os = DP_OS_NAME;
+ #ifndef __EMSCRIPTEN__
+ os = DP_OS_NAME;
+ #else
+ os = "Emscripten";
+ #endif
dpsnprintf (engineversion, sizeof (engineversion), "%s %s %s", gamename, os, buildstring);
Con_Printf("%s\n", engineversion);
}
Con_DPrint("========Initialized=========\n");
-
+
+ #ifdef __EMSCRIPTEN__
+ engineup = true;
+ #endif
if (cls.state != ca_dedicated)
SV_StartThread();
}
return time;
}
-#ifdef __EMSCRIPTEN__
-EM_JS(void,emshutdown,(),{FS.syncfs(); window.close();});
-#endif
+
void Host_Loop(void){
// Something bad happened, or the server disconnected
+ #ifdef __EMSCRIPTEN__
+ if(engineup == false){
+ return;
+ }
+ #endif
+
if (setjmp(host.abortframe))
{
host.state = host_active; // In case we were loading
sleeptime -= Sys_DirtyTime() - host.dirtytime; // execution time
host.sleeptime = Host_Sleep(sleeptime);
+
#ifdef __EMSCRIPTEN__
- if(host.state == host_shutdown){
- emshutdown();
- }
+ if(host.state == host_shutdown){emshutdown(); engineup = false;}
#endif
+
}
+
+
void Host_Main(void)
{
-
+
Host_Init(); // Start!
-
host.realtime = 0;
oldtime = Sys_DirtyTime();
#include "cdaudio.h"
#include "image.h"
#include "progsvm.h"
-
#include "mprogdefs.h"
+#ifdef __EMSCRIPTEN__
+ #include <emscripten.h>
+#endif
#define TYPE_DEMO 1
#define TYPE_GAME 2
#define TYPE_BOTH 3
static qbool m_missingdata = false;
static int MAIN_ITEMS = 4; // Nehahra: Menu Disable
-
+static qbool emmenu = false;
void M_Menu_Main_f(cmd_state_t *cmd)
{
MAIN_ITEMS = 5;
// check if the game data is missing and use a different main menu if so
+
m_missingdata = !forceqmenu.integer && !Draw_IsPicLoaded(Draw_CachePic_Flags(s, CACHEPICFLAG_FAILONMISSING));
if (m_missingdata)
MAIN_ITEMS = 2;
+ #ifdef __EMSCRIPTEN__
+ MAIN_ITEMS=1;
+ emmenu = true;
+ #endif
/*
if (key_dest != key_menu)
{
cachepic_t *p;
char vabuf[1024];
- if (m_missingdata)
+ if(emmenu){
+ M_Background(640, 480); //fall back is always to 640x480, this makes it most readable at that.
+ float y;
+ const char *s;
+ y = 480/3-16;
+ s = "Press Enter to Start Game";M_PrintRed ((640-strlen(s)*8)*0.5, (480/3)-16, s);y+=8;
+ }
+ else if (m_missingdata)
{
float y;
const char *s;
M_DrawPic (54, 32 + m_main_cursor * 20, va(vabuf, sizeof(vabuf), "gfx/menudot%i", f+1));
}
+void M_Menu_Restart_f(cmd_state_t *cmd){
+ Cbuf_AddText(cmd, "loadconfig\nmenu_reset\n");
+ Cbuf_Execute(cmd->cbuf);
+}
static void M_Main_Key(cmd_state_t *cmd, int key, int ascii)
{
case K_ENTER:
m_entersound = true;
-
+ if(emmenu){
+ emmenu = false;
+ M_Menu_Restart_f(cmd);
+ }
if (m_missingdata)
{
switch (m_main_cursor)
}
}
+
void M_Menu_Reset_f(cmd_state_t *cmd)
{
key_dest = key_menu;