Browse Source

Initial mod import tests

Signed-off-by: crueter <crueter@eden-emu.dev>
pull/3472/head
crueter 6 days ago
parent
commit
f222c28c7c
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 3
      src/frontend_common/CMakeLists.txt
  2. 66
      src/frontend_common/mod_manager.cpp
  3. 12
      src/frontend_common/mod_manager.h
  4. 6
      src/qt_common/CMakeLists.txt
  5. 25
      src/qt_common/abstract/frontend.cpp
  6. 6
      src/qt_common/abstract/frontend.h
  7. 84
      src/qt_common/util/mod.cpp
  8. 12
      src/qt_common/util/mod.h
  9. 2
      src/yuzu/main_window.cpp

3
src/frontend_common/CMakeLists.txt

@ -13,7 +13,8 @@ add_library(frontend_common STATIC
data_manager.h data_manager.cpp
play_time_manager.cpp
play_time_manager.h
settings_generator.h settings_generator.cpp)
settings_generator.h settings_generator.cpp
mod_manager.h mod_manager.cpp)
if (ENABLE_UPDATE_CHECKER)
target_link_libraries(frontend_common PRIVATE httplib::httplib)

66
src/frontend_common/mod_manager.cpp

@ -0,0 +1,66 @@
#include <algorithm>
#include <filesystem>
#include <iostream>
#include <fmt/format.h>
#include "common/fs/fs.h"
#include "common/fs/fs_types.h"
#include "common/logging/backend.h"
#include "frontend_common/data_manager.h"
#include "mod_manager.h"
namespace FrontendCommon {
// TODO: Handle cases where the folder appears to contain multiple mods.
std::optional<std::filesystem::path> GetModFolder(const std::string& root) {
std::filesystem::path path;
bool found;
auto callback = [&path, &found](const std::filesystem::directory_entry& entry) -> bool {
const auto name = entry.path().filename().string();
static constexpr const std::array<std::string, 5> valid_names = {"exefs",
"romfs"
"romfs_ext",
"cheats", "romfslite"};
if (std::ranges::find(valid_names, name) != valid_names.end()) {
path = entry.path().parent_path();
found = true;
}
return true;
};
Common::FS::IterateDirEntriesRecursively(root, callback, Common::FS::DirEntryFilter::Directory);
if (found)
return path;
return std::nullopt;
}
bool InstallMod(const std::filesystem::path& path, const u64 program_id, const bool copy) {
const auto program_id_string = fmt::format("{:016X}", program_id);
const auto mod_name = path.filename();
const auto mod_dir =
DataManager::GetDataDir(DataManager::DataDir::Mods) / program_id_string / mod_name;
// pre-emptively remove any existing mod here
std::filesystem::remove_all(mod_dir);
// now copy
try {
if (copy)
std::filesystem::copy(path, mod_dir, std::filesystem::copy_options::recursive);
else
std::filesystem::rename(path, mod_dir);
} catch (std::exception& e) {
LOG_ERROR(Frontend, "Mod install failed with message {}", e.what());
return false;
}
LOG_INFO(Frontend, "Copied mod from {} to {}", path.string(), mod_dir.string());
return true;
}
} // namespace FrontendCommon

12
src/frontend_common/mod_manager.h

@ -0,0 +1,12 @@
#pragma once
#include <filesystem>
#include <optional>
#include "common/common_types.h"
namespace FrontendCommon {
std::optional<std::filesystem::path> GetModFolder(const std::string& root);
bool InstallMod(const std::filesystem::path &path, const u64 program_id, const bool copy = true);
}

6
src/qt_common/CMakeLists.txt

@ -22,6 +22,8 @@ add_library(qt_common STATIC
util/rom.h util/rom.cpp
util/applet.h util/applet.cpp
util/compress.h util/compress.cpp
util/fs.h util/fs.cpp
util/mod.h util/mod.cpp
abstract/frontend.h abstract/frontend.cpp
abstract/qt_progress_dialog.h abstract/qt_progress_dialog.cpp
@ -29,9 +31,7 @@ add_library(qt_common STATIC
qt_string_lookup.h
qt_compat.h
discord/discord.h
util/fs.h util/fs.cpp
)
discord/discord.h)
if (UNIX)
target_sources(qt_common PRIVATE gui_settings.cpp gui_settings.h)

25
src/qt_common/abstract/frontend.cpp

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <QLineEdit>
#include "frontend.h"
#include "qt_common/qt_common.h"
@ -8,6 +9,9 @@
#include <QFileDialog>
#endif
#include <QAbstractButton>
#include <QInputDialog>
namespace QtCommon::Frontend {
StandardButton ShowMessage(
@ -50,4 +54,25 @@ const QString GetExistingDirectory(const QString& caption, const QString& dir,
#endif
}
int Choice(const QString& title, const QString& caption, const QStringList& options) {
QMessageBox box(rootObject);
box.setText(caption);
box.setWindowTitle(title);
for (const QString &opt : options) {
box.addButton(opt, QMessageBox::AcceptRole);
}
box.addButton(QMessageBox::Cancel);
box.exec();
auto button = box.clickedButton();
return options.indexOf(button->text());
}
const QString GetTextInput(const QString& title, const QString& caption,
const QString& defaultText) {
return QInputDialog::getText(rootObject, title, caption, QLineEdit::Normal, defaultText);
}
} // namespace QtCommon::Frontend

6
src/qt_common/abstract/frontend.h

@ -139,5 +139,11 @@ const QString GetExistingDirectory(const QString &caption = QString(),
const QString &dir = QString(),
Options options = Option::ShowDirsOnly);
int Choice(const QString& title = QString(), const QString& caption = QString(),
const QStringList& options = {});
const QString GetTextInput(const QString& title = QString(), const QString& caption = QString(),
const QString& defaultText = QString());
} // namespace QtCommon::Frontend
#endif // FRONTEND_H

84
src/qt_common/util/mod.cpp

@ -0,0 +1,84 @@
#include <filesystem>
#include "frontend_common/mod_manager.h"
#include "mod.h"
#include "qt_common/abstract/frontend.h"
namespace QtCommon::Mod {
QString GetModFolder(const QString& root, const QString& fallbackName) {
namespace fs = std::filesystem;
const auto std_root = root.toStdString();
auto std_path = FrontendCommon::GetModFolder(std_root);
QString default_name;
if (std_path)
default_name = QString::fromStdString(std_path->filename());
else if (fallbackName.isEmpty())
default_name = root.split(QLatin1Char('/')).last();
else
default_name = fallbackName;
QString name = QtCommon::Frontend::GetTextInput(
tr("Mod Name"), tr("What should this mod be called?"), default_name);
// if std_path is empty, frontend_common could not determine mod type and/or name.
// so we have to prompt the user and set up the structure ourselves
if (!std_path) {
// TODO: Carboxyl impl.
const QStringList choices = {
tr("RomFS"),
tr("ExeFS/Patch"),
tr("Cheat"),
};
int choice = QtCommon::Frontend::Choice(
tr("Mod Type"),
tr("Could not detect mod type automatically. Please manually "
"specify the type of mod you downloaded.\n\nMost mods are RomFS mods, but patches "
"(.pchtxt) are typically ExeFS mods."),
choices);
std::string to_make;
switch (choice) {
case 0:
to_make = "romfs";
break;
case 1:
to_make = "exefs";
break;
case 2:
to_make = "cheats";
break;
default:
return QString();
}
// now make a temp directory...
const auto mod_dir = fs::temp_directory_path() / "eden" / "mod" / name.toStdString();
const auto tmp = mod_dir / to_make;
fs::remove_all(mod_dir);
if (!fs::create_directories(tmp))
return QString();
std_path = mod_dir;
// ... and copy everything from the root to the temp dir
for (const auto& entry : fs::directory_iterator(root.toStdString())) {
const auto target = tmp / entry.path().filename();
fs::copy(entry.path(), target,
fs::copy_options::recursive | fs::copy_options::overwrite_existing);
}
}
return QString::fromStdString(std_path->string());
}
bool InstallMod(const QString& path, const QString& fallbackName, const u64 program_id,
const bool copy) {
const auto target = GetModFolder(path, fallbackName);
return FrontendCommon::InstallMod(target.toStdString(), program_id, copy);
}
} // namespace QtCommon::Mod

12
src/qt_common/util/mod.h

@ -0,0 +1,12 @@
#pragma once
#include <QString>
#include "common/common_types.h"
namespace QtCommon::Mod {
QString GetModFolder(const QString &root, const QString &fallbackName);
bool InstallMod(const QString &path, const QString &fallbackName, const u64 program_id, const bool copy);
}

2
src/yuzu/main_window.cpp

@ -3,6 +3,7 @@
// Qt on macOS doesn't define VMA shit
#include <boost/algorithm/string/split.hpp>
#include "frontend_common/mod_manager.h"
#include "frontend_common/settings_generator.h"
#include "qt_common/qt_string_lookup.h"
#if defined(QT_STATICPLUGIN) && !defined(__APPLE__)
@ -85,6 +86,7 @@
#include "qt_common/util/meta.h"
#include "qt_common/util/content.h"
#include "qt_common/util/fs.h"
#include "qt_common/util/mod.h"
// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
// defines.

Loading…
Cancel
Save