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:
parent
eb55d68e1f
commit
1ba5dd5eb1
|
@ -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_string(target, "", "Specifies the target .xex or .iso to execute.");
|
||||||
DEFINE_bool(fullscreen, false, "Toggles fullscreen");
|
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_scratch, false, "Enable scratch mount");
|
||||||
DEFINE_bool(mount_cache, false, "Enable cache 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::Initialize();
|
||||||
Profiler::ThreadEnter("main");
|
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.
|
// 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.
|
// Main emulator display window.
|
||||||
auto emulator_window = EmulatorWindow::Create(emulator.get());
|
auto emulator_window = EmulatorWindow::Create(emulator.get());
|
||||||
|
|
|
@ -20,6 +20,15 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace filesystem {
|
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.
|
// Canonicalizes a path, removing ..'s.
|
||||||
std::string CanonicalizePath(const std::string& original_path);
|
std::string CanonicalizePath(const std::string& original_path);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,21 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace filesystem {
|
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) {
|
bool PathExists(const std::wstring& path) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
return stat(xe::to_string(path).c_str(), &st) == 0;
|
return stat(xe::to_string(path).c_str(), &st) == 0;
|
||||||
|
|
|
@ -12,11 +12,33 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <shlobj.h>
|
||||||
|
|
||||||
#include "xenia/base/platform_win.h"
|
#include "xenia/base/platform_win.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace filesystem {
|
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) {
|
bool PathExists(const std::wstring& path) {
|
||||||
DWORD attrib = GetFileAttributes(path.c_str());
|
DWORD attrib = GetFileAttributes(path.c_str());
|
||||||
return attrib != INVALID_FILE_ATTRIBUTES;
|
return attrib != INVALID_FILE_ATTRIBUTES;
|
||||||
|
|
|
@ -48,8 +48,9 @@ DEFINE_double(time_scalar, 1.0,
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
Emulator::Emulator(const std::wstring& command_line)
|
Emulator::Emulator(const std::wstring& command_line,
|
||||||
: command_line_(command_line) {}
|
const std::wstring& content_root)
|
||||||
|
: command_line_(command_line), content_root_(content_root) {}
|
||||||
|
|
||||||
Emulator::~Emulator() {
|
Emulator::~Emulator() {
|
||||||
// Note that we delete things in the reverse order they were initialized.
|
// Note that we delete things in the reverse order they were initialized.
|
||||||
|
|
|
@ -47,12 +47,16 @@ namespace xe {
|
||||||
// This is responsible for initializing and managing all the various subsystems.
|
// This is responsible for initializing and managing all the various subsystems.
|
||||||
class Emulator {
|
class Emulator {
|
||||||
public:
|
public:
|
||||||
explicit Emulator(const std::wstring& command_line);
|
explicit Emulator(const std::wstring& command_line,
|
||||||
|
const std::wstring& content_root);
|
||||||
~Emulator();
|
~Emulator();
|
||||||
|
|
||||||
// Full command line used when launching the process.
|
// Full command line used when launching the process.
|
||||||
const std::wstring& command_line() const { return command_line_; }
|
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.
|
// Title of the game in the default language.
|
||||||
const std::wstring& game_title() const { return game_title_; }
|
const std::wstring& game_title() const { return game_title_; }
|
||||||
|
|
||||||
|
@ -154,6 +158,8 @@ class Emulator {
|
||||||
const std::string& module_path);
|
const std::string& module_path);
|
||||||
|
|
||||||
std::wstring command_line_;
|
std::wstring command_line_;
|
||||||
|
std::wstring content_root_;
|
||||||
|
|
||||||
std::wstring game_title_;
|
std::wstring game_title_;
|
||||||
|
|
||||||
ui::Window* display_window_;
|
ui::Window* display_window_;
|
||||||
|
|
|
@ -103,7 +103,7 @@ int TraceDump::Main(const std::vector<std::wstring>& args) {
|
||||||
|
|
||||||
bool TraceDump::Setup() {
|
bool TraceDump::Setup() {
|
||||||
// Create the emulator but don't initialize so we can setup the window.
|
// 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(
|
X_STATUS result = emulator_->Setup(
|
||||||
nullptr, nullptr, [this]() { return CreateGraphicsSystem(); }, nullptr);
|
nullptr, nullptr, [this]() { return CreateGraphicsSystem(); }, nullptr);
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
|
|
|
@ -122,7 +122,7 @@ bool TraceViewer::Setup() {
|
||||||
window_->Resize(1920, 1200);
|
window_->Resize(1920, 1200);
|
||||||
|
|
||||||
// Create the emulator but don't initialize so we can setup the window.
|
// 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 =
|
X_STATUS result =
|
||||||
emulator_->Setup(window_.get(), nullptr,
|
emulator_->Setup(window_.get(), nullptr,
|
||||||
[this]() { return CreateGraphicsSystem(); }, nullptr);
|
[this]() { return CreateGraphicsSystem(); }, nullptr);
|
||||||
|
|
|
@ -31,8 +31,6 @@
|
||||||
|
|
||||||
DEFINE_bool(headless, false,
|
DEFINE_bool(headless, false,
|
||||||
"Don't display any UI, using defaults for prompts as needed.");
|
"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 xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
@ -57,7 +55,7 @@ KernelState::KernelState(Emulator* emulator)
|
||||||
app_manager_ = std::make_unique<xam::AppManager>();
|
app_manager_ = std::make_unique<xam::AppManager>();
|
||||||
user_profile_ = std::make_unique<xam::UserProfile>();
|
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_root = xe::to_absolute_path(content_root);
|
||||||
content_manager_ = std::make_unique<xam::ContentManager>(this, content_root);
|
content_manager_ = std::make_unique<xam::ContentManager>(this, content_root);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue