mirror of
https://github.com/The-Powder-Toy/The-Powder-Toy.git
synced 2025-08-11 10:54:15 +02:00
Emscripten: Support persistent storage
This commit is contained in:
@@ -209,7 +209,10 @@ if host_platform == 'emscripten'
|
|||||||
'-s', 'WASM=1',
|
'-s', 'WASM=1',
|
||||||
'-s', 'ALLOW_MEMORY_GROWTH=1',
|
'-s', 'ALLOW_MEMORY_GROWTH=1',
|
||||||
'-s', 'FORCE_FILESYSTEM=1',
|
'-s', 'FORCE_FILESYSTEM=1',
|
||||||
'-s', 'EXIT_RUNTIME=1',
|
'-s', 'EXIT_RUNTIME=0',
|
||||||
|
'-s', 'EXPORTED_RUNTIME_METHODS=ccall,cwrap',
|
||||||
|
'-s', 'FS_DEBUG',
|
||||||
|
'-lidbfs.js',
|
||||||
]
|
]
|
||||||
emcc_args = [
|
emcc_args = [
|
||||||
'-s', 'USE_SDL=2',
|
'-s', 'USE_SDL=2',
|
||||||
|
@@ -182,6 +182,11 @@ static std::unique_ptr<ExplicitSingletons> explicitSingletons;
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
Platform::SetupCrt();
|
Platform::SetupCrt();
|
||||||
|
return Platform::InvokeMain(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Main(int argc, char *argv[])
|
||||||
|
{
|
||||||
Platform::Atexit([]() {
|
Platform::Atexit([]() {
|
||||||
SaveWindowPosition();
|
SaveWindowPosition();
|
||||||
// Unregister dodgy error handlers so they don't try to show the blue screen when the window is closed
|
// Unregister dodgy error handlers so they don't try to show the blue screen when the window is closed
|
||||||
@@ -254,22 +259,22 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto ddir = std::unique_ptr<char, decltype(&SDL_free)>(SDL_GetPrefPath(NULL, APPDATA), SDL_free);
|
auto ddir = Platform::DefaultDdir();
|
||||||
if (!Platform::FileExists("powder.pref"))
|
if (!Platform::FileExists("powder.pref"))
|
||||||
{
|
{
|
||||||
if (ddir)
|
if (ddir.size())
|
||||||
{
|
{
|
||||||
if (!Platform::ChangeDir(ddir.get()))
|
if (!Platform::ChangeDir(ddir))
|
||||||
{
|
{
|
||||||
perror("failed to chdir to default ddir");
|
perror("failed to chdir to default ddir");
|
||||||
ddir.reset();
|
ddir = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ddir)
|
if (ddir.size())
|
||||||
{
|
{
|
||||||
Platform::sharedCwd = ddir.get();
|
Platform::sharedCwd = ddir;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We're now in the correct directory, time to get prefs.
|
// We're now in the correct directory, time to get prefs.
|
||||||
|
@@ -3,12 +3,23 @@
|
|||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace Platform
|
||||||
|
{
|
||||||
|
void MaybeTriggerSyncFs();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MainLoopBody()
|
||||||
|
{
|
||||||
|
EngineProcess();
|
||||||
|
Platform::MaybeTriggerSyncFs();
|
||||||
|
}
|
||||||
|
|
||||||
void SetFpsLimit(FpsLimit newFpsLimit)
|
void SetFpsLimit(FpsLimit newFpsLimit)
|
||||||
{
|
{
|
||||||
static bool mainLoopSet = false;
|
static bool mainLoopSet = false;
|
||||||
if (!mainLoopSet)
|
if (!mainLoopSet)
|
||||||
{
|
{
|
||||||
emscripten_set_main_loop(EngineProcess, 0, 0);
|
emscripten_set_main_loop(MainLoopBody, 0, 0);
|
||||||
mainLoopSet = true;
|
mainLoopSet = true;
|
||||||
}
|
}
|
||||||
if (auto *fpsLimitVsync = std::get_if<FpsLimitVsync>(&newFpsLimit))
|
if (auto *fpsLimitVsync = std::get_if<FpsLimitVsync>(&newFpsLimit))
|
||||||
@@ -28,8 +39,9 @@ void SetFpsLimit(FpsLimit newFpsLimit)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is actually only called once at startup, the real main loop body is MainLoopBody.
|
||||||
void MainLoop()
|
void MainLoop()
|
||||||
{
|
{
|
||||||
SetFpsLimit(ui::Engine::Ref().GetFpsLimit());
|
SetFpsLimit(ui::Engine::Ref().GetFpsLimit());
|
||||||
EngineProcess();
|
MainLoopBody();
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@ namespace http
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void RequestManager_UpdateRequestStatusThunk(http::RequestHandleHttp *handle);
|
EMSCRIPTEN_KEEPALIVE extern "C" void RequestManager_UpdateRequestStatusThunk(http::RequestHandleHttp *handle);
|
||||||
|
|
||||||
namespace http
|
namespace http
|
||||||
{
|
{
|
||||||
|
@@ -6,10 +6,6 @@ if not enable_http
|
|||||||
client_files += files('Null.cpp')
|
client_files += files('Null.cpp')
|
||||||
elif host_platform == 'emscripten'
|
elif host_platform == 'emscripten'
|
||||||
client_files += files('Emscripten.cpp')
|
client_files += files('Emscripten.cpp')
|
||||||
project_link_args += [
|
|
||||||
'-s', 'EXPORTED_FUNCTIONS=_main,_RequestManager_UpdateRequestStatusThunk',
|
|
||||||
'-s', 'EXPORTED_RUNTIME_METHODS=cwrap',
|
|
||||||
]
|
|
||||||
else
|
else
|
||||||
client_files += files('Libcurl.cpp')
|
client_files += files('Libcurl.cpp')
|
||||||
endif
|
endif
|
||||||
|
@@ -24,4 +24,8 @@ bool CanUpdate()
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetupCrt()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -48,4 +48,8 @@ bool CanUpdate()
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetupCrt()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
14
src/common/platform/DdirCommon.cpp
Normal file
14
src/common/platform/DdirCommon.cpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#include "Platform.h"
|
||||||
|
#include "common/String.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Platform
|
||||||
|
{
|
||||||
|
ByteString DefaultDdir()
|
||||||
|
{
|
||||||
|
auto ddir = std::unique_ptr<char, decltype(&SDL_free)>(SDL_GetPrefPath(NULL, APPDATA), SDL_free);
|
||||||
|
return ddir.get();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,17 @@
|
|||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <emscripten.h>
|
||||||
|
#include <emscripten/threading.h>
|
||||||
|
#include <atomic>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
static std::atomic<bool> shouldSyncFs = false;
|
||||||
|
static bool syncFsInFlight = false;
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE extern "C" void Platform_SyncFsDone()
|
||||||
|
{
|
||||||
|
syncFsInFlight = false;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Platform
|
namespace Platform
|
||||||
{
|
{
|
||||||
@@ -37,4 +49,84 @@ void Atexit(ExitFunc exitFunc)
|
|||||||
void Exit(int code)
|
void Exit(int code)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ByteString DefaultDdir()
|
||||||
|
{
|
||||||
|
return "/powder";
|
||||||
|
}
|
||||||
|
|
||||||
|
int InvokeMain(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
EM_ASM({
|
||||||
|
FS.syncfs(true, () => {
|
||||||
|
Module.ccall('MainJs', 'number', [ 'number', 'number' ], [ $0, $1 ]);
|
||||||
|
});
|
||||||
|
}, argc, argv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaybeTriggerSyncFs()
|
||||||
|
{
|
||||||
|
if (!syncFsInFlight && shouldSyncFs.exchange(false, std::memory_order_relaxed))
|
||||||
|
{
|
||||||
|
std::cerr << "invoking FS.syncfs" << std::endl;
|
||||||
|
syncFsInFlight = true;
|
||||||
|
EM_ASM({
|
||||||
|
FS.syncfs(false, err => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
Module.ccall('Platform_SyncFsDone', null, [], []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE extern "C" int MainJs(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
return Main(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE extern "C" void Platform_ShouldSyncFs()
|
||||||
|
{
|
||||||
|
shouldSyncFs.store(true, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Platform
|
||||||
|
{
|
||||||
|
void SetupCrt()
|
||||||
|
{
|
||||||
|
EM_ASM({
|
||||||
|
let ddir = UTF8ToString($0);
|
||||||
|
let prefix = ddir + '/';
|
||||||
|
let shouldSyncFs = Module.cwrap(
|
||||||
|
'Platform_ShouldSyncFs',
|
||||||
|
null,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
FS.trackingDelegate['onMovePath'] = function(oldpath, newpath) {
|
||||||
|
if (oldpath.startsWith(prefix) || newpath.startsWith(prefix)) {
|
||||||
|
shouldSyncFs();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FS.trackingDelegate['onDeletePath'] = function(path) {
|
||||||
|
if (path.startsWith(prefix)) {
|
||||||
|
shouldSyncFs();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FS.trackingDelegate['onWriteToFile'] = function(path, bytesWritten) {
|
||||||
|
if (path.startsWith(prefix)) {
|
||||||
|
shouldSyncFs();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FS.trackingDelegate['onMakeDirectory'] = function(path, mode) {
|
||||||
|
if (path.startsWith(prefix)) {
|
||||||
|
shouldSyncFs();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FS.mkdir(ddir);
|
||||||
|
FS.mount(IDBFS, {}, ddir);
|
||||||
|
}, DefaultDdir().c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -109,4 +109,8 @@ bool Install()
|
|||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetupCrt()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
9
src/common/platform/MainCommon.cpp
Normal file
9
src/common/platform/MainCommon.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "Platform.h"
|
||||||
|
|
||||||
|
namespace Platform
|
||||||
|
{
|
||||||
|
int InvokeMain(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
return Main(argc, argv);
|
||||||
|
}
|
||||||
|
}
|
@@ -11,4 +11,8 @@ bool CanUpdate()
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetupCrt()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,4 +62,10 @@ namespace Platform
|
|||||||
using ExitFunc = void (*)();
|
using ExitFunc = void (*)();
|
||||||
void Atexit(ExitFunc exitFunc);
|
void Atexit(ExitFunc exitFunc);
|
||||||
void Exit(int code);
|
void Exit(int code);
|
||||||
|
|
||||||
|
ByteString DefaultDdir();
|
||||||
|
|
||||||
|
int InvokeMain(int argc, char *argv[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" int Main(int argc, char *argv[]);
|
||||||
|
@@ -218,8 +218,4 @@ bool UpdateFinish()
|
|||||||
void UpdateCleanup()
|
void UpdateCleanup()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupCrt()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,10 @@ if host_platform == 'windows'
|
|||||||
'Windows.cpp',
|
'Windows.cpp',
|
||||||
'ExitCommon.cpp',
|
'ExitCommon.cpp',
|
||||||
)
|
)
|
||||||
|
powder_files += files(
|
||||||
|
'MainCommon.cpp',
|
||||||
|
'DdirCommon.cpp',
|
||||||
|
)
|
||||||
elif host_platform == 'darwin'
|
elif host_platform == 'darwin'
|
||||||
can_install_enforce_no = true
|
can_install_enforce_no = true
|
||||||
common_files += files(
|
common_files += files(
|
||||||
@@ -19,6 +23,10 @@ elif host_platform == 'darwin'
|
|||||||
'Posix.cpp',
|
'Posix.cpp',
|
||||||
'ExitCommon.cpp',
|
'ExitCommon.cpp',
|
||||||
)
|
)
|
||||||
|
powder_files += files(
|
||||||
|
'MainCommon.cpp',
|
||||||
|
'DdirCommon.cpp',
|
||||||
|
)
|
||||||
elif host_platform == 'android'
|
elif host_platform == 'android'
|
||||||
can_install_enforce_no = true
|
can_install_enforce_no = true
|
||||||
common_files += files(
|
common_files += files(
|
||||||
@@ -26,6 +34,10 @@ elif host_platform == 'android'
|
|||||||
'Posix.cpp',
|
'Posix.cpp',
|
||||||
'ExitCommon.cpp',
|
'ExitCommon.cpp',
|
||||||
)
|
)
|
||||||
|
powder_files += files(
|
||||||
|
'MainCommon.cpp',
|
||||||
|
'DdirCommon.cpp',
|
||||||
|
)
|
||||||
elif host_platform == 'emscripten'
|
elif host_platform == 'emscripten'
|
||||||
use_bluescreen = false
|
use_bluescreen = false
|
||||||
can_install_enforce_no = true
|
can_install_enforce_no = true
|
||||||
@@ -41,6 +53,10 @@ elif host_platform == 'linux'
|
|||||||
'Posix.cpp',
|
'Posix.cpp',
|
||||||
'ExitCommon.cpp',
|
'ExitCommon.cpp',
|
||||||
)
|
)
|
||||||
|
powder_files += files(
|
||||||
|
'MainCommon.cpp',
|
||||||
|
'DdirCommon.cpp',
|
||||||
|
)
|
||||||
else
|
else
|
||||||
can_install_enforce_no = true
|
can_install_enforce_no = true
|
||||||
common_files += files(
|
common_files += files(
|
||||||
@@ -48,6 +64,10 @@ else
|
|||||||
'Posix.cpp',
|
'Posix.cpp',
|
||||||
'ExitCommon.cpp',
|
'ExitCommon.cpp',
|
||||||
)
|
)
|
||||||
|
powder_files += files(
|
||||||
|
'MainCommon.cpp',
|
||||||
|
'DdirCommon.cpp',
|
||||||
|
)
|
||||||
endif
|
endif
|
||||||
conf_data.set('SET_WINDOW_ICON', set_window_icon ? 'true' : 'false')
|
conf_data.set('SET_WINDOW_ICON', set_window_icon ? 'true' : 'false')
|
||||||
conf_data.set('PATH_SEP_CHAR', path_sep_char)
|
conf_data.set('PATH_SEP_CHAR', path_sep_char)
|
||||||
|
Reference in New Issue
Block a user