Use platform-specific user directory to store content. Create a file named portable.txt next to xenia.exe to restore previous behavior.

This commit is contained in:
gibbed 2018-11-21 18:04:43 -06:00
parent eb55d68e1f
commit 1ba5dd5eb1
9 changed files with 89 additions and 9 deletions

View File

@ -44,6 +44,8 @@ DEFINE_string(hid, "any", "Input system. Use: [any, nop, winkey, xinput]");
DEFINE_string(target, "", "Specifies the target .xex or .iso to execute.");
DEFINE_bool(fullscreen, false, "Toggles fullscreen");
DEFINE_string(content_root, "", "Root path for content (save/etc) storage.");
DEFINE_bool(mount_scratch, false, "Enable scratch mount");
DEFINE_bool(mount_cache, false, "Enable cache mount");
@ -129,8 +131,35 @@ int xenia_main(const std::vector<std::wstring>& args) {
Profiler::Initialize();
Profiler::ThreadEnter("main");
// Figure out where content should go.
std::wstring content_root;
if (!FLAGS_content_root.empty()) {
content_root = xe::to_wstring(FLAGS_content_root);
} else {
auto base_path = xe::filesystem::GetExecutableFolder();
base_path = xe::to_absolute_path(base_path);
auto portable_path = xe::join_paths(base_path, L"portable.txt");
if (xe::filesystem::PathExists(portable_path)) {
content_root = xe::join_paths(base_path, L"content");
} else {
content_root = xe::filesystem::GetUserFolder();
#if defined(XE_PLATFORM_WIN32)
content_root = xe::join_paths(content_root, L"Xenia");
#elif defined(XE_PLATFORM_LINUX)
content_root = xe::join_paths(content_root, L".xenia");
#else
#warning Unhandled platform for content root.
content_root = xe::join_paths(content_root, L"Xenia");
#endif
content_root = xe::join_paths(content_root, L"content");
}
content_root = xe::to_absolute_path(content_root);
}
// Create the emulator but don't initialize so we can setup the window.
auto emulator = std::make_unique<Emulator>(L"");
auto emulator = std::make_unique<Emulator>(L"", content_root);
// Main emulator display window.
auto emulator_window = EmulatorWindow::Create(emulator.get());

View File

@ -20,6 +20,15 @@
namespace xe {
namespace filesystem {
// Get executable path.
std::wstring GetExecutablePath();
// Get executable folder.
std::wstring GetExecutableFolder();
// Get user folder.
std::wstring GetUserFolder();
// Canonicalizes a path, removing ..'s.
std::string CanonicalizePath(const std::string& original_path);

View File

@ -21,6 +21,21 @@
namespace xe {
namespace filesystem {
std::wstring GetExecutablePath() {
assert_always(); // IMPLEMENT ME.
return std::wstring();
}
std::wstring GetExecutableFolder() {
assert_always(); // IMPLEMENT ME.
return std::wstring();
}
std::wstring GetUserFolder() {
assert_always(); // IMPLEMENT ME.
return std::wstring();
}
bool PathExists(const std::wstring& path) {
struct stat st;
return stat(xe::to_string(path).c_str(), &st) == 0;

View File

@ -12,11 +12,33 @@
#include <string>
#include <shlobj.h>
#include "xenia/base/platform_win.h"
namespace xe {
namespace filesystem {
std::wstring GetExecutablePath() {
wchar_t* path;
auto error = _get_wpgmptr(&path);
return !error ? std::wstring(path) : std::wstring();
}
std::wstring GetExecutableFolder() {
auto path = GetExecutablePath();
return xe::find_base_path(path);
}
std::wstring GetUserFolder() {
wchar_t path[MAX_PATH];
if (!SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_MYDOCUMENTS, nullptr,
SHGFP_TYPE_CURRENT, path))) {
return std::wstring();
}
return std::wstring(path);
}
bool PathExists(const std::wstring& path) {
DWORD attrib = GetFileAttributes(path.c_str());
return attrib != INVALID_FILE_ATTRIBUTES;

View File

@ -48,8 +48,9 @@ DEFINE_double(time_scalar, 1.0,
namespace xe {
Emulator::Emulator(const std::wstring& command_line)
: command_line_(command_line) {}
Emulator::Emulator(const std::wstring& command_line,
const std::wstring& content_root)
: command_line_(command_line), content_root_(content_root) {}
Emulator::~Emulator() {
// Note that we delete things in the reverse order they were initialized.

View File

@ -47,12 +47,16 @@ namespace xe {
// This is responsible for initializing and managing all the various subsystems.
class Emulator {
public:
explicit Emulator(const std::wstring& command_line);
explicit Emulator(const std::wstring& command_line,
const std::wstring& content_root);
~Emulator();
// Full command line used when launching the process.
const std::wstring& command_line() const { return command_line_; }
// Folder content is stored in.
const std::wstring& content_root() const { return content_root_; }
// Title of the game in the default language.
const std::wstring& game_title() const { return game_title_; }
@ -154,6 +158,8 @@ class Emulator {
const std::string& module_path);
std::wstring command_line_;
std::wstring content_root_;
std::wstring game_title_;
ui::Window* display_window_;

View File

@ -103,7 +103,7 @@ int TraceDump::Main(const std::vector<std::wstring>& args) {
bool TraceDump::Setup() {
// Create the emulator but don't initialize so we can setup the window.
emulator_ = std::make_unique<Emulator>(L"");
emulator_ = std::make_unique<Emulator>(L"", L"");
X_STATUS result = emulator_->Setup(
nullptr, nullptr, [this]() { return CreateGraphicsSystem(); }, nullptr);
if (XFAILED(result)) {

View File

@ -122,7 +122,7 @@ bool TraceViewer::Setup() {
window_->Resize(1920, 1200);
// Create the emulator but don't initialize so we can setup the window.
emulator_ = std::make_unique<Emulator>(L"");
emulator_ = std::make_unique<Emulator>(L"", L"");
X_STATUS result =
emulator_->Setup(window_.get(), nullptr,
[this]() { return CreateGraphicsSystem(); }, nullptr);

View File

@ -31,8 +31,6 @@
DEFINE_bool(headless, false,
"Don't display any UI, using defaults for prompts as needed.");
DEFINE_string(content_root, "content",
"Root path for content (save/etc) storage.");
namespace xe {
namespace kernel {
@ -57,7 +55,7 @@ KernelState::KernelState(Emulator* emulator)
app_manager_ = std::make_unique<xam::AppManager>();
user_profile_ = std::make_unique<xam::UserProfile>();
auto content_root = xe::to_wstring(FLAGS_content_root);
auto content_root = emulator_->content_root();
content_root = xe::to_absolute_path(content_root);
content_manager_ = std::make_unique<xam::ContentManager>(this, content_root);