mirror of
https://github.com/SpeedBreakerProject/speedbreaker.git
synced 2026-10-17 16:02:21 +02:00
Co-authored-by: Lydacious <81742991+lydacious@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
139 lines
4.2 KiB
C++
139 lines
4.2 KiB
C++
// SpeedBreaker runtime. GPL-3.0-or-later (see COPYING).
|
|
#pragma once
|
|
#include <cstdlib>
|
|
#include <filesystem>
|
|
#include <string>
|
|
#ifdef __APPLE__
|
|
#include <TargetConditionals.h>
|
|
#endif
|
|
|
|
#include "portable.h"
|
|
|
|
// Extracted disc contents (default.xex, NFS/, Movies/): where startup found
|
|
// or installed the game (install::FindGameInstall, SetGamePath); before
|
|
// that, NFSMW_GAME_DIR or the repo layout.
|
|
inline std::filesystem::path& GamePathStorage()
|
|
{
|
|
static std::filesystem::path path; // set once, before the game starts
|
|
return path;
|
|
}
|
|
|
|
inline void SetGamePath(std::filesystem::path path)
|
|
{
|
|
GamePathStorage() = std::move(path);
|
|
}
|
|
|
|
inline std::filesystem::path GetGamePath()
|
|
{
|
|
if (!GamePathStorage().empty())
|
|
return GamePathStorage();
|
|
if (const char* dir = std::getenv("NFSMW_GAME_DIR"))
|
|
return dir;
|
|
return "game/files";
|
|
}
|
|
|
|
// The per-user folders are named for the project: SpeedBreaker (macOS) or
|
|
// speedbreaker (Linux), nfsmw-recomp until 2026-10. MigrateUserFolders
|
|
// (user/paths.cpp, first thing at startup) renames an old folder; where that
|
|
// fails, the old one is used as it is.
|
|
#ifdef __APPLE__
|
|
inline constexpr const char* kUserFolderName = "SpeedBreaker";
|
|
#else
|
|
inline constexpr const char* kUserFolderName = "speedbreaker";
|
|
#endif
|
|
inline constexpr const char* kOldUserFolderName = "nfsmw-recomp";
|
|
|
|
// The folders' names in use (set before any other thread starts).
|
|
inline const char*& DataFolderName()
|
|
{
|
|
static const char* name = kUserFolderName;
|
|
return name;
|
|
}
|
|
|
|
inline const char*& CacheFolderName()
|
|
{
|
|
static const char* name = kUserFolderName;
|
|
return name;
|
|
}
|
|
|
|
// Where the per-user folders go (outside portable mode: user/portable.h).
|
|
// macOS: ~/Library/Application Support, ~/Library/Caches
|
|
// iOS: the same in the app's container; $XDG_DATA_HOME and
|
|
// $XDG_CACHE_HOME when set (test runs: iOS sets HOME itself)
|
|
// Linux: $XDG_DATA_HOME or ~/.local/share, $XDG_CACHE_HOME or ~/.cache
|
|
inline std::filesystem::path UserDataBase()
|
|
{
|
|
const char* home = std::getenv("HOME");
|
|
std::filesystem::path base = home ? home : ".";
|
|
#ifdef __APPLE__
|
|
#if TARGET_OS_IOS
|
|
if (const char* xdg = std::getenv("XDG_DATA_HOME"))
|
|
return xdg;
|
|
#endif
|
|
return base / "Library/Application Support";
|
|
#else
|
|
if (const char* xdg = std::getenv("XDG_DATA_HOME"))
|
|
return xdg;
|
|
return base / ".local/share";
|
|
#endif
|
|
}
|
|
|
|
inline std::filesystem::path CacheBase()
|
|
{
|
|
const char* home = std::getenv("HOME");
|
|
std::filesystem::path base = home ? home : ".";
|
|
#ifdef __APPLE__
|
|
#if TARGET_OS_IOS
|
|
if (const char* xdg = std::getenv("XDG_CACHE_HOME"))
|
|
return xdg;
|
|
#endif
|
|
return base / "Library/Caches";
|
|
#else
|
|
if (const char* xdg = std::getenv("XDG_CACHE_HOME"))
|
|
return xdg;
|
|
return base / ".cache";
|
|
#endif
|
|
}
|
|
|
|
// This computer's own data and cache folders, portable mode or not
|
|
// (install/portable_switch.h copies between them and SpeedBreaker's folder).
|
|
inline std::filesystem::path HomeUserPath()
|
|
{
|
|
return UserDataBase() / DataFolderName();
|
|
}
|
|
|
|
inline std::filesystem::path HomeCachePath()
|
|
{
|
|
return CacheBase() / CacheFolderName();
|
|
}
|
|
|
|
// Per-user data: saves, settings, logs and (by default) the installed game.
|
|
// In portable mode, the data folder in SpeedBreaker's own folder.
|
|
inline std::filesystem::path GetUserPath()
|
|
{
|
|
if (const portable::Layout& layout = portable::Current(); layout.Active())
|
|
return layout.data;
|
|
return HomeUserPath();
|
|
}
|
|
|
|
// Caches that can be deleted any time (compiled shaders, pipelines). In
|
|
// portable mode, the cache folder in SpeedBreaker's own folder.
|
|
inline std::filesystem::path GetCachePath()
|
|
{
|
|
if (const portable::Layout& layout = portable::Current(); layout.Active())
|
|
return layout.cache;
|
|
return HomeCachePath();
|
|
}
|
|
|
|
// Renames nfsmw-recomp folders to the current name, leaving the old name as
|
|
// a link to the new folder (for older builds and scripts). Call first thing
|
|
// in main (after portable::Detect: in portable mode it does nothing, since
|
|
// the home folder isn't SpeedBreaker's then); returns what it did, for the
|
|
// log once that is open.
|
|
std::string MigrateUserFolders();
|
|
|
|
inline std::filesystem::path GetSavePath(bool)
|
|
{
|
|
return GetUserPath() / "save";
|
|
}
|