1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Automatic mod conflict resolution

This commit is contained in:
nordsoft 2022-12-26 04:34:10 +04:00 committed by Nordsoft91
parent a2e358876c
commit 2cce15efbe
5 changed files with 146 additions and 25 deletions

View File

@ -134,6 +134,7 @@ void Lobby::serverCommand(const ServerCommand & command) try
if(args[1] == username)
{
hostModsMap.clear();
ui->buttonReady->setText("Ready");
ui->optNewGame->setChecked(true);
sysMessage(joinStr.arg("you", args[0]));
@ -155,33 +156,15 @@ void Lobby::serverCommand(const ServerCommand & command) try
protocolAssert(amount * 2 == (args.size() - 1));
tagPoint = 1;
ui->modsList->clear();
auto enabledMods = buildModsMap();
for(int i = 0; i < amount; ++i, tagPoint += 2)
{
if(enabledMods.contains(args[tagPoint]))
{
if(enabledMods[args[tagPoint]] == args[tagPoint + 1])
enabledMods.remove(args[tagPoint]);
else
ui->modsList->addItem(new QListWidgetItem(QIcon("icons:mod-update.png"), QString("%1 (v%2)").arg(args[tagPoint], args[tagPoint + 1])));
}
else if(isModAvailable(args[tagPoint], args[tagPoint + 1]))
ui->modsList->addItem(new QListWidgetItem(QIcon("icons:mod-enabled.png"), QString("%1 (v%2)").arg(args[tagPoint], args[tagPoint + 1])));
else
ui->modsList->addItem(new QListWidgetItem(QIcon("icons:mod-delete.png"), QString("%1 (v%2)").arg(args[tagPoint], args[tagPoint + 1])));
}
for(auto & remainMod : enabledMods.keys())
{
ui->modsList->addItem(new QListWidgetItem(QIcon("icons:mod-disabled.png"), QString("%1 (v%2)").arg(remainMod, enabledMods[remainMod])));
}
if(!ui->modsList->count())
ui->modsList->addItem("No issues detected");
hostModsMap[args[tagPoint]] = args[tagPoint + 1];
updateMods();
break;
}
case CLIENTMODS: {
protocolAssert(args.size() > 1);
protocolAssert(args.size() >= 1);
amount = args[1].toInt();
protocolAssert(amount * 2 == (args.size() - 2));
@ -398,10 +381,87 @@ void Lobby::on_connectButton_toggled(bool checked)
ui->serverEdit->setEnabled(true);
ui->userEdit->setEnabled(true);
ui->listUsers->clear();
hostModsMap.clear();
updateMods();
socketLobby.disconnectServer();
}
}
void Lobby::updateMods()
{
ui->modsList->clear();
if(hostModsMap.empty())
return;
auto enabledMods = buildModsMap();
for(auto & mod : hostModsMap.keys())
{
auto & modValue = hostModsMap[mod];
auto modName = QString("%1 (v%2)").arg(mod, modValue);
//first - mod name
//second.first - should mod be enabled
//second.second - is possible to resolve
QMap<QString, QVariant> modData;
QList<QVariant> modDataVal;
if(enabledMods.contains(mod))
{
if(enabledMods[mod] == modValue)
enabledMods.remove(mod); //mod fully matches, remove from list
else
{
modDataVal.append(true);
modDataVal.append(false);
modData[mod] = modDataVal;
auto * lw = new QListWidgetItem(QIcon("icons:mod-update.png"), modName); //mod version mismatch
lw->setData(Qt::UserRole, modData);
ui->modsList->addItem(lw);
}
}
else if(isModAvailable(mod, modValue))
{
modDataVal.append(true);
modDataVal.append(true);
modData[mod] = modDataVal;
auto * lw = new QListWidgetItem(QIcon("icons:mod-enabled.png"), modName); //mod available and needs to be enabled
lw->setData(Qt::UserRole, modData);
ui->modsList->addItem(lw);
}
else
{
modDataVal.append(true);
modDataVal.append(false);
modData[mod] = modDataVal;
auto * lw = new QListWidgetItem(QIcon("icons:mod-delete.png"), modName); //mod is not available and needs to be installed
lw->setData(Qt::UserRole, modData);
ui->modsList->addItem(lw);
}
}
for(auto & remainMod : enabledMods.keys())
{
//first - mod name
//second.first - should mod be enabled
//second.second - is possible to resolve
QMap<QString, QVariant> modData;
QList<QVariant> modDataVal;
modDataVal.append(false);
modDataVal.append(true);
modData[remainMod] = modDataVal;
auto modName = QString("%1 (v%2)").arg(remainMod, enabledMods[remainMod]);
auto * lw = new QListWidgetItem(QIcon("icons:mod-disabled.png"), modName); //mod needs to be disabled
lw->setData(Qt::UserRole, modData);
ui->modsList->addItem(lw);
}
if(!ui->modsList->count())
{
ui->buttonResolve->setEnabled(false);
ui->modsList->addItem("No issues detected");
}
else
{
ui->buttonResolve->setEnabled(true);
}
}
void Lobby::on_newButton_clicked()
{
new LobbyRoomRequest(socketLobby, "", buildModsMap(), this);
@ -456,7 +516,31 @@ void Lobby::on_kickButton_clicked()
void Lobby::on_buttonResolve_clicked()
{
//TODO: auto-resolve mods conflicts
QStringList toEnableList, toDisableList;
for(auto * item : ui->modsList->selectedItems())
{
auto data = item->data(Qt::UserRole);
if(data.isNull())
continue;
auto modData = data.toMap();
assert(modData.size() == 1);
auto modDataVal = modData.begin()->toList();
assert(modDataVal.size() == 2);
if(!modDataVal[1].toBool())
continue;
if(modDataVal[0].toBool())
toEnableList << modData.begin().key();
else
toDisableList << modData.begin().key();
}
for(auto & mod : toDisableList)
emit disableMod(mod);
for(auto & mod : toEnableList)
emit enableMod(mod);
}
void Lobby::on_optNewGame_toggled(bool checked)

View File

@ -22,6 +22,14 @@ class Lobby : public QWidget
public:
explicit Lobby(QWidget *parent = nullptr);
~Lobby();
signals:
void enableMod(QString mod);
void disableMod(QString mod);
public slots:
void updateMods();
private slots:
void on_messageEdit_returnPressed();
@ -66,6 +74,7 @@ private:
QString session;
QString username;
QStringList gameArgs;
QMap<QString, QString> hostModsMap;
enum AuthStatus
{

View File

@ -53,6 +53,10 @@ MainWindow::MainWindow(QWidget * parent)
load(); // load FS before UI
ui->setupUi(this);
connect(ui->lobbyView, &Lobby::enableMod, ui->modlistView, &CModListView::enableModByName);
connect(ui->lobbyView, &Lobby::disableMod, ui->modlistView, &CModListView::disableModByName);
connect(ui->modlistView, &CModListView::modsChanged, ui->lobbyView, &Lobby::updateMods);
//load window settings
QSettings s(Ui::teamName, Ui::appName);

View File

@ -496,7 +496,14 @@ QStringList CModListView::findDependentMods(QString mod, bool excludeDisabled)
void CModListView::on_enableButton_clicked()
{
QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
enableModByName(modName);
checkManagerErrors();
}
void CModListView::enableModByName(QString modName)
{
assert(findBlockingMods(modName).empty());
assert(findInvalidDependencies(modName).empty());
@ -505,17 +512,24 @@ void CModListView::on_enableButton_clicked()
if(modModel->getMod(name).isDisabled())
manager->enableMod(name);
}
checkManagerErrors();
emit modsChanged();
}
void CModListView::on_disableButton_clicked()
{
QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
disableModByName(modName);
checkManagerErrors();
}
void CModListView::disableModByName(QString modName)
{
if(modModel->hasMod(modName) && modModel->getMod(modName).isEnabled())
manager->disableMod(modName);
checkManagerErrors();
emit modsChanged();
}
void CModListView::on_updateButton_clicked()
@ -544,6 +558,8 @@ void CModListView::on_uninstallButton_clicked()
manager->disableMod(modName);
manager->uninstallMod(modName);
}
emit modsChanged();
checkManagerErrors();
}
@ -631,6 +647,8 @@ void CModListView::downloadFinished(QStringList savedFiles, QStringList failedFi
if(doInstallFiles)
installFiles(savedFiles);
emit modsChanged();
}
void CModListView::hideProgressBar()

View File

@ -66,6 +66,8 @@ class CModListView : public QWidget
signals:
void extraResolutionsEnabledChanged(bool enabled);
void modsChanged();
public:
explicit CModListView(QWidget * parent = 0);
@ -82,6 +84,10 @@ public:
bool isExtraResolutionsModEnabled() const;
const CModList & getModList() const;
public slots:
void enableModByName(QString modName);
void disableModByName(QString modName);
private slots:
void dataChanged(const QModelIndex & topleft, const QModelIndex & bottomRight);