mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-24 23:34:37 +01:00
Emscripten: Reimplement save/load
This commit is contained in:
@@ -12,7 +12,7 @@ if (EMSCRIPTEN)
|
||||
endif ()
|
||||
set(SHARED_FLAGS "-fexceptions")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${USE_FLAGS} ${SHARED_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EMSCRIPTEN_LDFLAGS} --bind ${SHARED_FLAGS} -s EXPORTED_FUNCTIONS=_GetVersion,_main --js-library ${ROOT_DIR}/emscripten/deps.js")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EMSCRIPTEN_LDFLAGS} --bind ${SHARED_FLAGS} -sEXPORTED_FUNCTIONS=${EMSCRIPTEN_EXPORTED_FUNCTIONS} --js-library ${ROOT_DIR}/emscripten/deps.js")
|
||||
find_package(SpeexDSP REQUIRED)
|
||||
elseif (MSVC)
|
||||
find_package(SDL2 REQUIRED)
|
||||
|
||||
@@ -28,6 +28,13 @@
|
||||
#include <openrct2/ui/WindowManager.h>
|
||||
#include <openrct2/windows/Intent.h>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
extern "C" {
|
||||
extern void EmscriptenLoadGame(LoadSaveType type);
|
||||
extern void EmscriptenSaveGame(bool isTrackDesign, bool isAutosave, bool saveAs, LoadSaveType type);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace OpenRCT2::Ui::FileBrowser
|
||||
{
|
||||
static LoadSaveCallback _loadSaveCallback;
|
||||
@@ -37,6 +44,19 @@ namespace OpenRCT2::Ui::FileBrowser
|
||||
{
|
||||
RegisterCallback(callback);
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
if (action == LoadSaveAction::save)
|
||||
{
|
||||
Select("/save.park", action, type, trackDesign);
|
||||
EmscriptenSaveGame(type == LoadSaveType::track, false, true, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmscriptenLoadGame(type);
|
||||
}
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
auto hasFilePicker = OpenRCT2::GetContext()->GetUiContext().HasFilePicker();
|
||||
auto& config = Config::Get().general;
|
||||
|
||||
@@ -526,3 +546,10 @@ namespace OpenRCT2::Ui::FileBrowser
|
||||
return ContextOpenCommonFileDialog(desc);
|
||||
}
|
||||
} // namespace OpenRCT2::Ui::FileBrowser
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
extern "C" void LoadGameCallback(const char* path, LoadSaveType action)
|
||||
{
|
||||
OpenRCT2::Ui::FileBrowser::Select(path, LoadSaveAction::load, action, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -66,3 +66,7 @@ namespace OpenRCT2::Ui::FileBrowser
|
||||
WindowBase* OpenPreferred(
|
||||
LoadSaveAction action, LoadSaveType type, u8string defaultPath, LoadSaveCallback callback, TrackDesign* trackDesign);
|
||||
} // namespace OpenRCT2::Ui::FileBrowser
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
extern "C" void LoadGameCallback(const char* path, LoadSaveType action);
|
||||
#endif
|
||||
|
||||
@@ -48,6 +48,13 @@
|
||||
#include <openrct2/world/Scenery.h>
|
||||
#include <string>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
extern "C" {
|
||||
extern void EmscriptenLoadGame();
|
||||
}
|
||||
#endif
|
||||
|
||||
using namespace OpenRCT2::Numerics;
|
||||
|
||||
namespace OpenRCT2::Ui::Windows
|
||||
|
||||
@@ -182,7 +182,7 @@ target_link_libraries(libopenrct2 Threads::Threads)
|
||||
|
||||
# For some reason, these flags break the check for pthreads. Add them after.
|
||||
if (EMSCRIPTEN)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORTED_FUNCTIONS=_GetVersion,_main --js-library ${ROOT_DIR}/emscripten/deps.js")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORTED_FUNCTIONS=${EMSCRIPTEN_EXPORTED_FUNCTIONS} --js-library ${ROOT_DIR}/emscripten/deps.js")
|
||||
endif()
|
||||
|
||||
if (NOT MINGW AND NOT MSVC AND NOT EMSCRIPTEN)
|
||||
|
||||
@@ -76,6 +76,13 @@
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
extern "C" {
|
||||
extern void EmscriptenSaveGame(bool isTrackDesign, bool isAutosave, bool saveAs, LoadSaveType type);
|
||||
extern void EmscriptenResetAutosave();
|
||||
}
|
||||
#endif
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
uint16_t gCurrentDeltaTime;
|
||||
@@ -455,8 +462,14 @@ void SaveGame()
|
||||
{
|
||||
if (!gFirstTimeSaving && !gIsAutosaveLoaded)
|
||||
{
|
||||
#ifndef __EMSCRIPTEN__
|
||||
const auto savePath = Path::WithExtension(gScenarioSavePath, ".park");
|
||||
SaveGameWithName(savePath);
|
||||
#else
|
||||
const auto savePath = Path::WithExtension("save", ".park");
|
||||
SaveGameWithName(savePath);
|
||||
EmscriptenSaveGame(false, false, false, LoadSaveType::park);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -512,6 +525,7 @@ void SaveGameAs()
|
||||
ContextOpenIntent(intent.get());
|
||||
}
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
static void LimitAutosaveCount(const size_t numberOfFilesToKeep, bool processLandscapeFolder)
|
||||
{
|
||||
size_t autosavesCount = 0;
|
||||
@@ -613,6 +627,14 @@ void GameAutosave()
|
||||
if (!ScenarioSave(gameState, path, saveFlags))
|
||||
Console::Error::WriteLine("Could not autosave the scenario. Is the save folder writeable?");
|
||||
}
|
||||
#else
|
||||
void GameAutosave()
|
||||
{
|
||||
const auto savePath = Path::WithExtension("save", ".park");
|
||||
SaveGameWithName(savePath);
|
||||
EmscriptenSaveGame(false, true, false, LoadSaveType::park);
|
||||
}
|
||||
#endif // __EMSCRIPTEN__
|
||||
|
||||
static void GameLoadOrQuitNoSavePromptCallback(ModalResult result, const utf8* path)
|
||||
{
|
||||
@@ -643,6 +665,9 @@ static void NewGameWindowCallback(const utf8* path)
|
||||
GetContext()->LoadParkFromFile(path, false, true);
|
||||
GameLoadScripts();
|
||||
GameNotifyMapChanged();
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EmscriptenResetAutosave();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -685,6 +710,9 @@ void GameLoadOrQuitNoSavePrompt()
|
||||
gFirstTimeSaving = true;
|
||||
GameNotifyMapChange();
|
||||
GameUnloadScripts();
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EmscriptenResetAutosave();
|
||||
#endif
|
||||
|
||||
auto* context = OpenRCT2::GetContext();
|
||||
context->SetActiveScene(context->GetTitleScene());
|
||||
|
||||
138
src/openrct2/platform/Platform.Emscripten.cpp
Normal file
138
src/openrct2/platform/Platform.Emscripten.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2025 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
|
||||
#include "Platform.h"
|
||||
|
||||
#include "../Diagnostic.h"
|
||||
#include "../GameState.h"
|
||||
#include "../core/Compression.h"
|
||||
#include "../core/File.h"
|
||||
#include "../core/Guard.hpp"
|
||||
#include "../core/MemoryStream.h"
|
||||
#include "../localisation/Language.h"
|
||||
#include "../park/ParkFile.h"
|
||||
|
||||
#include <emscripten.h>
|
||||
|
||||
extern "C" {
|
||||
extern char* GetLocaleCurrencyCode();
|
||||
}
|
||||
|
||||
namespace OpenRCT2::Platform
|
||||
{
|
||||
std::string GetFolderPath(SpecialFolder folder)
|
||||
{
|
||||
switch (folder)
|
||||
{
|
||||
case SpecialFolder::userCache:
|
||||
case SpecialFolder::userConfig:
|
||||
case SpecialFolder::userData:
|
||||
case SpecialFolder::userHome:
|
||||
return "/persistent";
|
||||
default:
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetDocsPath()
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string GetInstallPath()
|
||||
{
|
||||
return "/OpenRCT2";
|
||||
}
|
||||
|
||||
std::string GetCurrentExecutablePath()
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
u8string StrDecompToPrecomp(u8string_view input)
|
||||
{
|
||||
return u8string(input);
|
||||
}
|
||||
|
||||
bool HandleSpecialCommandLineArgument(const char* argument)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t GetLocaleLanguage()
|
||||
{
|
||||
auto locale = reinterpret_cast<char*>(EM_ASM_PTR({
|
||||
const locale = Intl.DateTimeFormat().resolvedOptions().locale;
|
||||
return stringToNewUTF8(locale);
|
||||
}));
|
||||
auto languageId = LanguageGetIDFromLocale(locale);
|
||||
free(locale);
|
||||
return languageId;
|
||||
}
|
||||
|
||||
CurrencyType GetLocaleCurrency()
|
||||
{
|
||||
auto localeCurrencyCode = GetLocaleCurrencyCode();
|
||||
auto currency = Platform::GetCurrencyValue(localeCurrencyCode);
|
||||
free(localeCurrencyCode);
|
||||
return currency;
|
||||
}
|
||||
|
||||
MeasurementFormat GetLocaleMeasurementFormat()
|
||||
{
|
||||
int isImperial = EM_ASM_INT({
|
||||
// There is no way to get this directly from javascript! Assume based off of user country
|
||||
const country = Intl.DateTimeFormat().resolvedOptions().locale.split("-").pop();
|
||||
return ([ "LR", "MM", "US" ]).includes(country) ? 1 : 0;
|
||||
});
|
||||
|
||||
return isImperial == 1 ? MeasurementFormat::Imperial : MeasurementFormat::Metric;
|
||||
}
|
||||
|
||||
std::string GetSteamPath()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
u8string GetRCT1SteamDir()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
u8string GetRCT2SteamDir()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
u8string GetRCTClassicSteamDir()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifndef DISABLE_TTF
|
||||
std::string GetFontPath(const TTFFontDescriptor& font)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<std::string_view> GetSearchablePathsRCT1()
|
||||
{
|
||||
return { "/RCT" };
|
||||
}
|
||||
|
||||
std::vector<std::string_view> GetSearchablePathsRCT2()
|
||||
{
|
||||
return { "/RCT" };
|
||||
}
|
||||
} // namespace OpenRCT2::Platform
|
||||
|
||||
#endif
|
||||
@@ -7,7 +7,7 @@
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#if defined(__unix__) && !defined(__ANDROID__) && !defined(__APPLE__)
|
||||
#if defined(__unix__) && !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
|
||||
|
||||
#include "../Diagnostic.h"
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace OpenRCT2::Platform
|
||||
{
|
||||
LOG_FATAL("failed to get process path");
|
||||
}
|
||||
#elif defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
|
||||
#elif defined(__OpenBSD__)
|
||||
// There is no way to get the path name of a running executable.
|
||||
// If you are not using the port or package, you may have to change this line!
|
||||
strlcpy(exePath, "/usr/local/bin/", sizeof(exePath));
|
||||
|
||||
Reference in New Issue
Block a user