From 743af4769ee59b5830d79139852dda0679b28a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 17 May 2015 23:38:28 +0200 Subject: GH-952 Hardcore version page tweakery Version patches get a lot of new flags that determine which actions are allowed Version page respects the flags Customize, revert and edit for version patches Builting patches can be customized --- logic/ftb/FTBProfileStrategy.cpp | 14 ++- logic/ftb/FTBProfileStrategy.h | 3 +- logic/minecraft/MinecraftProfile.cpp | 87 +++++++++++------ logic/minecraft/MinecraftProfile.h | 7 +- logic/minecraft/MinecraftVersion.cpp | 11 ++- logic/minecraft/MinecraftVersion.h | 26 ++++++ logic/minecraft/NullProfileStrategy.h | 10 +- logic/minecraft/OneSixProfileStrategy.cpp | 150 ++++++++++++++++++++++++------ logic/minecraft/OneSixProfileStrategy.h | 4 +- logic/minecraft/ProfilePatch.h | 15 ++- logic/minecraft/ProfileStrategy.h | 5 + logic/minecraft/VersionFile.h | 56 ++++++++++- 12 files changed, 308 insertions(+), 80 deletions(-) (limited to 'logic') diff --git a/logic/ftb/FTBProfileStrategy.cpp b/logic/ftb/FTBProfileStrategy.cpp index cc20b247..ff40b642 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) +bool FTBProfileStrategy::installJarMods(QStringList filepaths) { return false; } -bool FTBProfileStrategy::installJarMods(QStringList filepaths) +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 65f07069..5e5c2e73 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 acde7dc7..345930ca 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())) + continue; + } + if(it->isRevertible() || it->isRemovable()) + { + if(!remove(it->getPatchID())) { - endResetModel(); + qWarning() << "Couldn't remove" << it->getPatchID() << "from profile!"; + reapply(); saveCurrentOrder(); return false; } - it = VersionPatches.erase(it); } - 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 ef7e1369..dba7d744 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 5a759421..982a5ac3 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 9ee8425a..af15c1a4 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 eaabd3c7..44a46060 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 a84f0387..acd2904d 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"); + 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); } - 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 b554b1ea..b140dee5 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 2e97677e..de42cb7a 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 364458f5..b4dfc4b3 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 346a8dcd..dd5c962f 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; -- cgit v1.2.3