1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-18 04:23:20 +01:00

Refactor Steam path handling

This commit is contained in:
Gymnasiast
2025-12-13 13:50:55 +01:00
parent fcd16cb00a
commit 6db4ac56f2
8 changed files with 145 additions and 131 deletions

View File

@@ -716,13 +716,24 @@ namespace OpenRCT2::Config
}
}
auto steamPath = Platform::GetSteamPath();
if (!steamPath.empty())
auto steamPaths = Platform::GetSteamPaths();
if (steamPaths.isSteamPresent())
{
std::string location = Path::Combine(steamPath, Platform::GetRCT1SteamDir());
if (RCT1DataPresentAtLocation(location))
for (const auto& root : steamPaths.roots)
{
return location;
auto nativePath = Path::Combine(root, steamPaths.nativeFolder, Platform::kSteamRCT1Data.nativeFolder);
if (RCT1DataPresentAtLocation(nativePath))
{
return nativePath;
}
if (!steamPaths.downloadDepotFolder.empty())
{
auto downloadDepotPath = steamPaths.getDownloadDepotFolder(root, Platform::kSteamRCT1Data);
if (RCT1DataPresentAtLocation(downloadDepotPath))
{
return downloadDepotPath;
}
}
}
}
@@ -753,19 +764,31 @@ namespace OpenRCT2::Config
}
}
auto steamPath = Platform::GetSteamPath();
if (!steamPath.empty())
auto steamPaths = Platform::GetSteamPaths();
if (steamPaths.isSteamPresent())
{
std::string location = Path::Combine(steamPath, Platform::GetRCT2SteamDir());
if (Platform::OriginalGameDataExists(location))
const std::array<Platform::SteamGameData, 2> gamesToCheck = {
Platform::kSteamRCT2Data,
Platform::kSteamRCTCData,
};
for (const auto& root : steamPaths.roots)
{
return location;
}
std::string location2 = Path::Combine(steamPath, Platform::GetRCTClassicSteamDir());
if (Platform::OriginalGameDataExists(location2))
{
return location2;
for (const auto& game : gamesToCheck)
{
auto nativePath = Path::Combine(root, steamPaths.nativeFolder, game.nativeFolder);
if (Platform::OriginalGameDataExists(nativePath))
{
return nativePath;
}
if (!steamPaths.downloadDepotFolder.empty())
{
auto downloadDepotPath = steamPaths.getDownloadDepotFolder(root, game);
if (Platform::OriginalGameDataExists(downloadDepotPath))
{
return downloadDepotPath;
}
}
}
}
}

View File

@@ -148,22 +148,7 @@ namespace OpenRCT2::Platform
return isImperial == JNI_TRUE ? MeasurementFormat::Imperial : MeasurementFormat::Metric;
}
std::string GetSteamPath()
{
return {};
}
u8string GetRCT1SteamDir()
{
return {};
}
u8string GetRCT2SteamDir()
{
return {};
}
u8string GetRCTClassicSteamDir()
SteamPaths GetSteamPaths()
{
return {};
}

View File

@@ -213,4 +213,15 @@ namespace OpenRCT2::Platform
return false;
}
bool SteamPaths::isSteamPresent() const
{
return !roots.empty();
}
u8string SteamPaths::getDownloadDepotFolder(u8string_view steamroot, const SteamGameData& data) const
{
return Path::Combine(
steamroot, downloadDepotFolder, "app_" + std::to_string(data.appId), "depot_" + std::to_string(data.depotId));
}
} // namespace OpenRCT2::Platform

View File

@@ -97,22 +97,7 @@ namespace OpenRCT2::Platform
return isImperial == 1 ? MeasurementFormat::Imperial : MeasurementFormat::Metric;
}
std::string GetSteamPath()
{
return {};
}
u8string GetRCT1SteamDir()
{
return {};
}
u8string GetRCT2SteamDir()
{
return {};
}
u8string GetRCTClassicSteamDir()
SteamPaths GetSteamPaths()
{
return {};
}

View File

@@ -320,65 +320,52 @@ namespace OpenRCT2::Platform
return MeasurementFormat::Metric;
}
std::string GetSteamPath()
SteamPaths GetSteamPaths()
{
SteamPaths ret = {};
ret.nativeFolder = "steamapps/common";
ret.downloadDepotFolder = "ubuntu12_32/steamapps/content";
ret.manifests = "steamapps";
const char* steamRoot = getenv("STEAMROOT");
if (steamRoot != nullptr)
{
return Path::Combine(steamRoot, u8"ubuntu12_32/steamapps/content");
ret.roots.emplace_back(steamRoot);
}
const char* localSharePath = getenv("XDG_DATA_HOME");
if (localSharePath != nullptr)
{
auto steamPath = Path::Combine(localSharePath, u8"Steam/ubuntu12_32/steamapps/content");
if (Path::DirectoryExists(steamPath))
auto xdgDataHomeSteamPath = Path::Combine(localSharePath, u8"Steam");
if (Path::DirectoryExists(xdgDataHomeSteamPath))
{
return steamPath;
ret.roots.emplace_back(xdgDataHomeSteamPath);
}
}
const char* homeDir = getpwuid(getuid())->pw_dir;
if (homeDir == nullptr)
if (homeDir != nullptr)
{
return {};
auto localShareSteamPath = Path::Combine(homeDir, u8".local/share/Steam");
if (Path::DirectoryExists(localShareSteamPath))
{
ret.roots.emplace_back(localShareSteamPath);
}
auto oldSteamPath = Path::Combine(homeDir, u8".steam/steam");
if (Path::DirectoryExists(oldSteamPath))
{
ret.roots.emplace_back(oldSteamPath);
}
auto snapLocalShareSteamPath = Path::Combine(homeDir, u8"snap/steam/common/.local/share/Steam");
if (Path::DirectoryExists(snapLocalShareSteamPath))
{
ret.roots.emplace_back(snapLocalShareSteamPath);
}
}
// Prefer new path for Steam, which is the default when using with Proton
auto steamPath = Path::Combine(homeDir, u8".local/share/Steam/steamapps/common");
if (Path::DirectoryExists(steamPath))
{
return steamPath;
}
// Fallback paths
steamPath = Path::Combine(homeDir, u8".local/share/Steam/ubuntu12_32/steamapps/content");
if (Path::DirectoryExists(steamPath))
{
return steamPath;
}
steamPath = Path::Combine(homeDir, u8".steam/steam/ubuntu12_32/steamapps/content");
if (Path::DirectoryExists(steamPath))
{
return steamPath;
}
return {};
}
u8string GetRCT1SteamDir()
{
return u8"Rollercoaster Tycoon Deluxe";
}
u8string GetRCT2SteamDir()
{
return u8"Rollercoaster Tycoon 2";
}
u8string GetRCTClassicSteamDir()
{
return u8"RollerCoaster Tycoon Classic";
return ret;
}
std::vector<std::string_view> GetSearchablePathsRCT1()

View File

@@ -737,7 +737,7 @@ namespace OpenRCT2::Platform
return isElevated;
}
std::string GetSteamPath()
SteamPaths GetSteamPaths()
{
wchar_t* wSteamPath;
HKEY hKey;
@@ -759,12 +759,18 @@ namespace OpenRCT2::Platform
result = RegQueryValueExW(hKey, L"SteamPath", nullptr, &type, reinterpret_cast<LPBYTE>(wSteamPath), &size);
if (result == ERROR_SUCCESS)
{
auto utf8SteamPath = String::toUtf8(wSteamPath);
outPath = Path::Combine(utf8SteamPath, u8"steamapps", u8"common");
outPath = String::toUtf8(wSteamPath);
}
free(wSteamPath);
RegCloseKey(hKey);
return outPath;
SteamPaths ret = {};
ret.roots.emplace_back(outPath);
ret.nativeFolder = "steamapps/common";
ret.downloadDepotFolder = "steamapps/content";
ret.manifests = "steamapps";
return ret;
}
std::string GetFontPath(const TTFFontDescriptor& font)
@@ -796,21 +802,6 @@ namespace OpenRCT2::Platform
return GetLogicalDrives();
}
u8string GetRCT1SteamDir()
{
return u8"Rollercoaster Tycoon Deluxe";
}
u8string GetRCT2SteamDir()
{
return u8"Rollercoaster Tycoon 2";
}
u8string GetRCTClassicSteamDir()
{
return u8"RollerCoaster Tycoon Classic";
}
time_t FileGetModifiedTime(u8string_view path)
{
WIN32_FILE_ATTRIBUTE_DATA data{};

View File

@@ -16,6 +16,7 @@
#include <bit>
#include <ctime>
#include <optional>
#include <sfl/static_vector.hpp>
#include <vector>
#ifdef _WIN32
@@ -60,6 +61,49 @@ struct TTFFontDescriptor;
namespace OpenRCT2::Platform
{
struct SteamGameData
{
u8string nativeFolder;
uint32_t appId;
uint32_t depotId;
};
const SteamGameData kSteamRCT1Data = {
.nativeFolder = u8"Rollercoaster Tycoon Deluxe",
.appId = 285310,
.depotId = 285311,
};
const SteamGameData kSteamRCT2Data = {
.nativeFolder = u8"Rollercoaster Tycoon 2",
.appId = 285330,
.depotId = 285331,
};
const SteamGameData kSteamRCTCData = {
.nativeFolder = u8"RollerCoaster Tycoon Classic",
.appId = 683900,
.depotId = 683901,
};
struct SteamPaths
{
sfl::static_vector<u8string, 5> roots{};
/**
* Used by native applications and applications installed through Steam Play.
*/
u8string nativeFolder{};
/**
* Used by applications downloaded through download_depot. Most likely used on macOS and Linux,
* though technically possible on Windows too.
*/
u8string downloadDepotFolder{};
/**
* Directory that contains the manifests to trigger a download.
*/
u8string manifests{};
bool isSteamPresent() const;
u8string getDownloadDepotFolder(u8string_view steamroot, const SteamGameData& data) const;
};
constexpr u8string_view kRCTClassicWindowsDataFolder = u8"Assets";
// clang-format off
constexpr u8string_view kRCTClassicMacOSDataFolder =
@@ -101,7 +145,7 @@ namespace OpenRCT2::Platform
std::string GetUsername();
std::string GetSteamPath();
SteamPaths GetSteamPaths();
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__) || defined(__NetBSD__)
std::string GetEnvironmentPath(const char* name);
std::string GetHomePath();
@@ -138,9 +182,6 @@ namespace OpenRCT2::Platform
bool LockSingleInstance();
u8string GetRCT1SteamDir();
u8string GetRCT2SteamDir();
u8string GetRCTClassicSteamDir();
datetime64 GetDatetimeNowUTC();
uint32_t GetTicks();

View File

@@ -235,7 +235,7 @@ namespace OpenRCT2::Platform
}
}
std::string GetSteamPath()
SteamPaths GetSteamPaths()
{
const char* homeDir = getpwuid(getuid())->pw_dir;
if (homeDir == nullptr)
@@ -244,27 +244,18 @@ namespace OpenRCT2::Platform
}
auto steamPath = Path::Combine(homeDir, "Library/Application Support/Steam");
if (Path::DirectoryExists(steamPath))
if (!Path::DirectoryExists(steamPath))
{
return steamPath;
return {};
}
return {};
}
SteamPaths ret = {};
ret.roots.emplace_back(steamPath);
ret.nativeFolder = "steamapps/common";
ret.downloadDepotFolder = "Steam.AppBundle/Steam/Contents/MacOS/steamapps/content";
ret.manifests = "steamapps";
u8string GetRCT1SteamDir()
{
return u8"Steam.AppBundle/Steam/Contents/MacOS/steamapps/content/app_285310/depot_285311";
}
u8string GetRCT2SteamDir()
{
return u8"Steam.AppBundle/Steam/Contents/MacOS/steamapps/content/app_285330/depot_285331";
}
u8string GetRCTClassicSteamDir()
{
return u8"steamapps/common/RollerCoaster Tycoon Classic";
return ret;
}
std::string GetFontPath(const TTFFontDescriptor& font)