diff options
Diffstat (limited to 'logic')
37 files changed, 1020 insertions, 478 deletions
diff --git a/logic/BaseInstance.cpp b/logic/BaseInstance.cpp index e166449f..10bb4573 100644 --- a/logic/BaseInstance.cpp +++ b/logic/BaseInstance.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "MultiMC.h" #include "BaseInstance.h" #include "BaseInstance_p.h" @@ -131,9 +132,9 @@ InstanceList *BaseInstance::instList() const return NULL; } -InstVersionList *BaseInstance::versionList() const +BaseVersionList *BaseInstance::versionList() const { - return &MinecraftVersionList::getMainList(); + return MMC->minecraftlist(); } SettingsObject &BaseInstance::settings() const diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h index cc9422be..fa317ba1 100644 --- a/logic/BaseInstance.h +++ b/logic/BaseInstance.h @@ -21,7 +21,7 @@ #include <settingsobject.h> #include "inifile.h" -#include "lists/InstVersionList.h" +#include "lists/BaseVersionList.h" class QDialog; class BaseUpdate; @@ -134,7 +134,7 @@ public: * \brief Gets a pointer to this instance's version list. * \return A pointer to the available version list for this instance. */ - virtual InstVersionList *versionList() const; + virtual BaseVersionList *versionList() const; /*! * \brief Gets this instance's settings object. diff --git a/logic/BaseUpdate.cpp b/logic/BaseUpdate.cpp index b086ab14..02b29d32 100644 --- a/logic/BaseUpdate.cpp +++ b/logic/BaseUpdate.cpp @@ -7,7 +7,5 @@ BaseUpdate::BaseUpdate ( BaseInstance* inst, QObject* parent ) : Task ( parent ) void BaseUpdate::updateDownloadProgress(qint64 current, qint64 total) { - // The progress on the current file is current / total - float currentDLProgress = (float) current / (float) total; - setProgress((int)(currentDLProgress * 100)); // convert to percentage + emit progress(current, total); }
\ No newline at end of file diff --git a/logic/InstanceVersion.h b/logic/BaseVersion.h index eecd9c4e..be717fee 100644 --- a/logic/InstanceVersion.h +++ b/logic/BaseVersion.h @@ -19,50 +19,27 @@ /*! * An abstract base class for versions. */ -struct InstVersion +struct BaseVersion { /*! - * Checks if this version is less (older) than the given version. - * \param other The version to compare this one to. - * \return True if this version is older than the given version. - */ - virtual bool operator<(const InstVersion &rhs) const - { - return timestamp < rhs.timestamp; - } - - /*! - * Checks if this version is greater (newer) than the given version. - * \param other The version to compare this one to. - * \return True if this version is newer than the given version. - */ - virtual bool operator>( const InstVersion& rhs ) const - { - return timestamp > rhs.timestamp; - } - - /*! * A string used to identify this version in config files. * This should be unique within the version list or shenanigans will occur. */ - QString descriptor; + virtual QString descriptor() = 0; + /*! * The name of this version as it is displayed to the user. * For example: "1.5.1" */ - QString name; + virtual QString name() = 0; + /*! - * Gets the version's timestamp. - * This is primarily used for sorting versions in a list. + * This should return a string that describes + * the kind of version this is (Stable, Beta, Snapshot, whatever) */ - qint64 timestamp; - - virtual QString typeString() const - { - return "InstVersion"; - } + virtual QString typeString() const = 0; }; -typedef QSharedPointer<InstVersion> InstVersionPtr; +typedef QSharedPointer<BaseVersion> BaseVersionPtr; -Q_DECLARE_METATYPE( InstVersionPtr )
\ No newline at end of file +Q_DECLARE_METATYPE( BaseVersionPtr )
\ No newline at end of file diff --git a/logic/EnabledItemFilter.cpp b/logic/EnabledItemFilter.cpp new file mode 100644 index 00000000..6ecd0271 --- /dev/null +++ b/logic/EnabledItemFilter.cpp @@ -0,0 +1,30 @@ +#include "EnabledItemFilter.h" + +EnabledItemFilter::EnabledItemFilter(QObject* parent) + :QSortFilterProxyModel(parent) +{ + +} + +void EnabledItemFilter::setActive(bool active) +{ + m_active = active; + invalidateFilter(); +} + +bool EnabledItemFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + if(!m_active) + return true; + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + if(sourceModel()->flags(index) & Qt::ItemIsEnabled) + { + return true; + } + return false; +} + +bool EnabledItemFilter::lessThan(const QModelIndex& left, const QModelIndex& right) const +{ + return QSortFilterProxyModel::lessThan(left, right); +} diff --git a/logic/EnabledItemFilter.h b/logic/EnabledItemFilter.h new file mode 100644 index 00000000..cb6d4041 --- /dev/null +++ b/logic/EnabledItemFilter.h @@ -0,0 +1,16 @@ +#pragma once +#include <QSortFilterProxyModel> + +class EnabledItemFilter : public QSortFilterProxyModel +{ + Q_OBJECT +public: + EnabledItemFilter(QObject *parent = 0); + void setActive(bool active); + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const; +private: + bool m_active = false; +};
\ No newline at end of file diff --git a/logic/InstanceFactory.cpp b/logic/InstanceFactory.cpp index f0630568..b5832ce5 100644 --- a/logic/InstanceFactory.cpp +++ b/logic/InstanceFactory.cpp @@ -22,7 +22,7 @@ #include "LegacyInstance.h" #include "OneSixInstance.h" #include "NostalgiaInstance.h" -#include "InstanceVersion.h" +#include "BaseVersion.h" #include "MinecraftVersion.h" #include "inifile.h" @@ -68,7 +68,7 @@ InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst } -InstanceFactory::InstCreateError InstanceFactory::createInstance( BaseInstance*& inst, InstVersionPtr version, const QString& instDir ) +InstanceFactory::InstCreateError InstanceFactory::createInstance( BaseInstance*& inst, BaseVersionPtr version, const QString& instDir ) { QDir rootDir(instDir); @@ -89,19 +89,19 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance( BaseInstance*& case MinecraftVersion::Legacy: m_settings->set("InstanceType", "Legacy"); inst = new LegacyInstance(instDir, m_settings, this); - inst->setIntendedVersionId(version->descriptor); + inst->setIntendedVersionId(version->descriptor()); inst->setShouldUseCustomBaseJar(false); break; case MinecraftVersion::OneSix: m_settings->set("InstanceType", "OneSix"); inst = new OneSixInstance(instDir, m_settings, this); - inst->setIntendedVersionId(version->descriptor); + inst->setIntendedVersionId(version->descriptor()); inst->setShouldUseCustomBaseJar(false); break; case MinecraftVersion::Nostalgia: m_settings->set("InstanceType", "Nostalgia"); inst = new NostalgiaInstance(instDir, m_settings, this); - inst->setIntendedVersionId(version->descriptor); + inst->setIntendedVersionId(version->descriptor()); inst->setShouldUseCustomBaseJar(false); break; default: diff --git a/logic/InstanceFactory.h b/logic/InstanceFactory.h index ed54f520..1c527749 100644 --- a/logic/InstanceFactory.h +++ b/logic/InstanceFactory.h @@ -19,9 +19,9 @@ #include <QMap> #include <QList> -#include "InstanceVersion.h" +#include "BaseVersion.h" -class InstVersion; +class BaseVersion; class BaseInstance; /*! @@ -61,7 +61,7 @@ public: * - InstExists if the given instance directory is already an instance. * - CantCreateDir if the given instance directory cannot be created. */ - InstCreateError createInstance(BaseInstance *&inst, InstVersionPtr version, const QString &instDir); + InstCreateError createInstance(BaseInstance *&inst, BaseVersionPtr version, const QString &instDir); /*! * \brief Loads an instance from the given directory. diff --git a/logic/InstanceLauncher.cpp b/logic/InstanceLauncher.cpp index a0557b37..f2f792c9 100644 --- a/logic/InstanceLauncher.cpp +++ b/logic/InstanceLauncher.cpp @@ -3,7 +3,7 @@ #include <iostream> #include "gui/logindialog.h" -#include "gui/taskdialog.h" +#include "gui/ProgressDialog.h" #include "gui/consolewindow.h" #include "logic/tasks/LoginTask.h" #include "logic/MinecraftProcess.h" @@ -48,7 +48,7 @@ void InstanceLauncher::doLogin ( const QString& errorMsg ) { UserInfo uInfo {loginDlg->getUsername(), loginDlg->getPassword() }; - TaskDialog* tDialog = new TaskDialog ( nullptr ); + ProgressDialog* tDialog = new ProgressDialog ( nullptr ); LoginTask* loginTask = new LoginTask ( uInfo, tDialog ); connect ( loginTask, SIGNAL ( succeeded() ),SLOT ( onLoginComplete() ), Qt::QueuedConnection ); connect ( loginTask, SIGNAL ( failed ( QString ) ),SLOT ( doLogin ( QString ) ), Qt::QueuedConnection ); diff --git a/logic/LegacyUpdate.cpp b/logic/LegacyUpdate.cpp index b8e179a5..0f58e3e3 100644 --- a/logic/LegacyUpdate.cpp +++ b/logic/LegacyUpdate.cpp @@ -34,15 +34,15 @@ void LegacyUpdate::lwjglStart() return; } - auto &list = LWJGLVersionList::get(); - if(!list.isLoaded()) + auto list = MMC->lwjgllist(); + if(!list->isLoaded()) { emitFailed("Too soon! Let the LWJGL list load :)"); return; } setStatus("Downloading new LWJGL."); - auto version = list.getVersion(lwjglVersion); + auto version = list->getVersion(lwjglVersion); if(!version) { emitFailed("Game update failed: the selected LWJGL version is invalid."); @@ -59,7 +59,7 @@ void LegacyUpdate::lwjglStart() QNetworkReply * rep = worker->get ( req ); m_reply = QSharedPointer<QNetworkReply> (rep, &QObject::deleteLater); - connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SIGNAL(progress(qint64,qint64))); connect(worker, SIGNAL(finished(QNetworkReply*)), SLOT(lwjglFinished(QNetworkReply*))); //connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError))); } @@ -97,7 +97,7 @@ void LegacyUpdate::lwjglFinished(QNetworkReply* reply) req.setRawHeader("Host", hostname.toLatin1()); req.setHeader(QNetworkRequest::UserAgentHeader, "Wget/1.14 (linux-gnu)"); QNetworkReply * rep = worker->get(req); - connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SIGNAL(progress(qint64,qint64))); m_reply = QSharedPointer<QNetworkReply> (rep, &QObject::deleteLater); return; } @@ -170,7 +170,7 @@ void LegacyUpdate::extractLwjgl() if (name.contains(nativesDir)) { int lastSlash = name.lastIndexOf('/'); - int lastBackSlash = name.lastIndexOf('/'); + int lastBackSlash = name.lastIndexOf('\\'); if(lastSlash != -1) name = name.mid(lastSlash+1); else if(lastBackSlash != -1) @@ -232,7 +232,7 @@ void LegacyUpdate::jarStart() legacyDownloadJob.reset(dljob); connect(dljob, SIGNAL(succeeded()), SLOT(jarFinished())); connect(dljob, SIGNAL(failed()), SLOT(jarFailed())); - connect(dljob, SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + connect(dljob, SIGNAL(progress(qint64,qint64)), SIGNAL(progress(qint64,qint64))); legacyDownloadJob->start(); } diff --git a/logic/MinecraftVersion.h b/logic/MinecraftVersion.h index 27977262..53c2f5ef 100644 --- a/logic/MinecraftVersion.h +++ b/logic/MinecraftVersion.h @@ -15,17 +15,16 @@ #pragma once -#include "InstanceVersion.h" +#include "BaseVersion.h" #include <QStringList> -struct MinecraftVersion : public InstVersion +struct MinecraftVersion : public BaseVersion { - // From InstVersion: - /* - QString m_descriptor; - QString m_name; - qint64 m_timestamp; - */ + /*! + * Gets the version's timestamp. + * This is primarily used for sorting versions in a list. + */ + qint64 timestamp; /// The URL that this version will be downloaded from. maybe. QString download_url; @@ -44,6 +43,20 @@ struct MinecraftVersion : public InstVersion /// is this a snapshot? bool is_snapshot = false; + QString m_name; + + QString m_descriptor; + + virtual QString descriptor() + { + return m_descriptor; + } + + virtual QString name() + { + return m_name; + } + virtual QString typeString() const { QStringList pre_final; diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp index c926df60..7b038c46 100644 --- a/logic/OneSixInstance.cpp +++ b/logic/OneSixInstance.cpp @@ -214,6 +214,13 @@ bool OneSixInstance::shouldUpdate() const return true; } +bool OneSixInstance::versionIsCustom() +{ + QString verpath_custom = PathCombine(instanceRoot(), "custom.json"); + QFile versionfile(verpath_custom); + return versionfile.exists(); +} + QString OneSixInstance::currentVersionId() const { return intendedVersionId(); @@ -224,6 +231,13 @@ bool OneSixInstance::reloadFullVersion() I_D(OneSixInstance); QString verpath = PathCombine(instanceRoot(), "version.json"); + { + QString verpath_custom = PathCombine(instanceRoot(), "custom.json"); + QFile versionfile(verpath_custom); + if(versionfile.exists()) + verpath = verpath_custom; + } + QFile versionfile(verpath); if(versionfile.exists() && versionfile.open(QIODevice::ReadOnly)) { @@ -264,7 +278,12 @@ bool OneSixInstance::menuActionEnabled ( QString action_name ) const QString OneSixInstance::getStatusbarDescription() { - return "One Six : " + intendedVersionId(); + QString descr = "One Six : " + intendedVersionId(); + if(versionIsCustom()) + { + descr + " (custom)"; + } + return descr; } QString OneSixInstance::loaderModsDir() const diff --git a/logic/OneSixInstance.h b/logic/OneSixInstance.h index a4c67ed1..72bde630 100644 --- a/logic/OneSixInstance.h +++ b/logic/OneSixInstance.h @@ -41,6 +41,8 @@ public: bool reloadFullVersion(); /// get the current full version info QSharedPointer<OneSixVersion> getFullVersion(); + /// is the current version original, or custom? + bool versionIsCustom(); virtual QString defaultBaseJar() const; virtual QString defaultCustomBaseJar() const; diff --git a/logic/OneSixInstance_p.h b/logic/OneSixInstance_p.h index c098c9e2..7b1ca82e 100644 --- a/logic/OneSixInstance_p.h +++ b/logic/OneSixInstance_p.h @@ -2,6 +2,7 @@ #include "BaseInstance_p.h" #include "OneSixVersion.h" +#include "OneSixLibrary.h" #include "ModList.h" struct OneSixInstancePrivate: public BaseInstancePrivate diff --git a/logic/OneSixLibrary.cpp b/logic/OneSixLibrary.cpp new file mode 100644 index 00000000..a45a4aec --- /dev/null +++ b/logic/OneSixLibrary.cpp @@ -0,0 +1,93 @@ +#include "OneSixLibrary.h" +#include "OneSixRule.h" +#include "OpSys.h" +void OneSixLibrary::finalize() +{ + QStringList parts = m_name.split ( ':' ); + QString relative = parts[0]; + relative.replace ( '.','/' ); + relative += '/' + parts[1] + '/' + parts[2] + '/' + parts[1] + '-' + parts[2]; + + if ( !m_is_native ) + relative += ".jar"; + else + { + if ( m_native_suffixes.contains ( currentSystem ) ) + { + relative += "-" + m_native_suffixes[currentSystem] + ".jar"; + } + else + { + // really, bad. + relative += ".jar"; + } + } + + m_decentname = parts[1]; + m_decentversion = parts[2]; + m_storage_path = relative; + m_download_path = m_base_url + relative; + + if ( m_rules.empty() ) + { + m_is_active = true; + } + else + { + RuleAction result = Disallow; + for ( auto rule: m_rules ) + { + RuleAction temp = rule->apply ( this ); + if ( temp != Defer ) + result = temp; + } + m_is_active = ( result == Allow ); + } + if ( m_is_native ) + { + m_is_active = m_is_active && m_native_suffixes.contains ( currentSystem ); + m_decenttype = "Native"; + } + else + { + m_decenttype = "Java"; + } +} + +void OneSixLibrary::setName ( QString name ) +{ + m_name = name; +} +void OneSixLibrary::setBaseUrl ( QString base_url ) +{ + m_base_url = base_url; +} +void OneSixLibrary::setIsNative() +{ + m_is_native = true; +} +void OneSixLibrary::addNative ( OpSys os, QString suffix ) +{ + m_is_native = true; + m_native_suffixes[os] = suffix; +} +void OneSixLibrary::setRules ( QList< QSharedPointer< Rule > > rules ) +{ + m_rules = rules; +} +bool OneSixLibrary::isActive() +{ + return m_is_active; +} +bool OneSixLibrary::isNative() +{ + return m_is_native; +} +QString OneSixLibrary::downloadPath() +{ + return m_download_path; +} +QString OneSixLibrary::storagePath() +{ + return m_storage_path; +} diff --git a/logic/OneSixLibrary.h b/logic/OneSixLibrary.h new file mode 100644 index 00000000..ac16d3d3 --- /dev/null +++ b/logic/OneSixLibrary.h @@ -0,0 +1,90 @@ +#pragma once +#include <QString> +#include <QStringList> +#include <QMap> +#include <QSharedPointer> +#include "OpSys.h" + +class Rule; + +class OneSixLibrary +{ +private: + // basic values used internally (so far) + QString m_name; + QString m_base_url; + QList<QSharedPointer<Rule> > m_rules; + + // derived values used for real things + /// a decent name fit for display + QString m_decentname; + /// a decent version fit for display + QString m_decentversion; + /// a decent type fit for display + QString m_decenttype; + /// where to store the lib locally + QString m_storage_path; + /// where to download the lib from + QString m_download_path; + /// is this lib actually active on the current OS? + bool m_is_active; + /// is the library a native? + bool m_is_native; + /// native suffixes per OS + QMap<OpSys, QString> m_native_suffixes; +public: + QStringList extract_excludes; + +public: + /// Constructor + OneSixLibrary(QString name) + { + m_is_native = false; + m_is_active = false; + m_name = name; + m_base_url = "https://s3.amazonaws.com/Minecraft.Download/libraries/"; + } + + /** + * finalize the library, processing the input values into derived values and state + * + * This SHALL be called after all the values are parsed or after any further change. + */ + void finalize(); + + /// Set the library composite name + void setName(QString name); + /// get a decent-looking name + QString name() + { + return m_decentname; + } + /// get a decent-looking version + QString version() + { + return m_decentversion; + } + /// what kind of library is it? (for display) + QString type() + { + return m_decenttype; + } + /// Set the url base for downloads + void setBaseUrl(QString base_url); + + /// Call this to mark the library as 'native' (it's a zip archive with DLLs) + void setIsNative(); + /// Attach a name suffix to the specified OS native + void addNative(OpSys os, QString suffix); + /// Set the load rules + void setRules(QList<QSharedPointer<Rule> > rules); + + /// Returns true if the library should be loaded (or extracted, in case of natives) + bool isActive(); + /// Returns true if the library is native + bool isNative(); + /// Get the URL to download the library from + QString downloadPath(); + /// Get the relative path where the library should be saved + QString storagePath(); +}; diff --git a/logic/OneSixRule.cpp b/logic/OneSixRule.cpp new file mode 100644 index 00000000..85f7d434 --- /dev/null +++ b/logic/OneSixRule.cpp @@ -0,0 +1,10 @@ +#include "OneSixRule.h" + +RuleAction RuleAction_fromString(QString name) +{ + if(name == "allow") + return Allow; + if(name == "disallow") + return Disallow; + return Defer; +}
\ No newline at end of file diff --git a/logic/OneSixRule.h b/logic/OneSixRule.h new file mode 100644 index 00000000..465c963f --- /dev/null +++ b/logic/OneSixRule.h @@ -0,0 +1,70 @@ +#pragma once +#include <QString> +#include <QSharedPointer> + +class OneSixLibrary; +#include "OneSixLibrary.h" + +enum RuleAction +{ + Allow, + Disallow, + Defer +}; + +RuleAction RuleAction_fromString(QString); + +class Rule +{ +protected: + RuleAction m_result; + virtual bool applies(OneSixLibrary * parent) = 0; +public: + Rule(RuleAction result) + :m_result(result) {} + virtual ~Rule(){}; + RuleAction apply(OneSixLibrary * parent) + { + if(applies(parent)) + return m_result; + else + return Defer; + }; +}; + +class OsRule : public Rule +{ +private: + // the OS + OpSys m_system; + // the OS version regexp + QString m_version_regexp; +protected: + virtual bool applies ( OneSixLibrary* ) + { + return (m_system == currentSystem); + } + OsRule(RuleAction result, OpSys system, QString version_regexp) + : Rule(result), m_system(system), m_version_regexp(version_regexp) {} +public: + static QSharedPointer<OsRule> create(RuleAction result, OpSys system, QString version_regexp) + { + return QSharedPointer<OsRule> (new OsRule(result, system, version_regexp)); + } +}; + +class ImplicitRule : public Rule +{ +protected: + virtual bool applies ( OneSixLibrary* ) + { + return true; + } + ImplicitRule(RuleAction result) + : Rule(result) {} +public: + static QSharedPointer<ImplicitRule> create(RuleAction result) + { + return QSharedPointer<ImplicitRule> (new ImplicitRule(result)); + } +}; diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp index ce71bde0..298ad28a 100644 --- a/logic/OneSixUpdate.cpp +++ b/logic/OneSixUpdate.cpp @@ -28,6 +28,7 @@ #include "lists/MinecraftVersionList.h" #include "VersionFactory.h" #include "OneSixVersion.h" +#include "OneSixLibrary.h" #include "OneSixInstance.h" #include "pathutils.h" @@ -48,7 +49,7 @@ void OneSixUpdate::executeTask() } // Get a pointer to the version object that corresponds to the instance's version. - targetVersion = MinecraftVersionList::getMainList().findVersion(intendedVersion).dynamicCast<MinecraftVersion>(); + targetVersion = MMC->minecraftlist()->findVersion(intendedVersion).dynamicCast<MinecraftVersion>(); if(targetVersion == nullptr) { // don't do anything if it was invalid @@ -71,44 +72,59 @@ void OneSixUpdate::versionFileStart() setStatus("Getting the version files from Mojang."); QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/"); - urlstr += targetVersion->descriptor + "/" + targetVersion->descriptor + ".json"; + urlstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".json"; auto job = new DownloadJob("Version index"); job->add(QUrl(urlstr)); specificVersionDownloadJob.reset(job); connect(specificVersionDownloadJob.data(), SIGNAL(succeeded()), SLOT(versionFileFinished())); connect(specificVersionDownloadJob.data(), SIGNAL(failed()), SLOT(versionFileFailed())); - connect(specificVersionDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + connect(specificVersionDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SIGNAL(progress(qint64,qint64))); specificVersionDownloadJob->start(); } void OneSixUpdate::versionFileFinished() { DownloadPtr DlJob = specificVersionDownloadJob->first(); + OneSixInstance * inst = (OneSixInstance *) m_inst; - QString version_id = targetVersion->descriptor; + QString version_id = targetVersion->descriptor(); QString inst_dir = m_inst->instanceRoot(); // save the version file in $instanceId/version.json { QString version1 = PathCombine(inst_dir, "/version.json"); ensureFilePathExists(version1); // FIXME: detect errors here, download to a temp file, swap - QFile vfile1 (version1); - vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly ); - vfile1.write(DlJob.dynamicCast<ByteArrayDownload>()->m_data); - vfile1.close(); + QSaveFile vfile1 (version1); + if(!vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly )) + { + emitFailed("Can't open " + version1 + " for writing."); + return; + } + auto data = DlJob.dynamicCast<ByteArrayDownload>()->m_data; + qint64 actual = 0; + if((actual = vfile1.write(data)) != data.size()) + { + emitFailed("Failed to write into " + version1 + ". Written " + actual + " out of " + data.size() + '.'); + return; + } + if(!vfile1.commit()) + { + emitFailed("Can't commit changes to " + version1); + return; + } } // the version is downloaded safely. update is 'done' at this point m_inst->setShouldUpdate(false); - // save the version file in versions/$version/$version.json - /* - //QString version2 = QString("versions/") + version_id + "/" + version_id + ".json"; - //ensurePathExists(version2); - //QFile vfile2 (version2); - //vfile2.open(QIODevice::Truncate | QIODevice::WriteOnly ); - //vfile2.write(DlJob->m_data); - //vfile2.close(); - */ + + // delete any custom version inside the instance (it's no longer relevant, we did an update) + QString custom = PathCombine(inst_dir, "/custom.json"); + QFile finfo(custom); + if(finfo.exists()) + { + finfo.remove(); + } + inst->reloadFullVersion(); jarlibStart(); } @@ -155,7 +171,7 @@ void OneSixUpdate::jarlibStart() } connect(jarlibDownloadJob.data(), SIGNAL(succeeded()), SLOT(jarlibFinished())); connect(jarlibDownloadJob.data(), SIGNAL(failed()), SLOT(jarlibFailed())); - connect(jarlibDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + connect(jarlibDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SIGNAL(progress(qint64,qint64))); jarlibDownloadJob->start(); } diff --git a/logic/OneSixVersion.cpp b/logic/OneSixVersion.cpp index 56e272e2..dc1b5d6f 100644 --- a/logic/OneSixVersion.cpp +++ b/logic/OneSixVersion.cpp @@ -1,132 +1,101 @@ #include "OneSixVersion.h" +#include "OneSixLibrary.h" -RuleAction RuleAction_fromString(QString name) +QList<QSharedPointer<OneSixLibrary> > OneSixVersion::getActiveNormalLibs() { - if(name == "allow") - return Allow; - if(name == "disallow") - return Disallow; - return Defer; + QList<QSharedPointer<OneSixLibrary> > output; + for ( auto lib: libraries ) + { + if (lib->isActive() && !lib->isNative()) + { + output.append(lib); + } + } + return output; } -OpSys OpSys_fromString(QString name) +QList<QSharedPointer<OneSixLibrary> > OneSixVersion::getActiveNativeLibs() { - if(name == "linux") - return Os_Linux; - if(name == "windows") - return Os_Windows; - if(name == "osx") - return Os_OSX; - return Os_Other; + QList<QSharedPointer<OneSixLibrary> > output; + for ( auto lib: libraries ) + { + if (lib->isActive() && lib->isNative()) + { + output.append(lib); + } + } + return output; } -void Library::finalize() + +QVariant OneSixVersion::data(const QModelIndex& index, int role) const { - QStringList parts = m_name.split ( ':' ); - QString relative = parts[0]; - relative.replace ( '.','/' ); - relative += '/' + parts[1] + '/' + parts[2] + '/' + parts[1] + '-' + parts[2]; - if ( !m_is_native ) - relative += ".jar"; - else + if(!index.isValid()) + return QVariant(); + + int row = index.row(); + int column = index.column(); + + if(row < 0 || row >= libraries.size()) + return QVariant(); + + if(role == Qt::DisplayRole) { - if ( m_native_suffixes.contains ( currentSystem ) ) - { - relative += "-" + m_native_suffixes[currentSystem] + ".jar"; - } - else + switch(column) { - // really, bad. - relative += ".jar"; + case 0: + return libraries[row]->name(); + case 1: + return libraries[row]->type(); + case 2: + return libraries[row]->version(); + default: + return QVariant(); } } - m_storage_path = relative; - m_download_path = m_base_url + relative; + return QVariant(); +} - if ( m_rules.empty() ) +Qt::ItemFlags OneSixVersion::flags(const QModelIndex& index) const +{ + if(!index.isValid()) + return Qt::NoItemFlags; + int row = index.row(); + if(libraries[row]->isActive()) { - m_is_active = true; + return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren; } else { - RuleAction result = Disallow; - for ( auto rule: m_rules ) - { - RuleAction temp = rule->apply ( this ); - if ( temp != Defer ) - result = temp; - } - m_is_active = ( result == Allow ); + return Qt::ItemNeverHasChildren; } - if ( m_is_native ) - { - m_is_active = m_is_active && m_native_suffixes.contains ( currentSystem ); - } -} - -void Library::setName ( QString name ) -{ - m_name = name; -} -void Library::setBaseUrl ( QString base_url ) -{ - m_base_url = base_url; -} -void Library::setIsNative() -{ - m_is_native = true; -} -void Library::addNative ( OpSys os, QString suffix ) -{ - m_is_native = true; - m_native_suffixes[os] = suffix; -} -void Library::setRules ( QList< QSharedPointer< Rule > > rules ) -{ - m_rules = rules; -} -bool Library::isActive() -{ - return m_is_active; -} -bool Library::isNative() -{ - return m_is_native; -} -QString Library::downloadPath() -{ - return m_download_path; -} -QString Library::storagePath() -{ - return m_storage_path; + //return QAbstractListModel::flags(index); } -QList<QSharedPointer<Library> > OneSixVersion::getActiveNormalLibs() +QVariant OneSixVersion::headerData ( int section, Qt::Orientation orientation, int role ) const { - QList<QSharedPointer<Library> > output; - for ( auto lib: libraries ) + if (role != Qt::DisplayRole || orientation != Qt::Horizontal) + return QVariant(); + switch (section) { - if (lib->isActive() && !lib->isNative()) - { - output.append(lib); - } + case 0: + return QString("Name"); + case 1: + return QString("Type"); + case 2: + return QString("Version"); + default: + return QString(); } - return output; } -QList<QSharedPointer<Library> > OneSixVersion::getActiveNativeLibs() +int OneSixVersion::rowCount(const QModelIndex& parent) const { - QList<QSharedPointer<Library> > output; - for ( auto lib: libraries ) - { - if (lib->isActive() && lib->isNative()) - { - output.append(lib); - } - } - return output; + return libraries.size(); } - +int OneSixVersion::columnCount(const QModelIndex& parent) const +{ + return 3; +} diff --git a/logic/OneSixVersion.h b/logic/OneSixVersion.h index 89b7c911..6a6a5b4b 100644 --- a/logic/OneSixVersion.h +++ b/logic/OneSixVersion.h @@ -1,154 +1,15 @@ #pragma once #include <QtCore> +class OneSixLibrary; -class Library; - -enum OpSys -{ - Os_Windows, - Os_Linux, - Os_OSX, - Os_Other -}; - -OpSys OpSys_fromString(QString); - -#ifdef Q_OS_WIN32 - #define currentSystem Os_Windows -#else - #ifdef Q_OS_MAC - #define currentSystem Os_OSX - #else - #define currentSystem Os_Linux - #endif -#endif -enum RuleAction -{ - Allow, - Disallow, - Defer -}; - -RuleAction RuleAction_fromString(QString); - -class Rule -{ -protected: - RuleAction m_result; - virtual bool applies(Library * parent) = 0; -public: - Rule(RuleAction result) - :m_result(result) {} - virtual ~Rule(){}; - RuleAction apply(Library * parent) - { - if(applies(parent)) - return m_result; - else - return Defer; - }; -}; - -class OsRule : public Rule +class OneSixVersion : public QAbstractListModel { -private: - // the OS - OpSys m_system; - // the OS version regexp - QString m_version_regexp; -protected: - virtual bool applies ( Library* ) - { - return (m_system == currentSystem); - } - OsRule(RuleAction result, OpSys system, QString version_regexp) - : Rule(result), m_system(system), m_version_regexp(version_regexp) {} public: - static QSharedPointer<OsRule> create(RuleAction result, OpSys system, QString version_regexp) - { - return QSharedPointer<OsRule> (new OsRule(result, system, version_regexp)); - } -}; - -class ImplicitRule : public Rule -{ -protected: - virtual bool applies ( Library* ) - { - return true; - } - ImplicitRule(RuleAction result) - : Rule(result) {} -public: - static QSharedPointer<ImplicitRule> create(RuleAction result) - { - return QSharedPointer<ImplicitRule> (new ImplicitRule(result)); - } -}; - -class Library -{ -private: - // basic values used internally (so far) - QString m_name; - QString m_base_url; - QList<QSharedPointer<Rule> > m_rules; - - // derived values used for real things - /// where to store the lib locally - QString m_storage_path; - /// where to download the lib from - QString m_download_path; - /// is this lib actually active on the current OS? - bool m_is_active; - /// is the library a native? - bool m_is_native; - /// native suffixes per OS - QMap<OpSys, QString> m_native_suffixes; -public: - QStringList extract_excludes; - -public: - /// Constructor - Library(QString name) - { - m_is_native = false; - m_is_native = false; - m_name = name; - m_base_url = "https://s3.amazonaws.com/Minecraft.Download/libraries/"; - } - - /** - * finalize the library, processing the input values into derived values and state - * - * This SHALL be called after all the values are parsed or after any further change. - */ - void finalize(); - - /// Set the library composite name - void setName(QString name); - /// Set the url base for downloads - void setBaseUrl(QString base_url); - /// Call this to mark the library as 'native' (it's a zip archive with DLLs) - void setIsNative(); - /// Attach a name suffix to the specified OS native - void addNative(OpSys os, QString suffix); - /// Set the load rules - void setRules(QList<QSharedPointer<Rule> > rules); - - /// Returns true if the library should be loaded (or extracted, in case of natives) - bool isActive(); - /// Returns true if the library is native - bool isNative(); - /// Get the URL to download the library from - QString downloadPath(); - /// Get the relative path where the library should be saved - QString storagePath(); -}; - - -class OneSixVersion -{ + virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const; + virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const; + virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; + virtual int columnCount ( const QModelIndex& parent ) const; + virtual Qt::ItemFlags flags(const QModelIndex& index) const; public: /// the ID - determines which jar to use! ACTUALLY IMPORTANT! QString id; @@ -180,7 +41,7 @@ public: QString mainClass; /// the list of libs - both active and inactive, native and java - QList<QSharedPointer<Library> > libraries; + QList<QSharedPointer<OneSixLibrary> > libraries; /* FIXME: add support for those rules here? Looks like a pile of quick hacks to me though. @@ -203,11 +64,12 @@ public: // QList<Rule> rules; public: + OneSixVersion() { minimumLauncherVersion = 0xDEADBEEF; } - QList<QSharedPointer<Library> > getActiveNormalLibs(); - QList<QSharedPointer<Library> > getActiveNativeLibs(); -};
\ No newline at end of file + QList<QSharedPointer<OneSixLibrary> > getActiveNormalLibs(); + QList<QSharedPointer<OneSixLibrary> > getActiveNativeLibs(); +}; diff --git a/logic/OpSys.cpp b/logic/OpSys.cpp new file mode 100644 index 00000000..559479fd --- /dev/null +++ b/logic/OpSys.cpp @@ -0,0 +1,12 @@ +#include "OpSys.h" + +OpSys OpSys_fromString(QString name) +{ + if(name == "linux") + return Os_Linux; + if(name == "windows") + return Os_Windows; + if(name == "osx") + return Os_OSX; + return Os_Other; +}
\ No newline at end of file diff --git a/logic/OpSys.h b/logic/OpSys.h new file mode 100644 index 00000000..c68c437a --- /dev/null +++ b/logic/OpSys.h @@ -0,0 +1,21 @@ +#pragma once +#include <QString> +enum OpSys +{ + Os_Windows, + Os_Linux, + Os_OSX, + Os_Other +}; + +OpSys OpSys_fromString(QString); + +#ifdef Q_OS_WIN32 + #define currentSystem Os_Windows +#else + #ifdef Q_OS_MAC + #define currentSystem Os_OSX + #else + #define currentSystem Os_Linux + #endif +#endif
\ No newline at end of file diff --git a/logic/VersionFactory.cpp b/logic/VersionFactory.cpp index 71c4d747..4fa5ad3f 100644 --- a/logic/VersionFactory.cpp +++ b/logic/VersionFactory.cpp @@ -1,5 +1,6 @@ #include "VersionFactory.h" #include "OneSixVersion.h" +#include "OneSixRule.h" // Library rules (if any) QList<QSharedPointer<Rule> > FullVersionFactory::parse4rules(QJsonObject & baseObj) @@ -103,7 +104,7 @@ QSharedPointer<OneSixVersion> FullVersionFactory::parse4(QJsonObject root, QShar auto nameVal = libObj.value("name"); if(!nameVal.isString()) continue; - QSharedPointer<Library> library(new Library(nameVal.toString())); + QSharedPointer<OneSixLibrary> library(new OneSixLibrary(nameVal.toString())); auto urlVal = libObj.value("url"); if(urlVal.isString()) diff --git a/logic/lists/InstVersionList.cpp b/logic/lists/BaseVersionList.cpp index 7dc67155..61da5eeb 100644 --- a/logic/lists/InstVersionList.cpp +++ b/logic/lists/BaseVersionList.cpp @@ -13,33 +13,33 @@ * limitations under the License. */ -#include "logic/lists/InstVersionList.h" -#include "logic/InstanceVersion.h" +#include "logic/lists/BaseVersionList.h" +#include "logic/BaseVersion.h" -InstVersionList::InstVersionList(QObject *parent) : +BaseVersionList::BaseVersionList(QObject *parent) : QAbstractListModel(parent) { } -InstVersionPtr InstVersionList::findVersion( const QString& descriptor ) +BaseVersionPtr BaseVersionList::findVersion( const QString& descriptor ) { for (int i = 0; i < count(); i++) { - if (at(i)->descriptor == descriptor) + if (at(i)->descriptor() == descriptor) return at(i); } - return InstVersionPtr(); + return BaseVersionPtr(); } -InstVersionPtr InstVersionList::getLatestStable() const +BaseVersionPtr BaseVersionList::getLatestStable() const { if (count() <= 0) - return InstVersionPtr(); + return BaseVersionPtr(); else return at(0); } -QVariant InstVersionList::data(const QModelIndex &index, int role) const +QVariant BaseVersionList::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); @@ -48,7 +48,7 @@ QVariant InstVersionList::data(const QModelIndex &index, int role) const return QVariant(); - InstVersionPtr version = at(index.row()); + BaseVersionPtr version = at(index.row()); switch (role) { @@ -56,20 +56,17 @@ QVariant InstVersionList::data(const QModelIndex &index, int role) const switch (index.column()) { case NameColumn: - return version->name; + return version->name(); case TypeColumn: return version->typeString(); - case TimeColumn: - return version->timestamp; - default: return QVariant(); } case Qt::ToolTipRole: - return version->descriptor; + return version->descriptor(); case VersionPointerRole: return qVariantFromValue(version); @@ -79,7 +76,7 @@ QVariant InstVersionList::data(const QModelIndex &index, int role) const } } -QVariant InstVersionList::headerData(int section, Qt::Orientation orientation, int role) const +QVariant BaseVersionList::headerData(int section, Qt::Orientation orientation, int role) const { switch (role) { @@ -91,9 +88,6 @@ QVariant InstVersionList::headerData(int section, Qt::Orientation orientation, i case TypeColumn: return "Type"; - - case TimeColumn: - return "Time"; default: return QVariant(); @@ -117,13 +111,13 @@ QVariant InstVersionList::headerData(int section, Qt::Orientation orientation, i } } -int InstVersionList::rowCount(const QModelIndex &parent) const +int BaseVersionList::rowCount(const QModelIndex &parent) const { // Return count return count(); } -int InstVersionList::columnCount(const QModelIndex &parent) const +int BaseVersionList::columnCount(const QModelIndex &parent) const { return 2; } diff --git a/logic/lists/InstVersionList.h b/logic/lists/BaseVersionList.h index bc6aa5d4..d37431ed 100644 --- a/logic/lists/InstVersionList.h +++ b/logic/lists/BaseVersionList.h @@ -20,7 +20,7 @@ #include <QAbstractListModel> #include <QSharedPointer> -#include "logic/InstanceVersion.h" +#include "logic/BaseVersion.h" class Task; @@ -36,7 +36,7 @@ class Task; * all have a default implementation, but they can be overridden by plugins to * change the behavior of the list. */ -class InstVersionList : public QAbstractListModel +class BaseVersionList : public QAbstractListModel { Q_OBJECT public: @@ -57,7 +57,7 @@ public: TimeColumn }; - explicit InstVersionList(QObject *parent = 0); + explicit BaseVersionList(QObject *parent = 0); /*! * \brief Gets a task that will reload the version list. @@ -71,7 +71,7 @@ public: virtual bool isLoaded() = 0; //! Gets the version at the given index. - virtual const InstVersionPtr at(int i) const = 0; + virtual const BaseVersionPtr at(int i) const = 0; //! Returns the number of versions in the list. virtual int count() const = 0; @@ -90,14 +90,14 @@ public: * \return A const pointer to the version with the given descriptor. NULL if * one doesn't exist. */ - virtual InstVersionPtr findVersion(const QString &descriptor); + virtual BaseVersionPtr findVersion(const QString &descriptor); /*! * \brief Gets the latest stable version of this instance type. * This is the version that will be selected by default. * By default, this is simply the first version in the list. */ - virtual InstVersionPtr getLatestStable() const; + virtual BaseVersionPtr getLatestStable() const; /*! * Sorts the version list. @@ -117,5 +117,5 @@ protected slots: * then copies the versions and sets their parents correctly. * \param versions List of versions whose parents should be set. */ - virtual void updateListData(QList<InstVersionPtr > versions) = 0; + virtual void updateListData(QList<BaseVersionPtr > versions) = 0; }; diff --git a/logic/lists/ForgeVersionList.cpp b/logic/lists/ForgeVersionList.cpp new file mode 100644 index 00000000..412c04fe --- /dev/null +++ b/logic/lists/ForgeVersionList.cpp @@ -0,0 +1,269 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ForgeVersionList.h" +#include <logic/net/DownloadJob.h> +#include "MultiMC.h" + +#include <QtNetwork> + +#include <QtXml> + +#include <QRegExp> + +#define JSON_URL "http://files.minecraftforge.net/minecraftforge/json" + + +ForgeVersionList::ForgeVersionList(QObject* parent): BaseVersionList(parent) +{ + +} + +Task *ForgeVersionList::getLoadTask() +{ + return new ForgeListLoadTask(this); +} + +bool ForgeVersionList::isLoaded() +{ + return m_loaded; +} + +const BaseVersionPtr ForgeVersionList::at(int i) const +{ + return m_vlist.at(i); +} + +int ForgeVersionList::count() const +{ + return m_vlist.count(); +} + +int ForgeVersionList::columnCount(const QModelIndex& parent) const +{ + return 3; +} + +QVariant ForgeVersionList::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() > count()) + return QVariant(); + + auto version = m_vlist[index.row()].dynamicCast<ForgeVersion>(); + switch (role) + { + case Qt::DisplayRole: + switch (index.column()) + { + case 0: + return version->name(); + + case 1: + return version->mcver; + + case 2: + return version->typeString(); + default: + return QVariant(); + } + + case Qt::ToolTipRole: + return version->descriptor(); + + case VersionPointerRole: + return qVariantFromValue(m_vlist[index.row()]); + + default: + return QVariant(); + } +} + +QVariant ForgeVersionList::headerData(int section, Qt::Orientation orientation, int role) const +{ + switch (role) + { + case Qt::DisplayRole: + switch (section) + { + case 0: + return "Version"; + + case 1: + return "Minecraft"; + + case 2: + return "Type"; + + default: + return QVariant(); + } + + case Qt::ToolTipRole: + switch (section) + { + case 0: + return "The name of the version."; + + case 1: + return "Minecraft version"; + + case 2: + return "The version's type."; + + default: + return QVariant(); + } + + default: + return QVariant(); + } +} + +BaseVersionPtr ForgeVersionList::getLatestStable() const +{ + return BaseVersionPtr(); +} + +void ForgeVersionList::updateListData(QList<BaseVersionPtr > versions) +{ + beginResetModel(); + m_vlist = versions; + m_loaded = true; + endResetModel(); + // NOW SORT!! + // sort(); +} + +void ForgeVersionList::sort() +{ + // NO-OP for now +} + + +ForgeListLoadTask::ForgeListLoadTask(ForgeVersionList* vlist): Task() +{ + m_list = vlist; +} + + +void ForgeListLoadTask::executeTask() +{ + auto job = new DownloadJob("Version index"); + job->add(QUrl(JSON_URL)); + listJob.reset(job); + connect(listJob.data(), SIGNAL(succeeded()), SLOT(list_downloaded())); + connect(listJob.data(), SIGNAL(failed()), SLOT(versionFileFailed())); + connect(listJob.data(), SIGNAL(progress(qint64,qint64)), SIGNAL(progress(qint64,qint64))); + listJob->start(); +} + +void ForgeListLoadTask::list_downloaded() +{ + auto DlJob = listJob->first(); + auto data = DlJob.dynamicCast<ByteArrayDownload>()->m_data; + + + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); + DlJob.reset(); + + if (jsonError.error != QJsonParseError::NoError) + { + emitFailed("Error parsing version list JSON:" + jsonError.errorString()); + return; + } + + if(!jsonDoc.isObject()) + { + emitFailed("Error parsing version list JSON: jsonDoc is not an object"); + return; + } + + QJsonObject root = jsonDoc.object(); + + // Now, get the array of versions. + if(!root.value("builds").isArray()) + { + emitFailed("Error parsing version list JSON: version list object is missing 'builds' array"); + return; + } + QJsonArray builds = root.value("builds").toArray(); + + QList<BaseVersionPtr > tempList; + for (int i = 0; i < builds.count(); i++) + { + // Load the version info. + if(!builds[i].isObject()) + { + //FIXME: log this somewhere + continue; + } + QJsonObject obj = builds[i].toObject(); + int build_nr = obj.value("build").toDouble(0); + if(!build_nr) + continue; + QJsonArray files = obj.value("files").toArray(); + QString url, jobbuildver, mcver, buildtype, filename; + QString changelog_url, installer_url; + bool valid = false; + for(int j = 0; j < files.count(); j++) + { + if(!files[j].isObject()) + continue; + QJsonObject file = files[j].toObject(); + buildtype = file.value("buildtype").toString(); + if((buildtype == "client" || buildtype == "universal") && !valid) + { + mcver = file.value("mcver").toString(); + url = file.value("url").toString(); + jobbuildver = file.value("jobbuildver").toString(); + int lastSlash = url.lastIndexOf('/'); + filename = url.mid(lastSlash+1); + valid = true; + } + else if(buildtype == "changelog") + { + QString ext = file.value("ext").toString(); + if(ext.isEmpty()) + continue; + changelog_url = file.value("url").toString(); + } + else if(buildtype == "installer") + { + installer_url = file.value("url").toString(); + } + } + if(valid) + { + // Now, we construct the version object and add it to the list. + QSharedPointer<ForgeVersion> fVersion(new ForgeVersion()); + fVersion->universal_url = url; + fVersion->changelog_url = changelog_url; + fVersion->installer_url = installer_url; + fVersion->jobbuildver = jobbuildver; + fVersion->mcver = mcver; + fVersion->filename = filename; + fVersion->m_buildnr = build_nr; + tempList.append(fVersion); + } + } + m_list->updateListData(tempList); + + emitSucceeded(); + return; +} diff --git a/logic/lists/ForgeVersionList.h b/logic/lists/ForgeVersionList.h new file mode 100644 index 00000000..ca6b27bc --- /dev/null +++ b/logic/lists/ForgeVersionList.h @@ -0,0 +1,102 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <QObject> +#include <QAbstractListModel> +#include <QSharedPointer> +#include <QUrl> + +#include <QNetworkReply> +#include "BaseVersionList.h" +#include "logic/tasks/Task.h" +#include "logic/net/DownloadJob.h" + +class ForgeVersion; +typedef QSharedPointer<ForgeVersion> ForgeVersionPtr; + +struct ForgeVersion : public BaseVersion +{ + virtual QString descriptor() + { + return filename; + }; + virtual QString name() + { + return "Forge " + jobbuildver; + }; + virtual QString typeString() const + { + if(installer_url.isEmpty()) + return "Universal"; + else + return "Installer"; + }; + + int m_buildnr = 0; + QString universal_url; + QString changelog_url; + QString installer_url; + QString jobbuildver; + QString mcver; + QString filename; +}; + +class ForgeVersionList : public BaseVersionList +{ + Q_OBJECT +public: + friend class ForgeListLoadTask; + + explicit ForgeVersionList(QObject *parent = 0); + + virtual Task *getLoadTask(); + virtual bool isLoaded(); + virtual const BaseVersionPtr at(int i) const; + virtual int count() const; + virtual void sort(); + + virtual BaseVersionPtr getLatestStable() const; + + virtual QVariant data(const QModelIndex& index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual int columnCount(const QModelIndex& parent) const; + +protected: + QList<BaseVersionPtr> m_vlist; + + bool m_loaded; + +protected slots: + virtual void updateListData(QList<BaseVersionPtr > versions); +}; + +class ForgeListLoadTask : public Task +{ + Q_OBJECT + +public: + explicit ForgeListLoadTask(ForgeVersionList *vlist); + + virtual void executeTask(); + +protected slots: + void list_downloaded(); + +protected: + DownloadJobPtr listJob; + ForgeVersionList *m_list; +}; diff --git a/logic/lists/LwjglVersionList.cpp b/logic/lists/LwjglVersionList.cpp index d7826a82..b3e2dab4 100644 --- a/logic/lists/LwjglVersionList.cpp +++ b/logic/lists/LwjglVersionList.cpp @@ -24,14 +24,6 @@ #define RSS_URL "http://sourceforge.net/api/file/index/project-id/58488/mtime/desc/rss" -LWJGLVersionList mainVersionList; - -LWJGLVersionList &LWJGLVersionList::get() -{ - return mainVersionList; -} - - LWJGLVersionList::LWJGLVersionList(QObject *parent) : QAbstractListModel(parent) { diff --git a/logic/lists/LwjglVersionList.h b/logic/lists/LwjglVersionList.h index 638a0b67..23e92a1a 100644 --- a/logic/lists/LwjglVersionList.h +++ b/logic/lists/LwjglVersionList.h @@ -53,8 +53,6 @@ class LWJGLVersionList : public QAbstractListModel public: explicit LWJGLVersionList(QObject *parent = 0); - static LWJGLVersionList &get(); - bool isLoaded() { return m_vlist.length() > 0; } const PtrLWJGLVersion getVersion(const QString &versionName); diff --git a/logic/lists/MinecraftVersionList.cpp b/logic/lists/MinecraftVersionList.cpp index 42fb1b50..86ba0792 100644 --- a/logic/lists/MinecraftVersionList.cpp +++ b/logic/lists/MinecraftVersionList.cpp @@ -34,10 +34,8 @@ #define ASSETS_URLBASE "http://assets.minecraft.net/" #define MCN_URLBASE "http://sonicrules.org/mcnweb.py" -MinecraftVersionList mcVList; - MinecraftVersionList::MinecraftVersionList(QObject *parent) : - InstVersionList(parent) + BaseVersionList(parent) { } @@ -52,7 +50,7 @@ bool MinecraftVersionList::isLoaded() return m_loaded; } -const InstVersionPtr MinecraftVersionList::at(int i) const +const BaseVersionPtr MinecraftVersionList::at(int i) const { return m_vlist.at(i); } @@ -62,11 +60,11 @@ int MinecraftVersionList::count() const return m_vlist.count(); } -bool cmpVersions(InstVersionPtr first, InstVersionPtr second) +bool cmpVersions(BaseVersionPtr first, BaseVersionPtr second) { - const InstVersion & left = *first; - const InstVersion & right = *second; - return left > right; + auto left = first.dynamicCast<MinecraftVersion>(); + auto right = second.dynamicCast<MinecraftVersion>(); + return left->timestamp > right->timestamp; } void MinecraftVersionList::sort() @@ -76,7 +74,7 @@ void MinecraftVersionList::sort() endResetModel(); } -InstVersionPtr MinecraftVersionList::getLatestStable() const +BaseVersionPtr MinecraftVersionList::getLatestStable() const { for (int i = 0; i < m_vlist.length(); i++) { @@ -86,15 +84,10 @@ InstVersionPtr MinecraftVersionList::getLatestStable() const return m_vlist.at(i); } } - return InstVersionPtr(); -} - -MinecraftVersionList &MinecraftVersionList::getMainList() -{ - return mcVList; + return BaseVersionPtr(); } -void MinecraftVersionList::updateListData(QList<InstVersionPtr > versions) +void MinecraftVersionList::updateListData(QList<BaseVersionPtr > versions) { beginResetModel(); m_vlist = versions; @@ -214,7 +207,7 @@ void MCVListLoadTask::list_downloaded() } QJsonArray versions = root.value("versions").toArray(); - QList<InstVersionPtr > tempList; + QList<BaseVersionPtr > tempList; for (int i = 0; i < versions.count(); i++) { bool is_snapshot = false; @@ -280,7 +273,7 @@ void MCVListLoadTask::list_downloaded() // Now, we construct the version object and add it to the list. QSharedPointer<MinecraftVersion> mcVersion(new MinecraftVersion()); - mcVersion->name = mcVersion->descriptor = versionID; + mcVersion->m_name = mcVersion->m_descriptor = versionID; mcVersion->timestamp = versionTime.toMSecsSinceEpoch(); mcVersion->download_url = dlUrl; mcVersion->is_latest = is_latest; @@ -293,8 +286,3 @@ void MCVListLoadTask::list_downloaded() emitSucceeded(); return; } - -// FIXME: we should have a local cache of the version list and a local cache of version data -bool MCVListLoadTask::loadFromVList() -{ -} diff --git a/logic/lists/MinecraftVersionList.h b/logic/lists/MinecraftVersionList.h index 0477379f..fb28ddfe 100644 --- a/logic/lists/MinecraftVersionList.h +++ b/logic/lists/MinecraftVersionList.h @@ -20,14 +20,14 @@ #include <QSet> #include <QSharedPointer> -#include "InstVersionList.h" +#include "BaseVersionList.h" #include "logic/tasks/Task.h" #include "logic/MinecraftVersion.h" class MCVListLoadTask; class QNetworkReply; -class MinecraftVersionList : public InstVersionList +class MinecraftVersionList : public BaseVersionList { Q_OBJECT public: @@ -37,25 +37,19 @@ public: virtual Task *getLoadTask(); virtual bool isLoaded(); - virtual const InstVersionPtr at(int i) const; + virtual const BaseVersionPtr at(int i) const; virtual int count() const; virtual void sort(); - virtual InstVersionPtr getLatestStable() const; - - /*! - * Gets the main version list instance. - */ - static MinecraftVersionList &getMainList(); - + virtual BaseVersionPtr getLatestStable() const; protected: - QList<InstVersionPtr > m_vlist; + QList<BaseVersionPtr> m_vlist; bool m_loaded; protected slots: - virtual void updateListData(QList<InstVersionPtr > versions); + virtual void updateListData(QList<BaseVersionPtr> versions); }; class MCVListLoadTask : public Task @@ -72,9 +66,6 @@ protected slots: void list_downloaded(); protected: - //! Loads versions from Mojang's official version list. - bool loadFromVList(); - QNetworkReply *vlistReply; MinecraftVersionList *m_list; MinecraftVersion *m_currentStable; diff --git a/logic/net/DownloadJob.cpp b/logic/net/DownloadJob.cpp index 9b083b6b..3acba050 100644 --- a/logic/net/DownloadJob.cpp +++ b/logic/net/DownloadJob.cpp @@ -5,6 +5,8 @@ #include "ByteArrayDownload.h" #include "CacheDownload.h" +#include <QDebug> + ByteArrayDownloadPtr DownloadJob::add ( QUrl url ) { ByteArrayDownloadPtr ptr (new ByteArrayDownload(url)); diff --git a/logic/net/DownloadJob.h b/logic/net/DownloadJob.h index 69a49e59..c8f6a9d7 100644 --- a/logic/net/DownloadJob.h +++ b/logic/net/DownloadJob.h @@ -5,6 +5,7 @@ #include "FileDownload.h" #include "CacheDownload.h" #include "HttpMetaCache.h" +#include "logic/tasks/ProgressProvider.h" class DownloadJob; typedef QSharedPointer<DownloadJob> DownloadJobPtr; @@ -12,12 +13,12 @@ typedef QSharedPointer<DownloadJob> DownloadJobPtr; /** * A single file for the downloader/cache to process. */ -class DownloadJob : public QObject +class DownloadJob : public ProgressProvider { Q_OBJECT public: explicit DownloadJob(QString job_name) - :QObject(), m_job_name(job_name){}; + :ProgressProvider(), m_job_name(job_name){}; ByteArrayDownloadPtr add(QUrl url); FileDownloadPtr add(QUrl url, QString rel_target_path); @@ -37,6 +38,19 @@ public: { return downloads.size(); } + virtual void getProgress(qint64& current, qint64& total) + { + current = current_progress; + total = total_progress; + }; + virtual QString getStatus() const + { + return m_job_name; + }; + virtual bool isRunning() const + { + return m_running; + }; signals: void started(); void progress(qint64 current, qint64 total); @@ -56,5 +70,6 @@ private: qint64 total_progress = 0; int num_succeeded = 0; int num_failed = 0; + bool m_running = false; }; diff --git a/logic/tasks/ProgressProvider.h b/logic/tasks/ProgressProvider.h new file mode 100644 index 00000000..e158eb54 --- /dev/null +++ b/logic/tasks/ProgressProvider.h @@ -0,0 +1,20 @@ +#pragma once +#include <QObject> +class ProgressProvider : public QObject +{ + Q_OBJECT +protected: + explicit ProgressProvider(QObject* parent = 0): QObject(parent){} +signals: + void started(); + void progress(qint64 current, qint64 total); + void succeeded(); + void failed(QString reason); + void status(QString status); +public: + virtual QString getStatus() const = 0; + virtual void getProgress(qint64 ¤t, qint64 &total) = 0; + virtual bool isRunning() const = 0; +public slots: + virtual void start() = 0; +}; diff --git a/logic/tasks/Task.cpp b/logic/tasks/Task.cpp index 7c148591..c75bcb8f 100644 --- a/logic/tasks/Task.cpp +++ b/logic/tasks/Task.cpp @@ -16,70 +16,56 @@ #include "Task.h" Task::Task(QObject *parent) : - QObject(parent) + ProgressProvider(parent) { } QString Task::getStatus() const { - return status; + return m_status; } -void Task::setStatus(const QString &status) +void Task::setStatus(const QString &new_status) { - this->status = status; - emitStatusChange(status); + m_status = new_status; + emit status(new_status); } -int Task::getProgress() const +void Task::setProgress(int new_progress) { - return progress; + m_progress = new_progress; + emit progress(new_progress, 100); } -void Task::setProgress(int progress) +void Task::getProgress(qint64& current, qint64& total) { - this->progress = progress; - emitProgressChange(progress); + current = m_progress; + total = 100; } -void Task::startTask() -{ - emitStarted(); - executeTask(); -} -void Task::emitStarted() +void Task::start() { - running = true; + m_running = true; emit started(); + executeTask(); } void Task::emitFailed(QString reason) { - running = false; + m_running = false; emit failed(reason); } void Task::emitSucceeded() { - running = false; + m_running = false; emit succeeded(); } bool Task::isRunning() const { - return running; -} - - -void Task::emitStatusChange(const QString &status) -{ - emit statusChanged(status); -} - -void Task::emitProgressChange(int progress) -{ - emit progressChanged(progress); + return m_running; } diff --git a/logic/tasks/Task.h b/logic/tasks/Task.h index 91852b0f..cfe71c51 100644 --- a/logic/tasks/Task.h +++ b/logic/tasks/Task.h @@ -13,53 +13,37 @@ * limitations under the License. */ -#ifndef TASK_H -#define TASK_H +#pragma once #include <QObject> #include <QString> +#include "ProgressProvider.h" -class Task : public QObject +class Task : public ProgressProvider { Q_OBJECT public: explicit Task(QObject *parent = 0); - QString getStatus() const; - int getProgress() const; - bool isRunning() const; + virtual QString getStatus() const; + virtual void getProgress(qint64& current, qint64& total); + virtual bool isRunning() const; public slots: - void startTask(); - -protected slots: - void setStatus(const QString& status); - void setProgress(int progress); - -signals: - void started(); - void failed(QString reason); - void succeeded(); - - void statusChanged(Task* task, const QString& status); - void progressChanged(Task* task, int progress); - - void statusChanged(const QString& status); - void progressChanged(int progress); + virtual void start(); protected: virtual void executeTask() = 0; - virtual void emitStarted(); - virtual void emitFailed(QString reason); virtual void emitSucceeded(); + virtual void emitFailed(QString reason); + +protected slots: + void setStatus(const QString& status); + void setProgress(int progress); - virtual void emitStatusChange(const QString &status); - virtual void emitProgressChange(int progress); - - QString status; - int progress; - bool running = false; +protected: + QString m_status; + int m_progress = 0; + bool m_running = false; }; - -#endif // TASK_H |