1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-25 00:37:24 +02:00

Merge pull request #5108 from IvanSavenko/preset_import

[1.6.1?] Mod preset import/export
This commit is contained in:
Ivan Savenko
2024-12-21 15:57:33 +02:00
committed by GitHub
8 changed files with 165 additions and 15 deletions

View File

@ -857,6 +857,12 @@ void CModListView::installMods(QStringList archives)
modNames.push_back(modName); modNames.push_back(modName);
} }
if (!activatingPreset.isEmpty())
{
modStateModel->activatePreset(activatingPreset);
activatingPreset.clear();
}
// uninstall old version of mod, if installed // uninstall old version of mod, if installed
for(QString mod : modNames) for(QString mod : modNames)
{ {
@ -1147,3 +1153,25 @@ QString CModListView::getActivePreset() const
{ {
return modStateModel->getActivePreset(); return modStateModel->getActivePreset();
} }
JsonNode CModListView::exportCurrentPreset() const
{
return modStateModel->exportCurrentPreset();
}
void CModListView::importPreset(const JsonNode & data)
{
const auto & [presetName, modList] = modStateModel->importPreset(data);
if (modList.empty())
{
modStateModel->activatePreset(presetName);
modStateModel->reloadLocalState();
}
else
{
activatingPreset = presetName;
for (const auto & modID : modList)
doInstallMod(modID);
}
}

View File

@ -37,6 +37,7 @@ class CModListView : public QWidget
CModFilterModel * filterModel; CModFilterModel * filterModel;
CDownloadManager * dlManager; CDownloadManager * dlManager;
JsonNode accumulatedRepositoryData; JsonNode accumulatedRepositoryData;
QString activatingPreset;
QStringList enqueuedModDownloads; QStringList enqueuedModDownloads;
@ -97,17 +98,16 @@ public:
QStringList getUpdateableMods(); QStringList getUpdateableMods();
void createNewPreset(const QString & presetName); void createNewPreset(const QString & presetName);
void deletePreset(const QString & presetName); void deletePreset(const QString & presetName);
void activatePreset(const QString & presetName); void activatePreset(const QString & presetName);
void renamePreset(const QString & oldPresetName, const QString & newPresetName); void renamePreset(const QString & oldPresetName, const QString & newPresetName);
QStringList getAllPresets() const; QStringList getAllPresets() const;
QString getActivePreset() const; QString getActivePreset() const;
JsonNode exportCurrentPreset() const;
void importPreset(const JsonNode & data);
/// returns true if mod is currently enabled /// returns true if mod is currently enabled
bool isModEnabled(const QString & modName); bool isModEnabled(const QString & modName);

View File

@ -157,3 +157,16 @@ QString ModStateModel::getActivePreset() const
{ {
return QString::fromStdString(modManager->getActivePreset()); return QString::fromStdString(modManager->getActivePreset());
} }
JsonNode ModStateModel::exportCurrentPreset() const
{
return modManager->exportCurrentPreset();
}
std::tuple<QString, QStringList> ModStateModel::importPreset(const JsonNode & data)
{
std::tuple<QString, QStringList> result;
const auto & [presetName, modList] = modManager->importPreset(data);
return {QString::fromStdString(presetName), stringListStdToQt(modList)};
}

View File

@ -57,4 +57,7 @@ public:
QStringList getAllPresets() const; QStringList getAllPresets() const;
QString getActivePreset() const; QString getActivePreset() const;
JsonNode exportCurrentPreset() const;
std::tuple<QString, QStringList> importPreset(const JsonNode & data);
}; };

View File

@ -44,12 +44,41 @@ StartGameTab::StartGameTab(QWidget * parent)
refreshState(); refreshState();
ui->buttonGameResume->setVisible(false); // TODO: implement ui->buttonGameResume->setVisible(false); // TODO: implement
ui->buttonPresetExport->setVisible(false); // TODO: implement
ui->buttonPresetImport->setVisible(false); // TODO: implement
#ifndef ENABLE_EDITOR #ifndef ENABLE_EDITOR
ui->buttonGameEditor->hide(); ui->buttonGameEditor->hide();
#endif #endif
auto clipboard = QGuiApplication::clipboard();
connect(clipboard, SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged()));
}
void StartGameTab::clipboardDataChanged()
{
ui->buttonPresetExport->setIcon(QIcon{});// reset icon, if any
auto clipboard = QGuiApplication::clipboard();
QString clipboardText = clipboard->text().trimmed();
if (clipboardText.isEmpty())
{
ui->buttonPresetImport->setEnabled(false);
}
else
{
// this *may* be json, try parsing it
if (clipboardText.startsWith('{'))
{
QByteArray presetBytes(clipboardText.toUtf8());
const JsonNode presetJson(reinterpret_cast<const std::byte*>(presetBytes.data()), presetBytes.size(), "preset in clipboard");
bool presetValid = !presetJson["name"].String().empty() && !presetJson["mods"].Vector().empty();
ui->buttonPresetImport->setEnabled(presetValid);
}
else
ui->buttonPresetImport->setEnabled(false);
}
} }
StartGameTab::~StartGameTab() StartGameTab::~StartGameTab()
@ -72,6 +101,8 @@ void StartGameTab::refreshState()
refreshTranslation(getMainWindow()->getTranslationStatus()); refreshTranslation(getMainWindow()->getTranslationStatus());
refreshPresets(); refreshPresets();
refreshMods(); refreshMods();
clipboardDataChanged();
} }
void StartGameTab::refreshPresets() void StartGameTab::refreshPresets()
@ -363,12 +394,22 @@ void StartGameTab::on_buttonMissingCampaignsHelp_clicked()
void StartGameTab::on_buttonPresetExport_clicked() void StartGameTab::on_buttonPresetExport_clicked()
{ {
// TODO JsonNode presetJson = getMainWindow()->getModView()->exportCurrentPreset();
QString presetString = QString::fromStdString(presetJson.toCompactString());
QGuiApplication::clipboard()->setText(presetString);
ui->buttonPresetExport->setIcon(QIcon{":/icons/mod-enabled.png"});
} }
void StartGameTab::on_buttonPresetImport_clicked() void StartGameTab::on_buttonPresetImport_clicked()
{ {
// TODO QString presetString = QGuiApplication::clipboard()->text();
QByteArray presetBytes(presetString.toUtf8());
JsonNode presetJson(reinterpret_cast<const std::byte*>(presetBytes.data()), presetBytes.size(), "imported preset");
getMainWindow()->getModView()->importPreset(presetJson);
getMainWindow()->switchToModsTab();
refreshPresets();
} }
void StartGameTab::on_buttonPresetNew_clicked() void StartGameTab::on_buttonPresetNew_clicked()

View File

@ -65,19 +65,14 @@ private slots:
void on_buttonMissingVideoHelp_clicked(); void on_buttonMissingVideoHelp_clicked();
void on_buttonMissingFilesHelp_clicked(); void on_buttonMissingFilesHelp_clicked();
void on_buttonMissingCampaignsHelp_clicked(); void on_buttonMissingCampaignsHelp_clicked();
void on_buttonPresetExport_clicked(); void on_buttonPresetExport_clicked();
void on_buttonPresetImport_clicked(); void on_buttonPresetImport_clicked();
void on_buttonPresetNew_clicked(); void on_buttonPresetNew_clicked();
void on_buttonPresetDelete_clicked(); void on_buttonPresetDelete_clicked();
void on_comboBoxModPresets_currentTextChanged(const QString &arg1); void on_comboBoxModPresets_currentTextChanged(const QString &arg1);
void on_buttonPresetRename_clicked(); void on_buttonPresetRename_clicked();
void clipboardDataChanged();
private: private:
Ui::StartGameTab * ui; Ui::StartGameTab * ui;
}; };

View File

@ -207,7 +207,12 @@ const JsonNode & ModsPresetState::getActivePresetConfig() const
TModList ModsPresetState::getActiveRootMods() const TModList ModsPresetState::getActiveRootMods() const
{ {
const JsonNode & modsToActivateJson = getActivePresetConfig()["mods"]; return getRootMods(getActivePreset());
}
TModList ModsPresetState::getRootMods(const std::string & presetName) const
{
const JsonNode & modsToActivateJson = modConfig["presets"][presetName]["mods"];
auto modsToActivate = modsToActivateJson.convertTo<std::vector<TModID>>(); auto modsToActivate = modsToActivateJson.convertTo<std::vector<TModID>>();
if (!vstd::contains(modsToActivate, ModScope::scopeBuiltin())) if (!vstd::contains(modsToActivate, ModScope::scopeBuiltin()))
modsToActivate.push_back(ModScope::scopeBuiltin()); modsToActivate.push_back(ModScope::scopeBuiltin());
@ -385,6 +390,33 @@ std::string ModsPresetState::getActivePreset() const
return modConfig["activePreset"].String(); return modConfig["activePreset"].String();
} }
JsonNode ModsPresetState::exportCurrentPreset() const
{
JsonNode data = getActivePresetConfig();
std::string presetName = getActivePreset();
data["name"] = JsonNode(presetName);
vstd::erase_if(data["settings"].Struct(), [&](const auto & pair){
return !vstd::contains(data["mods"].Vector(), JsonNode(pair.first));
});
return data;
}
std::string ModsPresetState::importPreset(const JsonNode & newConfig)
{
std::string importedPresetName = newConfig["name"].String();
if (importedPresetName.empty())
throw std::runtime_error("Attempt to import invalid preset");
modConfig["presets"][importedPresetName] = newConfig;
modConfig["presets"][importedPresetName].Struct().erase("name");
return importedPresetName;
}
ModsStorage::ModsStorage(const std::vector<TModID> & modsToLoad, const JsonNode & repositoryList) ModsStorage::ModsStorage(const std::vector<TModID> & modsToLoad, const JsonNode & repositoryList)
{ {
JsonNode coreModConfig(JsonPath::builtin("config/gameConfig.json")); JsonNode coreModConfig(JsonPath::builtin("config/gameConfig.json"));
@ -796,4 +828,28 @@ std::string ModManager::getActivePreset() const
return modsPreset->getActivePreset(); return modsPreset->getActivePreset();
} }
JsonNode ModManager::exportCurrentPreset() const
{
return modsPreset->exportCurrentPreset();
}
std::tuple<std::string, TModList> ModManager::importPreset(const JsonNode & data)
{
std::string presetName = modsPreset->importPreset(data);
TModList requiredMods = modsPreset->getRootMods(presetName);
TModList installedMods = modsState->getInstalledMods();
TModList missingMods;
for (const auto & modID : requiredMods)
{
if (!vstd::contains(installedMods, modID))
missingMods.push_back(modID);
}
modsPreset->saveConfigurationState();
return {presetName, missingMods};
}
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@ -58,6 +58,12 @@ public:
std::vector<std::string> getAllPresets() const; std::vector<std::string> getAllPresets() const;
std::string getActivePreset() const; std::string getActivePreset() const;
JsonNode exportCurrentPreset() const;
/// Imports preset from provided json
/// Returns name of imported preset on success
std::string importPreset(const JsonNode & data);
void setModActive(const TModID & modName, bool isActive); void setModActive(const TModID & modName, bool isActive);
void addRootMod(const TModID & modName); void addRootMod(const TModID & modName);
@ -72,6 +78,8 @@ public:
/// Returns list of currently active root mods (non-submod) /// Returns list of currently active root mods (non-submod)
TModList getActiveRootMods() const; TModList getActiveRootMods() const;
/// Returns list of root mods present in specified preset
TModList getRootMods(const std::string & presetName) const;
/// Returns list of all known settings (submods) for a specified mod /// Returns list of all known settings (submods) for a specified mod
std::map<TModID, bool> getModSettings(const TModID & modID) const; std::map<TModID, bool> getModSettings(const TModID & modID) const;
@ -155,6 +163,12 @@ public:
std::vector<std::string> getAllPresets() const; std::vector<std::string> getAllPresets() const;
std::string getActivePreset() const; std::string getActivePreset() const;
JsonNode exportCurrentPreset() const;
/// Imports preset from provided json
/// Returns name of imported preset and list of mods that must be installed to activate preset
std::tuple<std::string, TModList> importPreset(const JsonNode & data);
}; };
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END