diff --git a/application/pages/VersionPage.cpp b/application/pages/VersionPage.cpp index ab4aecf6e..bb310eea1 100644 --- a/application/pages/VersionPage.cpp +++ b/application/pages/VersionPage.cpp @@ -67,16 +67,14 @@ VersionPage::VersionPage(OneSixInstance *inst, QWidget *parent) m_version = m_inst->getMinecraftProfile(); if (m_version) { - ui->libraryTreeView->setModel(m_version.get()); - ui->libraryTreeView->installEventFilter(this); - ui->libraryTreeView->setSelectionMode(QAbstractItemView::SingleSelection); - connect(ui->libraryTreeView->selectionModel(), &QItemSelectionModel::currentChanged, + ui->packageView->setModel(m_version.get()); + ui->packageView->installEventFilter(this); + ui->packageView->setSelectionMode(QAbstractItemView::SingleSelection); + connect(ui->packageView->selectionModel(), &QItemSelectionModel::currentChanged, this, &VersionPage::versionCurrent); updateVersionControls(); // select first item. - auto index = ui->libraryTreeView->model()->index(0,0); - if(index.isValid()) - ui->libraryTreeView->setCurrentIndex(index); + preselect(0); } else { @@ -95,14 +93,15 @@ void VersionPage::updateVersionControls() { ui->forgeBtn->setEnabled(true); ui->liteloaderBtn->setEnabled(true); + updateButtons(); } void VersionPage::disableVersionControls() { ui->forgeBtn->setEnabled(false); ui->liteloaderBtn->setEnabled(false); - ui->reloadLibrariesBtn->setEnabled(false); - ui->removeLibraryBtn->setEnabled(false); + ui->reloadBtn->setEnabled(false); + updateButtons(); } bool VersionPage::reloadMinecraftProfile() @@ -126,21 +125,22 @@ bool VersionPage::reloadMinecraftProfile() } } -void VersionPage::on_reloadLibrariesBtn_clicked() +void VersionPage::on_reloadBtn_clicked() { reloadMinecraftProfile(); } -void VersionPage::on_removeLibraryBtn_clicked() +void VersionPage::on_removeBtn_clicked() { - if (ui->libraryTreeView->currentIndex().isValid()) + if (ui->packageView->currentIndex().isValid()) { // FIXME: use actual model, not reloading. - if (!m_version->remove(ui->libraryTreeView->currentIndex().row())) + if (!m_version->remove(ui->packageView->currentIndex().row())) { QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file")); } } + updateButtons(); } void VersionPage::on_jarmodBtn_clicked() @@ -150,9 +150,10 @@ void VersionPage::on_jarmodBtn_clicked() { m_version->installJarMods(list); } + updateButtons(); } -void VersionPage::on_resetLibraryOrderBtn_clicked() +void VersionPage::on_resetOrderBtn_clicked() { try { @@ -162,43 +163,36 @@ void VersionPage::on_resetLibraryOrderBtn_clicked() { QMessageBox::critical(this, tr("Error"), e.cause()); } + updateButtons(); } -void VersionPage::on_moveLibraryUpBtn_clicked() +void VersionPage::on_moveUpBtn_clicked() { - if (ui->libraryTreeView->selectionModel()->selectedRows().isEmpty()) - { - return; - } try { - const int row = ui->libraryTreeView->selectionModel()->selectedRows().first().row(); - m_version->move(row, MinecraftProfile::MoveUp); + m_version->move(currentRow(), MinecraftProfile::MoveUp); } catch (MMCError &e) { QMessageBox::critical(this, tr("Error"), e.cause()); } + updateButtons(); } -void VersionPage::on_moveLibraryDownBtn_clicked() +void VersionPage::on_moveDownBtn_clicked() { - if (ui->libraryTreeView->selectionModel()->selectedRows().isEmpty()) - { - return; - } try { - const int row = ui->libraryTreeView->selectionModel()->selectedRows().first().row(); - m_version->move(row, MinecraftProfile::MoveDown); + m_version->move(currentRow(), MinecraftProfile::MoveDown); } catch (MMCError &e) { QMessageBox::critical(this, tr("Error"), e.cause()); } + updateButtons(); } -void VersionPage::on_changeMCVersionBtn_clicked() +void VersionPage::on_changeVersionBtn_clicked() { VersionSelectDialog vselect(m_inst->versionList().get(), tr("Change Minecraft version"), this); @@ -239,6 +233,7 @@ void VersionPage::on_changeMCVersionBtn_clicked() ProgressDialog tDialog(this); connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString))); tDialog.exec(updateTask.get()); + updateButtons(); } void VersionPage::on_forgeBtn_clicked() @@ -253,6 +248,7 @@ void VersionPage::on_forgeBtn_clicked() ProgressDialog dialog(this); dialog.exec( ForgeInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this)); + preselect(m_version->rowCount(QModelIndex())-1); } } @@ -269,32 +265,59 @@ void VersionPage::on_liteloaderBtn_clicked() ProgressDialog dialog(this); dialog.exec( LiteLoaderInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this)); + preselect(m_version->rowCount(QModelIndex())-1); } } void VersionPage::versionCurrent(const QModelIndex ¤t, const QModelIndex &previous) { - if (!current.isValid()) + currentIdx = current.row(); + updateButtons(currentIdx); +} + +void VersionPage::preselect(int row) +{ + if(row < 0) { - ui->removeLibraryBtn->setDisabled(true); - ui->moveLibraryDownBtn->setDisabled(true); - ui->moveLibraryUpBtn->setDisabled(true); + row = 0; + } + if(row >= m_version->rowCount(QModelIndex())) + { + row = m_version->rowCount(QModelIndex()) - 1; + } + if(row < 0) + { + return; + } + auto model_index = m_version->index(row); + ui->packageView->selectionModel()->select(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + updateButtons(row); +} + +void VersionPage::updateButtons(int row) +{ + if(row == -1) + row = currentRow(); + auto patch = m_version->versionPatch(row); + if (!patch) + { + ui->removeBtn->setDisabled(true); + ui->moveDownBtn->setDisabled(true); + ui->moveUpBtn->setDisabled(true); + ui->changeVersionBtn->setDisabled(true); + ui->editBtn->setDisabled(true); + ui->customizeBtn->setDisabled(true); + ui->revertBtn->setDisabled(true); } else { - bool enabled = m_version->canRemove(current.row()); - ui->removeLibraryBtn->setEnabled(enabled); - ui->moveLibraryDownBtn->setEnabled(enabled); - ui->moveLibraryUpBtn->setEnabled(enabled); - } - QString selectedId = m_version->versionFileId(current.row()); - if (selectedId == "net.minecraft") - { - ui->changeMCVersionBtn->setEnabled(true); - } - else - { - ui->changeMCVersionBtn->setEnabled(false); + ui->removeBtn->setEnabled(patch->isRemovable()); + ui->moveDownBtn->setEnabled(patch->isMoveable()); + ui->moveUpBtn->setEnabled(patch->isMoveable()); + ui->changeVersionBtn->setEnabled(patch->isVersionChangeable()); + ui->editBtn->setEnabled(patch->isEditable()); + ui->customizeBtn->setEnabled(patch->isCustomizable()); + ui->revertBtn->setEnabled(patch->isRevertible()); } } @@ -303,3 +326,68 @@ void VersionPage::onGameUpdateError(QString error) CustomMessageBox::selectable(this, tr("Error updating instance"), error, QMessageBox::Warning)->show(); } + +ProfilePatchPtr VersionPage::current() +{ + auto row = currentRow(); + if(row < 0) + { + return nullptr; + } + return m_version->versionPatch(row); +} + +int VersionPage::currentRow() +{ + if (ui->packageView->selectionModel()->selectedRows().isEmpty()) + { + return -1; + } + return ui->packageView->selectionModel()->selectedRows().first().row(); +} + +void VersionPage::on_customizeBtn_clicked() +{ + auto version = currentRow(); + if(version == -1) + { + return; + } + if(!m_version->customize(version)) + { + // TODO: some error box here + } + updateButtons(); + preselect(currentIdx); +} + +void VersionPage::on_editBtn_clicked() +{ + auto version = current(); + if(!version) + { + return; + } + auto filename = version->getPatchFilename(); + if(!QFileInfo::exists(filename)) + { + qWarning() << "file" << filename << "can't be opened for editing, doesn't exist!"; + return; + } + MMC->openJsonEditor(filename); +} + +void VersionPage::on_revertBtn_clicked() +{ + auto version = currentRow(); + if(version == -1) + { + return; + } + if(!m_version->revert(version)) + { + // TODO: some error box here + } + updateButtons(); + preselect(currentIdx); +} diff --git a/application/pages/VersionPage.h b/application/pages/VersionPage.h index 0965edeb2..45732b25c 100644 --- a/application/pages/VersionPage.h +++ b/application/pages/VersionPage.h @@ -46,22 +46,29 @@ public: return "Instance-version"; } virtual bool shouldDisplay() const; -private -slots: - // version tab +private slots: void on_forgeBtn_clicked(); void on_liteloaderBtn_clicked(); - void on_reloadLibrariesBtn_clicked(); - void on_removeLibraryBtn_clicked(); - void on_resetLibraryOrderBtn_clicked(); - void on_moveLibraryUpBtn_clicked(); - void on_moveLibraryDownBtn_clicked(); + void on_reloadBtn_clicked(); + void on_removeBtn_clicked(); + void on_resetOrderBtn_clicked(); + void on_moveUpBtn_clicked(); + void on_moveDownBtn_clicked(); void on_jarmodBtn_clicked(); + void on_revertBtn_clicked(); + void on_editBtn_clicked(); + void on_customizeBtn_clicked(); void updateVersionControls(); void disableVersionControls(); - void on_changeMCVersionBtn_clicked(); + void on_changeVersionBtn_clicked(); + +private: + ProfilePatchPtr current(); + int currentRow(); + void updateButtons(int row = -1); + void preselect(int row = 0); protected: /// FIXME: this shouldn't be necessary! @@ -71,9 +78,9 @@ private: Ui::VersionPage *ui; std::shared_ptr m_version; OneSixInstance *m_inst; + int currentIdx = 0; -public -slots: +public slots: void versionCurrent(const QModelIndex ¤t, const QModelIndex &previous); private slots: diff --git a/application/pages/VersionPage.ui b/application/pages/VersionPage.ui index 67a556c8d..1216229f3 100644 --- a/application/pages/VersionPage.ui +++ b/application/pages/VersionPage.ui @@ -11,7 +11,7 @@ - Version + Package Versions @@ -37,7 +37,7 @@ - + Qt::ScrollBarAlwaysOn @@ -65,16 +65,19 @@ - + + + Change version of the selected package. + Change version - + - This isn't implemented yet. + Make the selected package apply sooner. Move up @@ -82,9 +85,9 @@ - + - This isn't implemented yet. + Make the selected package apply later. Move down @@ -92,12 +95,58 @@ - + + + Remove selected package from the instance. + Remove + + + + + + + Edit + + + Qt::AlignCenter + + + + + + + Customize selected package. + + + Customize + + + + + + + Edit selected package. + + + Edit + + + + + + + Revert the selected package to default. + + + Revert + + + @@ -114,7 +163,7 @@ - Replace any current custom version with Minecraft Forge + Install the Minecraft Forge package. Install Forge @@ -123,6 +172,9 @@ + + Install the LiteLoader package. + Install LiteLoader @@ -130,6 +182,9 @@ + + Add a mod into the Minecraft jar file. + Add jar mod @@ -149,9 +204,9 @@ - + - This isn't implemented yet. + Reset apply order of packages. Reset order @@ -159,7 +214,10 @@ - + + + Reload all packages. + Reload @@ -199,6 +257,22 @@ 1 + + tabWidget + packageView + changeVersionBtn + moveUpBtn + moveDownBtn + removeBtn + customizeBtn + editBtn + revertBtn + forgeBtn + liteloaderBtn + jarmodBtn + resetOrderBtn + reloadBtn + diff --git a/logic/ftb/FTBProfileStrategy.cpp b/logic/ftb/FTBProfileStrategy.cpp index cc20b247c..ff40b642e 100644 --- a/logic/ftb/FTBProfileStrategy.cpp +++ b/logic/ftb/FTBProfileStrategy.cpp @@ -26,6 +26,7 @@ void FTBProfileStrategy::loadDefaultBuiltinPatches() auto file = ProfileUtils::parseJsonFile(QFileInfo(mcJson), false); file->fileId = "net.minecraft"; file->name = QObject::tr("Minecraft (tracked)"); + file->setVanilla(true); if(file->version.isEmpty()) { file->version = mcVersion; @@ -59,6 +60,7 @@ void FTBProfileStrategy::loadDefaultBuiltinPatches() addLib->insertType = RawLibrary::Prepend; } file->fileId = "org.multimc.ftb.pack"; + file->setVanilla(true); file->name = QObject::tr("%1 (FTB pack)").arg(m_instance->name()); if(file->version.isEmpty()) { @@ -117,6 +119,8 @@ void FTBProfileStrategy::loadUserPatches() throw VersionBuildError( QObject::tr("load id %1 does not match internal id %2").arg(id, file->fileId)); } + file->setRemovable(true); + file->setMovable(true); profile->appendPatch(file); } // now load the rest by internal preference. @@ -140,6 +144,8 @@ void FTBProfileStrategy::loadUserPatches() throw VersionBuildError(QObject::tr("%1 has the same order as %2") .arg(file->fileId, files[file->order].second->fileId)); } + file->setRemovable(true); + file->setMovable(true); files.insert(file->order, qMakePair(info.fileName(), file)); } for (auto order : files.keys()) @@ -170,13 +176,17 @@ bool FTBProfileStrategy::resetOrder() return false; } -bool FTBProfileStrategy::removePatch(ProfilePatchPtr patch) -{ - return false; -} - bool FTBProfileStrategy::installJarMods(QStringList filepaths) { return false; } +bool FTBProfileStrategy::customizePatch(ProfilePatchPtr patch) +{ + return false; +} + +bool FTBProfileStrategy::revertPatch(ProfilePatchPtr patch) +{ + return false; +} diff --git a/logic/ftb/FTBProfileStrategy.h b/logic/ftb/FTBProfileStrategy.h index 65f070690..5e5c2e730 100644 --- a/logic/ftb/FTBProfileStrategy.h +++ b/logic/ftb/FTBProfileStrategy.h @@ -13,7 +13,8 @@ public: virtual bool resetOrder() override; virtual bool saveOrder(ProfileUtils::PatchOrder order) override; virtual bool installJarMods(QStringList filepaths) override; - virtual bool removePatch(ProfilePatchPtr patch) override; + virtual bool customizePatch (ProfilePatchPtr patch) override; + virtual bool revertPatch (ProfilePatchPtr patch) override; protected: void loadDefaultBuiltinPatches(); diff --git a/logic/minecraft/MinecraftProfile.cpp b/logic/minecraft/MinecraftProfile.cpp index acde7dc7b..345930cae 100644 --- a/logic/minecraft/MinecraftProfile.cpp +++ b/logic/minecraft/MinecraftProfile.cpp @@ -91,22 +91,18 @@ void MinecraftProfile::appendPatch(ProfilePatchPtr patch) endInsertRows(); } -bool MinecraftProfile::canRemove(const int index) const -{ - return VersionPatches.at(index)->isMoveable(); -} - bool MinecraftProfile::remove(const int index) { - if (!canRemove(index)) + auto patch = versionPatch(index); + if (!patch->isRemovable()) { - qDebug() << "Patch" << index << "is non-removable"; + qDebug() << "Patch" << patch->getPatchID() << "is non-removable"; return false; } - if(!m_strategy->removePatch(VersionPatches.at(index))) + if(!m_strategy->removePatch(patch)) { - qCritical() << "Patch" << index << "could not be removed"; + qCritical() << "Patch" << patch->getPatchID() << "could not be removed"; return false; } @@ -132,6 +128,46 @@ bool MinecraftProfile::remove(const QString id) return false; } +bool MinecraftProfile::customize(int index) +{ + auto patch = versionPatch(index); + if (!patch->isCustomizable()) + { + qDebug() << "Patch" << patch->getPatchID() << "is not customizable"; + return false; + } + if(!m_strategy->customizePatch(patch)) + { + qCritical() << "Patch" << patch->getPatchID() << "could not be customized"; + return false; + } + reapply(); + saveCurrentOrder(); + // FIXME: maybe later in unstable + // emit dataChanged(createIndex(index, 0), createIndex(index, columnCount(QModelIndex()) - 1)); + return true; +} + +bool MinecraftProfile::revert(int index) +{ + auto patch = versionPatch(index); + if (!patch->isRevertible()) + { + qDebug() << "Patch" << patch->getPatchID() << "is not revertible"; + return false; + } + if(!m_strategy->revertPatch(patch)) + { + qCritical() << "Patch" << patch->getPatchID() << "could not be reverted"; + return false; + } + reapply(); + saveCurrentOrder(); + // FIXME: maybe later in unstable + // emit dataChanged(createIndex(index, 0), createIndex(index, columnCount(QModelIndex()) - 1)); + return true; +} + QString MinecraftProfile::versionFileId(const int index) const { if (index < 0 || index >= VersionPatches.size()) @@ -150,13 +186,13 @@ ProfilePatchPtr MinecraftProfile::versionPatch(const QString &id) return file; } } - return 0; + return nullptr; } ProfilePatchPtr MinecraftProfile::versionPatch(int index) { if(index < 0 || index >= VersionPatches.size()) - return 0; + return nullptr; return VersionPatches[index]; } @@ -172,37 +208,28 @@ bool MinecraftProfile::isVanilla() bool MinecraftProfile::revertToVanilla() { - /* - beginResetModel(); // remove patches, if present - auto it = VersionPatches.begin(); - while (it != VersionPatches.end()) + auto VersionPatchesCopy = VersionPatches; + for(auto & it: VersionPatchesCopy) { - if ((*it)->isMoveable()) + if (!it->isCustom()) { - if(!preremove(*it)) - { - endResetModel(); - saveCurrentOrder(); - return false; - } - if(!QFile::remove((*it)->getPatchFilename())) - { - endResetModel(); - saveCurrentOrder(); - return false; - } - it = VersionPatches.erase(it); + continue; + } + if(it->isRevertible() || it->isRemovable()) + { + if(!remove(it->getPatchID())) + { + qWarning() << "Couldn't remove" << it->getPatchID() << "from profile!"; + reapply(); + saveCurrentOrder(); + return false; + } } - else - it++; } reapply(); - endResetModel(); saveCurrentOrder(); return true; - */ - return false; } QList > MinecraftProfile::getActiveNormalLibs() diff --git a/logic/minecraft/MinecraftProfile.h b/logic/minecraft/MinecraftProfile.h index ef7e1369e..dba7d7447 100644 --- a/logic/minecraft/MinecraftProfile.h +++ b/logic/minecraft/MinecraftProfile.h @@ -60,9 +60,6 @@ public: /// DEPRECATED, remove ASAP int getFreeOrderNumber(); - /// Can patch file # be removed? - bool canRemove(const int index) const; - enum MoveDirection { MoveUp, MoveDown }; /// move patch file # up or down the list void move(const int index, const MoveDirection direction); @@ -73,6 +70,10 @@ public: /// remove patch file by id - including files/records bool remove(const QString id); + bool customize(int index); + + bool revert(int index); + void resetOrder(); /// reload all profile patches from storage, clear the profile and apply the patches diff --git a/logic/minecraft/MinecraftVersion.cpp b/logic/minecraft/MinecraftVersion.cpp index 5a7594212..982a5ac3e 100644 --- a/logic/minecraft/MinecraftVersion.cpp +++ b/logic/minecraft/MinecraftVersion.cpp @@ -60,11 +60,20 @@ void MinecraftVersion::applyFileTo(MinecraftProfile *version) getVersionFile()->applyTo(version); } +QJsonDocument MinecraftVersion::toJson(bool saveOrder) +{ + return getVersionFile()->toJson(saveOrder); +} + VersionFilePtr MinecraftVersion::getVersionFile() { QFileInfo versionFile(QString("versions/%1/%1.dat").arg(m_descriptor)); - return ProfileUtils::parseBinaryJsonFile(versionFile); + auto loadedVersionFile = ProfileUtils::parseBinaryJsonFile(versionFile); + loadedVersionFile->name = "Minecraft"; + //FIXME: possibly not the best place for this... but w/e + loadedVersionFile->setCustomizable(true); + return loadedVersionFile; } diff --git a/logic/minecraft/MinecraftVersion.h b/logic/minecraft/MinecraftVersion.h index 9ee8425a7..af15c1a4a 100644 --- a/logic/minecraft/MinecraftVersion.h +++ b/logic/minecraft/MinecraftVersion.h @@ -48,9 +48,35 @@ public: /* methods */ bool needsUpdate(); bool hasUpdate(); virtual bool isCustom() override; + virtual bool isMoveable() override + { + return false; + } + virtual bool isCustomizable() override + { + return true; + } + virtual bool isRemovable() override + { + return false; + } + virtual bool isRevertible() override + { + return false; + } + virtual bool isEditable() override + { + return false; + } + virtual bool isVersionChangeable() override + { + return true; + } VersionFilePtr getVersionFile(); + virtual QJsonDocument toJson(bool saveOrder) override; + private: /* methods */ void applyFileTo(MinecraftProfile *version); diff --git a/logic/minecraft/NullProfileStrategy.h b/logic/minecraft/NullProfileStrategy.h index eaabd3c75..44a46060c 100644 --- a/logic/minecraft/NullProfileStrategy.h +++ b/logic/minecraft/NullProfileStrategy.h @@ -13,6 +13,14 @@ class NullProfileStrategy: public ProfileStrategy { return false; } + virtual bool customizePatch(ProfilePatchPtr patch) + { + return false; + } + virtual bool revertPatch(ProfilePatchPtr patch) + { + return false; + } virtual bool resetOrder() { return false; @@ -21,4 +29,4 @@ class NullProfileStrategy: public ProfileStrategy { return false; } -}; \ No newline at end of file +}; diff --git a/logic/minecraft/OneSixProfileStrategy.cpp b/logic/minecraft/OneSixProfileStrategy.cpp index a84f03870..acd2904d4 100644 --- a/logic/minecraft/OneSixProfileStrategy.cpp +++ b/logic/minecraft/OneSixProfileStrategy.cpp @@ -76,46 +76,62 @@ void OneSixProfileStrategy::upgradeDeprecatedFiles() } } - void OneSixProfileStrategy::loadDefaultBuiltinPatches() { - auto mcJson = PathCombine(m_instance->instanceRoot(), "patches" , "net.minecraft.json"); - // load up the base minecraft patch - ProfilePatchPtr minecraftPatch; - if(QFile::exists(mcJson)) { - auto file = ProfileUtils::parseJsonFile(QFileInfo(mcJson), false); - if(file->version.isEmpty()) + auto mcJson = PathCombine(m_instance->instanceRoot(), "patches" , "net.minecraft.json"); + // load up the base minecraft patch + ProfilePatchPtr minecraftPatch; + if(QFile::exists(mcJson)) { - file->version = m_instance->intendedVersionId(); + auto file = ProfileUtils::parseJsonFile(QFileInfo(mcJson), false); + if(file->version.isEmpty()) + { + file->version = m_instance->intendedVersionId(); + } + file->setVanilla(false); + file->setRevertible(true); + minecraftPatch = std::dynamic_pointer_cast(file); } - file->setVanilla(false); - minecraftPatch = std::dynamic_pointer_cast(file); + else + { + auto mcversion = ENV.getVersion("net.minecraft", m_instance->intendedVersionId()); + minecraftPatch = std::dynamic_pointer_cast(mcversion); + } + if (!minecraftPatch) + { + throw VersionIncomplete("net.minecraft"); + } + minecraftPatch->setOrder(-2); + profile->appendPatch(minecraftPatch); } - else - { - auto mcversion = ENV.getVersion("net.minecraft", m_instance->intendedVersionId()); - minecraftPatch = std::dynamic_pointer_cast(mcversion); - } - if (!minecraftPatch) - { - throw VersionIncomplete("net.minecraft"); - } - minecraftPatch->setOrder(-2); - profile->appendPatch(minecraftPatch); - - // TODO: this is obviously fake. - QResource LWJGL(":/versions/LWJGL/2.9.1.json"); - auto lwjgl = ProfileUtils::parseJsonFile(LWJGL.absoluteFilePath(), false); - auto lwjglPatch = std::dynamic_pointer_cast(lwjgl); - if (!lwjglPatch) { - throw VersionIncomplete("org.lwjgl"); + auto lwjglJson = PathCombine(m_instance->instanceRoot(), "patches" , "org.lwjgl.json"); + ProfilePatchPtr lwjglPatch; + if(QFile::exists(lwjglJson)) + { + auto file = ProfileUtils::parseJsonFile(QFileInfo(lwjglJson), false); + file->setVanilla(false); + file->setRevertible(true); + lwjglPatch = std::dynamic_pointer_cast(file); + } + else + { + // NOTE: this is obviously fake, is fixed in unstable. + QResource LWJGL(":/versions/LWJGL/2.9.1.json"); + auto lwjgl = ProfileUtils::parseJsonFile(LWJGL.absoluteFilePath(), false); + lwjgl->setVanilla(true); + lwjgl->setCustomizable(true); + lwjglPatch = std::dynamic_pointer_cast(lwjgl); + } + if (!lwjglPatch) + { + throw VersionIncomplete("org.lwjgl"); + } + lwjglPatch->setOrder(-1); + profile->appendPatch(lwjglPatch); } - lwjglPatch->setOrder(-1); - lwjgl->setVanilla(true); - profile->appendPatch(lwjglPatch); } void OneSixProfileStrategy::loadUserPatches() @@ -149,6 +165,8 @@ void OneSixProfileStrategy::loadUserPatches() throw VersionBuildError( QObject::tr("load id %1 does not match internal id %2").arg(id, file->fileId)); } + file->setRemovable(true); + file->setMovable(true); profile->appendPatch(file); } // now load the rest by internal preference. @@ -172,6 +190,8 @@ void OneSixProfileStrategy::loadUserPatches() throw VersionBuildError(QObject::tr("%1 has the same order as %2") .arg(file->fileId, files[file->order].second->fileId)); } + file->setRemovable(true); + file->setMovable(true); files.insert(file->order, qMakePair(info.fileName(), file)); } for (auto order : files.keys()) @@ -243,6 +263,74 @@ bool OneSixProfileStrategy::removePatch(ProfilePatchPtr patch) return ok; } +bool OneSixProfileStrategy::customizePatch(ProfilePatchPtr patch) +{ + if(patch->isCustom()) + { + return false; + } + + auto filename = PathCombine(m_instance->instanceRoot(), "patches" , patch->getPatchID() + ".json"); + if(!ensureFilePathExists(filename)) + { + return false; + } + QSaveFile jsonFile(filename); + if(!jsonFile.open(QIODevice::WriteOnly)) + { + return false; + } + auto document = patch->toJson(true); + jsonFile.write(document.toJson()); + if(!jsonFile.commit()) + { + return false; + } + try + { + load(); + } + catch (VersionIncomplete &error) + { + qDebug() << "Version was incomplete:" << error.cause(); + } + catch (MMCError &error) + { + qWarning() << "Version could not be loaded:" << error.cause(); + } + return true; +} + +bool OneSixProfileStrategy::revertPatch(ProfilePatchPtr patch) +{ + if(!patch->isCustom()) + { + // already not custom + return true; + } + auto filename = patch->getPatchFilename(); + if(!QFile::exists(filename)) + { + // already gone / not custom + return true; + } + // just kill the file and reload + bool result = QFile::remove(filename); + try + { + load(); + } + catch (VersionIncomplete &error) + { + qDebug() << "Version was incomplete:" << error.cause(); + } + catch (MMCError &error) + { + qWarning() << "Version could not be loaded:" << error.cause(); + } + return result; +} + bool OneSixProfileStrategy::installJarMods(QStringList filepaths) { QString patchDir = PathCombine(m_instance->instanceRoot(), "patches"); diff --git a/logic/minecraft/OneSixProfileStrategy.h b/logic/minecraft/OneSixProfileStrategy.h index b554b1eae..b140dee50 100644 --- a/logic/minecraft/OneSixProfileStrategy.h +++ b/logic/minecraft/OneSixProfileStrategy.h @@ -13,6 +13,8 @@ public: virtual bool saveOrder(ProfileUtils::PatchOrder order) override; virtual bool installJarMods(QStringList filepaths) override; virtual bool removePatch(ProfilePatchPtr patch) override; + virtual bool customizePatch(ProfilePatchPtr patch) override; + virtual bool revertPatch(ProfilePatchPtr patch) override; protected: void loadDefaultBuiltinPatches(); @@ -21,4 +23,4 @@ protected: protected: OneSixInstance *m_instance; -}; \ No newline at end of file +}; diff --git a/logic/minecraft/ProfilePatch.h b/logic/minecraft/ProfilePatch.h index 2e97677ea..de42cb7ad 100644 --- a/logic/minecraft/ProfilePatch.h +++ b/logic/minecraft/ProfilePatch.h @@ -2,6 +2,7 @@ #include #include +#include #include "JarMod.h" class MinecraftProfile; @@ -10,15 +11,20 @@ class ProfilePatch public: virtual ~ProfilePatch(){}; virtual void applyTo(MinecraftProfile *version) = 0; + virtual QJsonDocument toJson(bool saveOrder) = 0; virtual bool isMinecraftVersion() = 0; virtual bool hasJarMods() = 0; virtual QList getJarMods() = 0; - virtual bool isMoveable() - { - return getOrder() >= 0; - } + virtual bool isMoveable() = 0; + virtual bool isCustomizable() = 0; + virtual bool isRevertible() = 0; + virtual bool isRemovable() = 0; + virtual bool isCustom() = 0; + virtual bool isEditable() = 0; + virtual bool isVersionChangeable() = 0; + virtual void setOrder(int order) = 0; virtual int getOrder() = 0; @@ -26,7 +32,6 @@ public: virtual QString getPatchName() = 0; virtual QString getPatchVersion() = 0; virtual QString getPatchFilename() = 0; - virtual bool isCustom() = 0; }; typedef std::shared_ptr ProfilePatchPtr; diff --git a/logic/minecraft/ProfileStrategy.h b/logic/minecraft/ProfileStrategy.h index 364458f5a..b4dfc4b3a 100644 --- a/logic/minecraft/ProfileStrategy.h +++ b/logic/minecraft/ProfileStrategy.h @@ -25,6 +25,11 @@ public: /// remove any files or records that constitute the version patch virtual bool removePatch(ProfilePatchPtr jarMod) = 0; + /// make the patch custom, if possible + virtual bool customizePatch(ProfilePatchPtr patch) = 0; + + /// revert the custom patch to 'vanilla', if possible + virtual bool revertPatch(ProfilePatchPtr patch) = 0; protected: MinecraftProfile *profile; }; diff --git a/logic/minecraft/VersionFile.h b/logic/minecraft/VersionFile.h index 346a8dcdf..dd5c962fd 100644 --- a/logic/minecraft/VersionFile.h +++ b/logic/minecraft/VersionFile.h @@ -20,7 +20,7 @@ class VersionFile : public ProfilePatch public: /* methods */ static VersionFilePtr fromJson(const QJsonDocument &doc, const QString &filename, const bool requireOrder); - QJsonDocument toJson(bool saveOrder); + virtual QJsonDocument toJson(bool saveOrder) override; virtual void applyTo(MinecraftProfile *version) override; virtual bool isMinecraftVersion() override; @@ -53,18 +53,64 @@ public: /* methods */ { return filename; } - virtual bool isCustom() + virtual bool isCustom() override { - return !isVanilla; + return !m_isVanilla; }; + virtual bool isCustomizable() override + { + return m_isCustomizable; + } + virtual bool isRemovable() override + { + return m_isRemovable; + } + virtual bool isRevertible() override + { + return m_isRevertible; + } + virtual bool isMoveable() override + { + return m_isMovable; + } + virtual bool isEditable() override + { + return isCustom(); + } + virtual bool isVersionChangeable() override + { + return false; + } + void setVanilla (bool state) { - isVanilla = state; + m_isVanilla = state; } + void setRemovable (bool state) + { + m_isRemovable = state; + } + void setRevertible (bool state) + { + m_isRevertible = state; + } + void setCustomizable (bool state) + { + m_isCustomizable = state; + } + void setMovable (bool state) + { + m_isMovable = state; + } + public: /* data */ int order = 0; - bool isVanilla = false; + bool m_isVanilla = false; + bool m_isRemovable = false; + bool m_isRevertible = false; + bool m_isCustomizable = false; + bool m_isMovable = false; QString name; QString fileId; QString version;