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
This commit is contained in:
Petr Mrázek
2015-05-17 23:38:28 +02:00
parent 6ab6a450f6
commit 743af4769e
15 changed files with 553 additions and 156 deletions

View File

@@ -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<std::shared_ptr<OneSixLibrary> > MinecraftProfile::getActiveNormalLibs()

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}
};
};

View File

@@ -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<ProfilePatch>(file);
}
file->setVanilla(false);
minecraftPatch = std::dynamic_pointer_cast<ProfilePatch>(file);
else
{
auto mcversion = ENV.getVersion("net.minecraft", m_instance->intendedVersionId());
minecraftPatch = std::dynamic_pointer_cast<ProfilePatch>(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<ProfilePatch>(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<ProfilePatch>(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<ProfilePatch>(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<ProfilePatch>(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");

View File

@@ -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;
};
};

View File

@@ -2,6 +2,7 @@
#include <memory>
#include <QList>
#include <QJsonDocument>
#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<JarmodPtr> 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<ProfilePatch> ProfilePatchPtr;

View File

@@ -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;
};

View File

@@ -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;