Removed old plugin system and implemented some version list stuff.
This commit is contained in:
parent
1626fa013c
commit
055198303c
@ -75,10 +75,6 @@ include_directories(${LIBMULTIMC_INCLUDE_DIR})
|
||||
add_subdirectory(libgroupview)
|
||||
include_directories(${LIBGROUPVIEW_INCLUDE_DIR})
|
||||
|
||||
# Add the stdinstance plugin.
|
||||
add_subdirectory(plugins/stdinstance)
|
||||
|
||||
|
||||
|
||||
################################ SET UP BUILD OPTIONS ################################
|
||||
|
||||
|
@ -155,8 +155,8 @@ void MainWindow::on_actionAddInstance_triggered()
|
||||
QString instDir = PathCombine(globalSettings->get("InstanceDir").toString(),
|
||||
instDirName);
|
||||
|
||||
InstanceLoader::InstTypeError error = InstanceLoader::get().
|
||||
createInstance(newInstance, newInstDlg->selectedType(), instDir);
|
||||
InstanceLoader::InstLoaderError error = InstanceLoader::get().
|
||||
createInstance(newInstance, instDir);
|
||||
|
||||
if (error == InstanceLoader::NoError)
|
||||
{
|
||||
@ -170,10 +170,6 @@ void MainWindow::on_actionAddInstance_triggered()
|
||||
|
||||
switch (error)
|
||||
{
|
||||
case InstanceLoader::TypeNotRegistered:
|
||||
errorMsg += "Instance type not found.";
|
||||
break;
|
||||
|
||||
case InstanceLoader::InstExists:
|
||||
errorMsg += "An instance with the given directory name already exists.";
|
||||
break;
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include <QLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <minecraftversionlist.h>
|
||||
|
||||
NewInstanceDialog::NewInstanceDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::NewInstanceDialog)
|
||||
@ -41,7 +43,14 @@ NewInstanceDialog::NewInstanceDialog(QWidget *parent) :
|
||||
resize(minimumSizeHint());
|
||||
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||
|
||||
loadTypeList();
|
||||
if (!MinecraftVersionList::getMainList().isLoaded())
|
||||
{
|
||||
TaskDialog *taskDlg = new TaskDialog(this);
|
||||
Task *loadTask = MinecraftVersionList::getMainList().getLoadTask();
|
||||
loadTask->setParent(taskDlg);
|
||||
taskDlg->exec(loadTask);
|
||||
}
|
||||
setSelectedVersion(MinecraftVersionList::getMainList().getLatestStable());
|
||||
}
|
||||
|
||||
NewInstanceDialog::~NewInstanceDialog()
|
||||
@ -49,40 +58,10 @@ NewInstanceDialog::~NewInstanceDialog()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void NewInstanceDialog::loadTypeList()
|
||||
{
|
||||
InstTypeList typeList = InstanceLoader::get().typeList();
|
||||
|
||||
for (int i = 0; i < typeList.length(); i++)
|
||||
{
|
||||
ui->instTypeComboBox->addItem(typeList.at(i)->displayName(), typeList.at(i)->typeID());
|
||||
}
|
||||
|
||||
updateSelectedType();
|
||||
}
|
||||
|
||||
void NewInstanceDialog::updateSelectedType()
|
||||
{
|
||||
QString typeID = ui->instTypeComboBox->itemData(ui->instTypeComboBox->currentIndex()).toString();
|
||||
|
||||
const InstanceTypeInterface *type = InstanceLoader::get().findType(typeID);
|
||||
m_selectedType = type;
|
||||
|
||||
updateDialogState();
|
||||
|
||||
if (m_selectedType)
|
||||
{
|
||||
if (!m_selectedType->versionList()->isLoaded())
|
||||
loadVersionList();
|
||||
|
||||
setSelectedVersion(m_selectedType->versionList()->getLatestStable());
|
||||
}
|
||||
}
|
||||
|
||||
void NewInstanceDialog::updateDialogState()
|
||||
{
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(m_selectedType && m_selectedVersion);
|
||||
ui->btnChangeVersion->setEnabled(m_selectedType && m_selectedVersion);
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(
|
||||
!instName().isEmpty() && m_selectedVersion);
|
||||
}
|
||||
|
||||
void NewInstanceDialog::setSelectedVersion(const InstVersion *version)
|
||||
@ -101,19 +80,6 @@ void NewInstanceDialog::setSelectedVersion(const InstVersion *version)
|
||||
updateDialogState();
|
||||
}
|
||||
|
||||
void NewInstanceDialog::loadVersionList()
|
||||
{
|
||||
if (!m_selectedType)
|
||||
return;
|
||||
|
||||
TaskDialog *taskDlg = new TaskDialog(this);
|
||||
Task *loadTask = m_selectedType->versionList()->getLoadTask();
|
||||
loadTask->setParent(taskDlg);
|
||||
taskDlg->exec(loadTask);
|
||||
|
||||
setSelectedVersion(m_selectedType->versionList()->getLatestStable());
|
||||
}
|
||||
|
||||
QString NewInstanceDialog::instName() const
|
||||
{
|
||||
return ui->instNameTextBox->text();
|
||||
@ -125,11 +91,6 @@ QString NewInstanceDialog::iconKey() const
|
||||
return "default";
|
||||
}
|
||||
|
||||
const InstanceTypeInterface *NewInstanceDialog::selectedType() const
|
||||
{
|
||||
return m_selectedType;
|
||||
}
|
||||
|
||||
const InstVersion *NewInstanceDialog::selectedVersion() const
|
||||
{
|
||||
return m_selectedVersion;
|
||||
@ -137,19 +98,11 @@ const InstVersion *NewInstanceDialog::selectedVersion() const
|
||||
|
||||
void NewInstanceDialog::on_btnChangeVersion_clicked()
|
||||
{
|
||||
if (m_selectedType)
|
||||
VersionSelectDialog *vselect = new VersionSelectDialog(&MinecraftVersionList::getMainList(), this);
|
||||
if (vselect->exec())
|
||||
{
|
||||
VersionSelectDialog *vselect = new VersionSelectDialog(m_selectedType->versionList(), this);
|
||||
if (vselect->exec())
|
||||
{
|
||||
const InstVersion *version = vselect->selectedVersion();
|
||||
if (version)
|
||||
setSelectedVersion(version);
|
||||
}
|
||||
const InstVersion *version = vselect->selectedVersion();
|
||||
if (version)
|
||||
setSelectedVersion(version);
|
||||
}
|
||||
}
|
||||
|
||||
void NewInstanceDialog::on_instTypeComboBox_activated(int index)
|
||||
{
|
||||
updateSelectedType();
|
||||
}
|
||||
|
@ -33,8 +33,6 @@ public:
|
||||
explicit NewInstanceDialog(QWidget *parent = 0);
|
||||
~NewInstanceDialog();
|
||||
|
||||
void loadTypeList();
|
||||
void updateSelectedType();
|
||||
void updateDialogState();
|
||||
|
||||
void setSelectedVersion(const InstVersion *version);
|
||||
@ -43,14 +41,11 @@ public:
|
||||
|
||||
QString instName() const;
|
||||
QString iconKey() const;
|
||||
const InstanceTypeInterface *selectedType() const;
|
||||
const InstVersion *selectedVersion() const;
|
||||
|
||||
private slots:
|
||||
void on_btnChangeVersion_clicked();
|
||||
|
||||
void on_instTypeComboBox_activated(int index);
|
||||
|
||||
private:
|
||||
Ui::NewInstanceDialog *ui;
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>220</width>
|
||||
<height>230</height>
|
||||
<height>234</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -75,27 +75,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="typeLabel">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="instTypeComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
@ -128,6 +107,19 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
|
@ -5,6 +5,7 @@ set(CMAKE_AUTOMOC ON)
|
||||
# Find Qt
|
||||
find_package(Qt5Core REQUIRED)
|
||||
find_package(Qt5Network REQUIRED)
|
||||
find_package(Qt5Xml REQUIRED)
|
||||
|
||||
# Include Qt headers.
|
||||
include_directories(${Qt5Base_INCLUDE_DIRS})
|
||||
@ -28,10 +29,8 @@ include/instanceloader.h
|
||||
include/instversion.h
|
||||
include/instversionlist.h
|
||||
|
||||
|
||||
# Plugin Stuff
|
||||
include/pluginmanager.h
|
||||
include/instancetypeinterface.h
|
||||
include/minecraftversion.h
|
||||
include/minecraftversionlist.h
|
||||
|
||||
|
||||
# Tasks
|
||||
@ -60,9 +59,8 @@ src/instanceloader.cpp
|
||||
src/instversion.cpp
|
||||
src/instversionlist.cpp
|
||||
|
||||
|
||||
# Plugin Stuff
|
||||
src/pluginmanager.cpp
|
||||
src/minecraftversion.cpp
|
||||
src/minecraftversionlist.cpp
|
||||
|
||||
|
||||
# Tasks
|
||||
@ -92,5 +90,5 @@ include_directories(${CMAKE_BINARY_DIR}/include)
|
||||
add_definitions(-DLIBMULTIMC_LIBRARY)
|
||||
|
||||
add_library(libMultiMC SHARED ${LIBINST_SOURCES} ${LIBINST_HEADERS})
|
||||
qt5_use_modules(libMultiMC Core Network)
|
||||
qt5_use_modules(libMultiMC Core Network Xml)
|
||||
target_link_libraries(libMultiMC libUtil libSettings)
|
||||
|
@ -103,6 +103,13 @@ class LIBMULTIMC_EXPORT Instance : public QObject
|
||||
*/
|
||||
Q_PROPERTY(qint64 lastLaunch READ lastLaunch WRITE setLastLaunch)
|
||||
|
||||
/*!
|
||||
* Gets the last time that the current version was checked.
|
||||
* This is checked against the last modified time on the jar file to see if
|
||||
* the current version needs to be checked again.
|
||||
*/
|
||||
Q_PROPERTY(qint64 lastCurrentVersionUpdate READ lastCurrentVersionUpdate WRITE setLastCurrentVersionUpdate)
|
||||
|
||||
|
||||
|
||||
// Dirs
|
||||
@ -225,6 +232,9 @@ public:
|
||||
emit propertiesChanged(this);
|
||||
}
|
||||
|
||||
virtual qint64 lastCurrentVersionUpdate() { return settings().get("lastVersionUpdate").value<qint64>(); }
|
||||
virtual void setLastCurrentVersionUpdate(qint64 val) { settings().set("lastVersionUpdate", val); }
|
||||
|
||||
|
||||
////// Directories //////
|
||||
QString minecraftDir() const;
|
||||
@ -250,17 +260,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 = 0;
|
||||
|
||||
|
||||
|
||||
//////// INSTANCE TYPE STUFF ////////
|
||||
|
||||
/*!
|
||||
* \brief Returns a pointer to this instance's type.
|
||||
* \return A pointer to this instance's type interface.
|
||||
*/
|
||||
virtual const InstanceTypeInterface *instanceType() const = 0;
|
||||
virtual InstVersionList *versionList() const;
|
||||
|
||||
|
||||
//////// OTHER FUNCTIONS ////////
|
||||
@ -274,7 +274,7 @@ public:
|
||||
* stored in the instance config file against the last modified time of Minecraft.jar.
|
||||
* \return True if updateCurrentVersion() should be called.
|
||||
*/
|
||||
virtual bool shouldUpdateCurrentVersion() = 0;
|
||||
virtual bool shouldUpdateCurrentVersion();
|
||||
|
||||
/*!
|
||||
* \brief Updates the current version.
|
||||
@ -286,7 +286,7 @@ public:
|
||||
* instance is loaded if shouldUpdateCurrentVersion returns true.
|
||||
* \param keepCurrent If true, only the version timestamp will be updated.
|
||||
*/
|
||||
virtual void updateCurrentVersion(bool keepCurrent = false) = 0;
|
||||
virtual void updateCurrentVersion(bool keepCurrent = false);
|
||||
|
||||
|
||||
//// Settings System ////
|
||||
|
@ -22,15 +22,10 @@
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
class InstanceTypeInterface;
|
||||
class Instance;
|
||||
|
||||
typedef QList<const InstanceTypeInterface *> InstTypeList;
|
||||
|
||||
/*!
|
||||
* \brief The InstanceLoader is a singleton that manages all of the instance types and handles loading and creating instances.
|
||||
* Instance types are registered with the instance loader through its registerInstType() function.
|
||||
* Creating instances is done through the InstanceLoader's createInstance() function. This function takes
|
||||
* The InstanceLoader is a singleton that manages loading and creating instances.
|
||||
*/
|
||||
class LIBMULTIMC_EXPORT InstanceLoader : public QObject
|
||||
{
|
||||
@ -46,94 +41,45 @@ public:
|
||||
*
|
||||
* - NoError indicates that no error occurred.
|
||||
* - OtherError indicates that an unspecified error occurred.
|
||||
* - TypeIDExists is returned by registerInstanceType() if the ID of the type being registered already exists.
|
||||
* - TypeNotRegistered is returned by createInstance() and loadInstance() when the given type is not registered.
|
||||
* - InstExists is returned by createInstance() if the given instance directory is already an instance.
|
||||
* - NotAnInstance is returned by loadInstance() if the given instance directory is not a valid instance.
|
||||
* - WrongInstType is returned by loadInstance() if the given instance directory's type doesn't match the given type.
|
||||
* - CantCreateDir is returned by createInstance( if the given instance directory can't be created.)
|
||||
*/
|
||||
enum InstTypeError
|
||||
enum InstLoaderError
|
||||
{
|
||||
NoError = 0,
|
||||
OtherError,
|
||||
|
||||
TypeIDExists,
|
||||
|
||||
TypeNotRegistered,
|
||||
InstExists,
|
||||
NotAnInstance,
|
||||
WrongInstType,
|
||||
CantCreateDir
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Registers the given InstanceType with the instance loader.
|
||||
*
|
||||
* \param type The InstanceType to register.
|
||||
* \return An InstTypeError error code.
|
||||
* - TypeIDExists if the given type's is already registered to another instance type.
|
||||
*/
|
||||
InstTypeError registerInstanceType(InstanceTypeInterface *type);
|
||||
|
||||
/*!
|
||||
* \brief Creates an instance with the given type and stores it in inst.
|
||||
*
|
||||
* \param inst Pointer to store the created instance in.
|
||||
* \param type The type of instance to create.
|
||||
* \param instDir The instance's directory.
|
||||
* \return An InstTypeError error code.
|
||||
* - TypeNotRegistered if the given type is not registered with the InstanceLoader.
|
||||
* \return An InstLoaderError error code.
|
||||
* - InstExists if the given instance directory is already an instance.
|
||||
* - CantCreateDir if the given instance directory cannot be created.
|
||||
*/
|
||||
InstTypeError createInstance(Instance *&inst, const InstanceTypeInterface *type, const QString &instDir);
|
||||
|
||||
/*!
|
||||
* \brief Loads an instance from the given directory.
|
||||
*
|
||||
* \param inst Pointer to store the loaded instance in.
|
||||
* \param type The type of instance to load.
|
||||
* \param instDir The instance's directory.
|
||||
* \return An InstTypeError error code.
|
||||
* - TypeNotRegistered if the given type is not registered with the InstanceLoader.
|
||||
* - NotAnInstance if the given instance directory isn't a valid instance.
|
||||
* - WrongInstType if the given instance directory's type isn't the same as the given type.
|
||||
*/
|
||||
InstTypeError loadInstance(Instance *&inst, const InstanceTypeInterface *type, const QString &instDir);
|
||||
InstLoaderError createInstance(Instance *&inst, const QString &instDir);
|
||||
|
||||
/*!
|
||||
* \brief Loads an instance from the given directory.
|
||||
* Checks the instance's INI file to figure out what the instance's type is first.
|
||||
* \param inst Pointer to store the loaded instance in.
|
||||
* \param instDir The instance's directory.
|
||||
* \return An InstTypeError error code.
|
||||
* - TypeNotRegistered if the instance's type is not registered with the InstanceLoader.
|
||||
* \return An InstLoaderError error code.
|
||||
* - NotAnInstance if the given instance directory isn't a valid instance.
|
||||
*/
|
||||
InstTypeError loadInstance(Instance *&inst, const QString &instDir);
|
||||
|
||||
/*!
|
||||
* \brief Finds an instance type with the given ID.
|
||||
* If one cannot be found, returns NULL.
|
||||
*
|
||||
* \param id The ID of the type to find.
|
||||
* \return The type with the given ID. NULL if none were found.
|
||||
*/
|
||||
const InstanceTypeInterface *findType(const QString &id);
|
||||
|
||||
/*!
|
||||
* \brief Gets a list of the registered instance types.
|
||||
*
|
||||
* \return A list of instance types.
|
||||
*/
|
||||
InstTypeList typeList();
|
||||
InstLoaderError loadInstance(Instance *&inst, const QString &instDir);
|
||||
|
||||
private:
|
||||
InstanceLoader();
|
||||
|
||||
QMap<QString, InstanceTypeInterface *> m_typeMap;
|
||||
|
||||
static InstanceLoader loader;
|
||||
};
|
||||
|
||||
|
@ -75,7 +75,7 @@ protected:
|
||||
* TypeNotRegistered if the given type is not registered with the InstanceLoader.
|
||||
* InstExists if the given instance directory is already an instance.
|
||||
*/
|
||||
virtual InstanceLoader::InstTypeError createInstance(Instance *&inst, const QString &instDir) const = 0;
|
||||
virtual InstanceLoader::InstLoaderError createInstance(Instance *&inst, const QString &instDir) const = 0;
|
||||
|
||||
/*!
|
||||
* \brief Loads an instance from the given directory.
|
||||
@ -86,7 +86,7 @@ protected:
|
||||
* NotAnInstance if the given instance directory isn't a valid instance.
|
||||
* WrongInstType if the given instance directory's type isn't an instance of this type.
|
||||
*/
|
||||
virtual InstanceLoader::InstTypeError loadInstance(Instance *&inst, const QString &instDir) const = 0;
|
||||
virtual InstanceLoader::InstLoaderError loadInstance(Instance *&inst, const QString &instDir) const = 0;
|
||||
};
|
||||
|
||||
Q_DECLARE_INTERFACE(InstanceTypeInterface, InstanceTypeInterface_IID)
|
||||
|
@ -22,36 +22,92 @@
|
||||
|
||||
class InstVersionList;
|
||||
|
||||
/*!
|
||||
* An abstract base class for instance versions.
|
||||
* InstVersions hold information about versions such as their names, identifiers,
|
||||
* types, etc.
|
||||
*/
|
||||
class LIBMULTIMC_EXPORT InstVersion : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/*!
|
||||
* A string used to identify this version in config files.
|
||||
* This should be unique within the version list or shenanigans will occur.
|
||||
*/
|
||||
Q_PROPERTY(QString descriptor READ descriptor CONSTANT)
|
||||
|
||||
/*!
|
||||
* The name of this version as it is displayed to the user.
|
||||
* For example: "1.5.1"
|
||||
*/
|
||||
Q_PROPERTY(QString name READ name)
|
||||
|
||||
/*!
|
||||
* The name of this version's type as it is displayed to the user.
|
||||
* For example: "Latest Version", "Snapshot", or "MCNostalgia"
|
||||
*/
|
||||
Q_PROPERTY(QString typeName READ typeName)
|
||||
|
||||
/*!
|
||||
* Whether or not this is a meta version.
|
||||
* Meta versions are not real versions, merely versions that act as aliases
|
||||
* for other versions.
|
||||
* For example: There could be a meta version called "Latest" that always
|
||||
* points to the latest version. The user would pick this version and when
|
||||
* a new version came out, it would point to the new one and update the instance
|
||||
* automatically.
|
||||
*/
|
||||
Q_PROPERTY(bool isMeta READ isMeta)
|
||||
|
||||
|
||||
/*!
|
||||
* Gets the version's timestamp.
|
||||
* This is primarily used for sorting versions in a list.
|
||||
*/
|
||||
Q_PROPERTY(qint64 timestamp READ timestamp)
|
||||
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Constructs a new InstVersion with the given parent.
|
||||
* The parent *must* be the InstVersionList that contains this InstVersion.
|
||||
* The InstVersion should be added to the list immediately after being created.
|
||||
* The InstVersion will be added to the list immediately after being created.
|
||||
*/
|
||||
explicit InstVersion(InstVersionList *parent = 0);
|
||||
|
||||
//! Gets the string used to identify this version in config files.
|
||||
virtual QString descriptor() const = 0;
|
||||
explicit InstVersion(const QString &descriptor,
|
||||
const QString &name,
|
||||
qint64 timestamp,
|
||||
InstVersionList *parent = 0);
|
||||
|
||||
/*!
|
||||
* \breif Returns this InstVersion's name.
|
||||
* This is displayed to the user in the GUI and is usually just the version number ("1.4.7"), for example.
|
||||
* Copy constructor.
|
||||
* If the 'parent' parameter is not NULL, sets this version's parent to the
|
||||
* specified object, rather than setting it to the same parent as the version
|
||||
* we're copying from.
|
||||
* \param other The version to copy.
|
||||
* \param parent If not NULL, will be set as the new version object's parent.
|
||||
*/
|
||||
virtual QString name() const = 0;
|
||||
InstVersion(const InstVersion &other, QObject *parent = 0);
|
||||
|
||||
/*!
|
||||
* \brief Returns this InstVersion's type name.
|
||||
* This is usually displayed to the user in the GUI and specifies what
|
||||
* kind of version this is. For example: it could be "Snapshot",
|
||||
* "Latest Version", "MCNostalgia", etc.
|
||||
*/
|
||||
virtual QString descriptor() const;
|
||||
virtual QString name() const;
|
||||
virtual QString typeName() const = 0;
|
||||
virtual qint64 timestamp() const;
|
||||
virtual bool isMeta() const;
|
||||
|
||||
//! Returns the version list that this InstVersion is a part of.
|
||||
virtual InstVersionList *versionList() const;
|
||||
|
||||
/*!
|
||||
* Creates a copy of this version with a different parent.
|
||||
* \param newParent The parent QObject of the copy.
|
||||
* \return A new, identical copy of this version with the given parent set.
|
||||
*/
|
||||
virtual InstVersion *copyVersion(InstVersionList *newParent) const = 0;
|
||||
|
||||
protected:
|
||||
QString m_descriptor;
|
||||
QString m_name;
|
||||
qint64 m_timestamp;
|
||||
};
|
||||
|
||||
#endif // INSTVERSION_H
|
||||
|
@ -49,7 +49,7 @@ public:
|
||||
explicit InstVersionList(QObject *parent = 0);
|
||||
|
||||
/*!
|
||||
* \brief Gets a task that will reload the version list.
|
||||
* \brief Gets a task that will reload the version islt.
|
||||
* Simply execute the task to load the list.
|
||||
* The task returned by this function should reset the model when it's done.
|
||||
* \return A pointer to a task that reloads the version list.
|
||||
@ -87,6 +87,21 @@ public:
|
||||
* By default, this is simply the first version in the list.
|
||||
*/
|
||||
virtual const InstVersion *getLatestStable();
|
||||
|
||||
protected slots:
|
||||
/*!
|
||||
* Updates this list with the given list of versions.
|
||||
* This is done by copying each version in the given list and inserting it
|
||||
* into this one.
|
||||
* We need to do this so that we can set the parents of the versions are set to this
|
||||
* version list. This can't be done in the load task, because the versions the load
|
||||
* task creates are on the load task's thread and Qt won't allow their parents
|
||||
* to be set to something created on another thread.
|
||||
* To get around that problem, we invoke this method on the GUI thread, which
|
||||
* then copies the versions and sets their parents correctly.
|
||||
* \param versions List of versions whose parents should be set.
|
||||
*/
|
||||
virtual void updateListData(QList<InstVersion *> versions) = 0;
|
||||
};
|
||||
|
||||
#endif // INSTVERSIONLIST_H
|
||||
|
95
libmultimc/include/minecraftversion.h
Normal file
95
libmultimc/include/minecraftversion.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* Copyright 2013 Andrew Okin
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MINECRAFTVERSION_H
|
||||
#define MINECRAFTVERSION_H
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
#include "instversion.h"
|
||||
|
||||
class LIBMULTIMC_EXPORT MinecraftVersion : public InstVersion
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/*!
|
||||
* This version's type. Used internally to identify what kind of version this is.
|
||||
*/
|
||||
Q_PROPERTY(VersionType versionType READ versionType WRITE setVersionType)
|
||||
|
||||
/*!
|
||||
* The URL that this version will be downloaded from.
|
||||
*/
|
||||
Q_PROPERTY(QString downloadURL READ downloadURL)
|
||||
|
||||
/*!
|
||||
* ETag/MD5 Used to verify the integrity of the downloaded minecraft.jar.
|
||||
*/
|
||||
Q_PROPERTY(QString etag READ etag)
|
||||
|
||||
public:
|
||||
explicit MinecraftVersion(QString descriptor,
|
||||
QString name,
|
||||
qint64 timestamp,
|
||||
QString dlUrl,
|
||||
QString etag,
|
||||
InstVersionList *parent = 0);
|
||||
|
||||
/*!
|
||||
* Creates a meta version that links to the given version.
|
||||
* This is *NOT* a copy constructor.
|
||||
* \param linkedVersion the version that the meta version will link to.
|
||||
*/
|
||||
explicit MinecraftVersion(const MinecraftVersion *linkedVersion);
|
||||
|
||||
MinecraftVersion(const MinecraftVersion &other, QObject *parent);
|
||||
|
||||
static InstVersion *mcnVersion(QString rawName, QString niceName);
|
||||
|
||||
enum VersionType
|
||||
{
|
||||
OldSnapshot,
|
||||
Stable,
|
||||
CurrentStable,
|
||||
Snapshot,
|
||||
MCNostalgia,
|
||||
MetaCustom,
|
||||
MetaLatestSnapshot,
|
||||
MetaLatestStable
|
||||
};
|
||||
|
||||
virtual QString descriptor() const;
|
||||
virtual QString name() const;
|
||||
virtual QString typeName() const;
|
||||
virtual qint64 timestamp() const;
|
||||
|
||||
virtual VersionType versionType() const;
|
||||
virtual void setVersionType(VersionType typeName);
|
||||
|
||||
virtual QString downloadURL() const;
|
||||
virtual QString etag() const;
|
||||
virtual bool isMeta() const;
|
||||
|
||||
virtual InstVersion *copyVersion(InstVersionList *newParent) const;
|
||||
|
||||
private:
|
||||
InstVersion *m_linkedVersion;
|
||||
|
||||
QString m_dlUrl;
|
||||
QString m_etag;
|
||||
VersionType m_type;
|
||||
};
|
||||
|
||||
#endif // MINECRAFTVERSION_H
|
105
libmultimc/include/minecraftversionlist.h
Normal file
105
libmultimc/include/minecraftversionlist.h
Normal file
@ -0,0 +1,105 @@
|
||||
/* Copyright 2013 Andrew Okin
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MINECRAFTVERSIONLIST_H
|
||||
#define MINECRAFTVERSIONLIST_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#include <QList>
|
||||
|
||||
#include "instversionlist.h"
|
||||
|
||||
#include "task.h"
|
||||
|
||||
#include "minecraftversion.h"
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
class MCVListLoadTask;
|
||||
|
||||
class LIBMULTIMC_EXPORT MinecraftVersionList : public InstVersionList
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
friend class MCVListLoadTask;
|
||||
|
||||
explicit MinecraftVersionList(QObject *parent = 0);
|
||||
|
||||
virtual Task *getLoadTask();
|
||||
virtual bool isLoaded();
|
||||
virtual const InstVersion *at(int i) const;
|
||||
virtual int count() const;
|
||||
virtual void printToStdOut() const;
|
||||
|
||||
/*!
|
||||
* Gets the main version list instance.
|
||||
*/
|
||||
static MinecraftVersionList &getMainList();
|
||||
|
||||
protected:
|
||||
QList<InstVersion *>m_vlist;
|
||||
|
||||
bool m_loaded;
|
||||
|
||||
protected slots:
|
||||
virtual void updateListData(QList<InstVersion *> versions);
|
||||
};
|
||||
|
||||
class MCVListLoadTask : public Task
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MCVListLoadTask(MinecraftVersionList *vlist);
|
||||
~MCVListLoadTask();
|
||||
|
||||
virtual void executeTask();
|
||||
|
||||
protected:
|
||||
void setSubStatus(const QString msg = "");
|
||||
|
||||
//! Loads versions from Mojang's official version list.
|
||||
bool loadFromVList();
|
||||
|
||||
//! Loads versions from assets.minecraft.net. Any duplicates are ignored.
|
||||
bool loadFromAssets();
|
||||
|
||||
//! Loads versions from MCNostalgia.
|
||||
bool loadMCNostalgia();
|
||||
|
||||
//! Finalizes loading by updating the version list.
|
||||
bool finalize();
|
||||
|
||||
void updateStuff();
|
||||
|
||||
QNetworkAccessManager *netMgr;
|
||||
|
||||
MinecraftVersionList *m_list;
|
||||
QList<InstVersion *> tempList; //! < List of loaded versions
|
||||
QList<InstVersion *> assetsList; //! < List of versions loaded from assets.minecraft.net
|
||||
QList<InstVersion *> mcnList; //! < List of loaded MCNostalgia versions
|
||||
|
||||
MinecraftVersion *m_currentStable;
|
||||
|
||||
bool processedMCVListReply;
|
||||
bool processedAssetsReply;
|
||||
bool processedMCNReply;
|
||||
};
|
||||
|
||||
|
||||
#endif // MINECRAFTVERSIONLIST_H
|
@ -22,6 +22,7 @@
|
||||
#include "overridesetting.h"
|
||||
|
||||
#include "pathutils.h"
|
||||
#include <minecraftversionlist.h>
|
||||
|
||||
Instance::Instance(const QString &rootDir, QObject *parent) :
|
||||
QObject(parent)
|
||||
@ -151,6 +152,39 @@ QString Instance::modListFile() const
|
||||
return PathCombine(rootDir(), "modlist");
|
||||
}
|
||||
|
||||
InstVersionList *Instance::versionList() const
|
||||
{
|
||||
return &MinecraftVersionList::getMainList();
|
||||
}
|
||||
|
||||
bool Instance::shouldUpdateCurrentVersion()
|
||||
{
|
||||
QFileInfo jar(mcJar());
|
||||
return jar.lastModified().toUTC().toMSecsSinceEpoch() != lastCurrentVersionUpdate();
|
||||
}
|
||||
|
||||
void Instance::updateCurrentVersion(bool keepCurrent)
|
||||
{
|
||||
QFileInfo jar(mcJar());
|
||||
|
||||
if(!jar.exists())
|
||||
{
|
||||
setLastCurrentVersionUpdate(0);
|
||||
setCurrentVersion("Unknown");
|
||||
return;
|
||||
}
|
||||
|
||||
qint64 time = jar.lastModified().toUTC().toMSecsSinceEpoch();
|
||||
|
||||
setLastCurrentVersionUpdate(time);
|
||||
if (!keepCurrent)
|
||||
{
|
||||
// TODO: Implement GetMinecraftJarVersion function.
|
||||
QString newVersion = "Unknown";//javautils::GetMinecraftJarVersion(jar.absoluteFilePath());
|
||||
setCurrentVersion(newVersion);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsObject &Instance::settings() const
|
||||
{
|
||||
return *m_settings;
|
||||
|
@ -147,21 +147,17 @@ InstanceList::InstListError InstanceList::loadList()
|
||||
{
|
||||
Instance *instPtr = NULL;
|
||||
|
||||
InstanceLoader::InstTypeError error = InstanceLoader::get().
|
||||
InstanceLoader::InstLoaderError error = InstanceLoader::get().
|
||||
loadInstance(instPtr, subDir);
|
||||
|
||||
if (error != InstanceLoader::NoError &&
|
||||
error != InstanceLoader::NotAnInstance)
|
||||
error != InstanceLoader::NotAnInstance)
|
||||
{
|
||||
QString errorMsg = QString("Failed to load instance %1: ").
|
||||
arg(QFileInfo(subDir).baseName()).toUtf8();
|
||||
|
||||
switch (error)
|
||||
{
|
||||
case InstanceLoader::TypeNotRegistered:
|
||||
errorMsg += "Instance type not found.";
|
||||
break;
|
||||
|
||||
default:
|
||||
errorMsg += QString("Unknown instance loader error %1").
|
||||
arg(error);
|
||||
@ -234,4 +230,4 @@ void InstanceList::propertiesChanged(Instance * inst)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,10 @@
|
||||
|
||||
#include "include/instanceloader.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "include/instancetypeinterface.h"
|
||||
#include "include/instance.h"
|
||||
|
||||
#include "inifile.h"
|
||||
|
||||
@ -31,79 +32,30 @@ InstanceLoader::InstanceLoader() :
|
||||
|
||||
}
|
||||
|
||||
|
||||
InstanceLoader::InstTypeError InstanceLoader::registerInstanceType(InstanceTypeInterface *type)
|
||||
InstanceLoader::InstLoaderError InstanceLoader::loadInstance(
|
||||
Instance *&inst, const QString &instDir)
|
||||
{
|
||||
// Check to see if the type ID exists.
|
||||
if (m_typeMap.contains(type->typeID()))
|
||||
return TypeIDExists;
|
||||
Instance *loadedInst = new Instance(instDir, this);
|
||||
|
||||
// Set the parent to this.
|
||||
// ((QObject *)type)->setParent(this);
|
||||
// TODO: Sanity checks to verify that the instance is valid.
|
||||
|
||||
// Add it to the map.
|
||||
m_typeMap.insert(type->typeID(), type);
|
||||
inst = loadedInst;
|
||||
|
||||
qDebug(QString("Registered instance type %1.").
|
||||
arg(type->typeID()).toUtf8());
|
||||
return NoError;
|
||||
}
|
||||
|
||||
InstanceLoader::InstTypeError InstanceLoader::createInstance(Instance *&inst,
|
||||
const InstanceTypeInterface *type,
|
||||
const QString &instDir)
|
||||
{
|
||||
// Check if the type is registered.
|
||||
if (!type || findType(type->typeID()) != type)
|
||||
return TypeNotRegistered;
|
||||
|
||||
// Create the instance.
|
||||
return type->createInstance(inst, instDir);
|
||||
}
|
||||
|
||||
InstanceLoader::InstTypeError InstanceLoader::loadInstance(Instance *&inst,
|
||||
const InstanceTypeInterface *type,
|
||||
const QString &instDir)
|
||||
InstanceLoader::InstLoaderError InstanceLoader::createInstance(Instance *&inst, const QString &instDir)
|
||||
{
|
||||
// Check if the type is registered.
|
||||
if (!type || findType(type->typeID()) != type)
|
||||
return TypeNotRegistered;
|
||||
QDir rootDir(instDir);
|
||||
|
||||
return type->loadInstance(inst, instDir);
|
||||
}
|
||||
|
||||
InstanceLoader::InstTypeError InstanceLoader::loadInstance(Instance *&inst,
|
||||
const QString &instDir)
|
||||
{
|
||||
QFileInfo instConfig(PathCombine(instDir, "instance.cfg"));
|
||||
|
||||
if (!instConfig.exists())
|
||||
return NotAnInstance;
|
||||
|
||||
INIFile ini;
|
||||
ini.loadFile(instConfig.path());
|
||||
QString typeName = ini.get("type", "net.forkk.MultiMC.StdInstance").toString();
|
||||
const InstanceTypeInterface *type = findType(typeName);
|
||||
|
||||
return loadInstance(inst, type, instDir);
|
||||
}
|
||||
|
||||
const InstanceTypeInterface *InstanceLoader::findType(const QString &id)
|
||||
{
|
||||
if (!m_typeMap.contains(id))
|
||||
return NULL;
|
||||
else
|
||||
return m_typeMap[id];
|
||||
}
|
||||
|
||||
InstTypeList InstanceLoader::typeList()
|
||||
{
|
||||
InstTypeList typeList;
|
||||
|
||||
for (QMap<QString, InstanceTypeInterface *>::iterator iter = m_typeMap.begin(); iter != m_typeMap.end(); iter++)
|
||||
qDebug(instDir.toUtf8());
|
||||
if (!rootDir.exists() && !rootDir.mkpath("."))
|
||||
{
|
||||
typeList.append(*iter);
|
||||
return InstanceLoader::CantCreateDir;
|
||||
}
|
||||
|
||||
return typeList;
|
||||
inst = new Instance(instDir, this);
|
||||
|
||||
return InstanceLoader::NoError;
|
||||
}
|
||||
|
@ -16,17 +16,48 @@
|
||||
#include "include/instversion.h"
|
||||
#include "include/instversionlist.h"
|
||||
|
||||
InstVersion::InstVersion(InstVersionList *parent) :
|
||||
QObject(parent)
|
||||
InstVersion::InstVersion(const QString &descriptor,
|
||||
const QString &name,
|
||||
qint64 timestamp,
|
||||
InstVersionList *parent) :
|
||||
QObject(parent), m_descriptor(descriptor), m_name(name), m_timestamp(timestamp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
InstVersion::InstVersion(const InstVersion &other, QObject *parent) :
|
||||
QObject(parent ? parent : other.parent()),
|
||||
m_descriptor(other.descriptor()), m_name(other.name()), m_timestamp(other.timestamp())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
InstVersionList *InstVersion::versionList() const
|
||||
{
|
||||
// Parent should *always* be an InstVersionList
|
||||
// Parent should *always* be either an InstVersionList or NULL.
|
||||
if (!parent() || !parent()->inherits("InstVersionList"))
|
||||
return NULL;
|
||||
else
|
||||
return (InstVersionList *)parent();
|
||||
}
|
||||
|
||||
bool InstVersion::isMeta() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QString InstVersion::descriptor() const
|
||||
{
|
||||
return m_descriptor;
|
||||
}
|
||||
|
||||
QString InstVersion::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
qint64 InstVersion::timestamp() const
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
|
142
libmultimc/src/minecraftversion.cpp
Normal file
142
libmultimc/src/minecraftversion.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
/* Copyright 2013 Andrew Okin
|
||||
*
|
||||
* 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 "minecraftversion.h"
|
||||
|
||||
MinecraftVersion::MinecraftVersion(QString descriptor,
|
||||
QString name,
|
||||
qint64 timestamp,
|
||||
QString dlUrl,
|
||||
QString etag,
|
||||
InstVersionList *parent) :
|
||||
InstVersion(descriptor, name, timestamp, parent), m_dlUrl(dlUrl), m_etag(etag)
|
||||
{
|
||||
m_linkedVersion = NULL;
|
||||
}
|
||||
|
||||
MinecraftVersion::MinecraftVersion(const MinecraftVersion *linkedVersion) :
|
||||
InstVersion(linkedVersion->descriptor(), linkedVersion->name(), linkedVersion->timestamp(),
|
||||
linkedVersion->versionList())
|
||||
{
|
||||
m_linkedVersion = (MinecraftVersion *)linkedVersion;
|
||||
}
|
||||
|
||||
MinecraftVersion::MinecraftVersion(const MinecraftVersion &other, QObject *parent) :
|
||||
InstVersion(other, parent)
|
||||
{
|
||||
if (other.m_linkedVersion)
|
||||
m_linkedVersion = other.m_linkedVersion;
|
||||
else
|
||||
{
|
||||
m_dlUrl = other.downloadURL();
|
||||
m_etag = other.etag();
|
||||
}
|
||||
}
|
||||
|
||||
QString MinecraftVersion::descriptor() const
|
||||
{
|
||||
return m_descriptor;
|
||||
}
|
||||
|
||||
QString MinecraftVersion::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
QString MinecraftVersion::typeName() const
|
||||
{
|
||||
if (m_linkedVersion)
|
||||
return m_linkedVersion->typeName();
|
||||
|
||||
switch (versionType())
|
||||
{
|
||||
case OldSnapshot:
|
||||
return "Old Snapshot";
|
||||
|
||||
case Stable:
|
||||
return "Stable";
|
||||
|
||||
case CurrentStable:
|
||||
return "Current Stable";
|
||||
|
||||
case Snapshot:
|
||||
return "Snapshot";
|
||||
|
||||
case MCNostalgia:
|
||||
return "MCNostalgia";
|
||||
|
||||
case MetaCustom:
|
||||
// Not really sure what this does, but it was in the code for v4,
|
||||
// so it must be important... Right?
|
||||
return "Custom Meta Version";
|
||||
|
||||
case MetaLatestSnapshot:
|
||||
return "Latest Snapshot";
|
||||
|
||||
case MetaLatestStable:
|
||||
return "Latest Stable";
|
||||
|
||||
default:
|
||||
return QString("Unknown Type %1").arg(versionType());
|
||||
}
|
||||
}
|
||||
|
||||
qint64 MinecraftVersion::timestamp() const
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
||||
|
||||
MinecraftVersion::VersionType MinecraftVersion::versionType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void MinecraftVersion::setVersionType(MinecraftVersion::VersionType typeName)
|
||||
{
|
||||
m_type = typeName;
|
||||
}
|
||||
|
||||
QString MinecraftVersion::downloadURL() const
|
||||
{
|
||||
return m_dlUrl;
|
||||
}
|
||||
|
||||
QString MinecraftVersion::etag() const
|
||||
{
|
||||
return m_etag;
|
||||
}
|
||||
|
||||
bool MinecraftVersion::isMeta() const
|
||||
{
|
||||
return versionType() == MetaCustom ||
|
||||
versionType() == MetaLatestSnapshot ||
|
||||
versionType() == MetaLatestStable;
|
||||
}
|
||||
|
||||
InstVersion *MinecraftVersion::copyVersion(InstVersionList *newParent) const
|
||||
{
|
||||
if (isMeta())
|
||||
{
|
||||
MinecraftVersion *version = new MinecraftVersion((MinecraftVersion *)m_linkedVersion);
|
||||
return version;
|
||||
}
|
||||
else
|
||||
{
|
||||
MinecraftVersion *version = new MinecraftVersion(
|
||||
descriptor(), name(), timestamp(), downloadURL(), etag(), newParent);
|
||||
version->setVersionType(versionType());
|
||||
return version;
|
||||
}
|
||||
}
|
489
libmultimc/src/minecraftversionlist.cpp
Normal file
489
libmultimc/src/minecraftversionlist.cpp
Normal file
@ -0,0 +1,489 @@
|
||||
/* Copyright 2013 Andrew Okin
|
||||
*
|
||||
* 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 "include/minecraftversionlist.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <QtXml>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonParseError>
|
||||
|
||||
#include <QtNetwork>
|
||||
|
||||
#define MCVLIST_URLBASE "http://s3.amazonaws.com/Minecraft.Download/versions/"
|
||||
#define ASSETS_URLBASE "http://assets.minecraft.net/"
|
||||
#define MCN_URLBASE "http://sonicrules.org/mcnweb.py"
|
||||
|
||||
MinecraftVersionList mcVList;
|
||||
|
||||
MinecraftVersionList::MinecraftVersionList(QObject *parent) :
|
||||
InstVersionList(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Task *MinecraftVersionList::getLoadTask()
|
||||
{
|
||||
return new MCVListLoadTask(this);
|
||||
}
|
||||
|
||||
bool MinecraftVersionList::isLoaded()
|
||||
{
|
||||
return m_loaded;
|
||||
}
|
||||
|
||||
const InstVersion *MinecraftVersionList::at(int i) const
|
||||
{
|
||||
return m_vlist.at(i);
|
||||
}
|
||||
|
||||
int MinecraftVersionList::count() const
|
||||
{
|
||||
return m_vlist.count();
|
||||
}
|
||||
|
||||
void MinecraftVersionList::printToStdOut() const
|
||||
{
|
||||
qDebug() << "---------------- Version List ----------------";
|
||||
|
||||
for (int i = 0; i < m_vlist.count(); i++)
|
||||
{
|
||||
MinecraftVersion *version = qobject_cast<MinecraftVersion *>(m_vlist.at(i));
|
||||
|
||||
if (!version)
|
||||
continue;
|
||||
|
||||
qDebug() << "Version " << version->name();
|
||||
qDebug() << "\tDownload: " << version->downloadURL();
|
||||
qDebug() << "\tTimestamp: " << version->timestamp();
|
||||
qDebug() << "\tType: " << version->typeName();
|
||||
qDebug() << "----------------------------------------------";
|
||||
}
|
||||
}
|
||||
|
||||
MinecraftVersionList &MinecraftVersionList::getMainList()
|
||||
{
|
||||
return mcVList;
|
||||
}
|
||||
|
||||
void MinecraftVersionList::updateListData(QList<InstVersion *> versions)
|
||||
{
|
||||
// First, we populate a temporary list with the copies of the versions.
|
||||
QList<InstVersion *> tempList;
|
||||
for (int i = 0; i < versions.length(); i++)
|
||||
{
|
||||
InstVersion *version = versions[i]->copyVersion(this);
|
||||
Q_ASSERT(version != NULL);
|
||||
tempList.append(version);
|
||||
}
|
||||
|
||||
// Now we swap the temporary list into the actual version list.
|
||||
// This applies our changes to the version list immediately and still gives us
|
||||
// access to the old version list so that we can delete the objects in it and
|
||||
// free their memory. By doing this, we cause the version list to update as
|
||||
// quickly as possible.
|
||||
beginResetModel();
|
||||
m_vlist.swap(tempList);
|
||||
m_loaded = true;
|
||||
endResetModel();
|
||||
|
||||
// We called swap, so all the data that was in the version list previously is now in
|
||||
// tempList (and vice-versa). Now we just free the memory.
|
||||
while (!tempList.isEmpty())
|
||||
delete tempList.takeFirst();
|
||||
}
|
||||
|
||||
inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname)
|
||||
{
|
||||
QDomNodeList elementList = parent.elementsByTagName(tagname);
|
||||
if (elementList.count())
|
||||
return elementList.at(0).toElement();
|
||||
else
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
inline QDateTime timeFromS3Time(QString str)
|
||||
{
|
||||
const QString fmt("yyyy-MM-dd'T'HH:mm:ss'.000Z'");
|
||||
return QDateTime::fromString(str, fmt);
|
||||
}
|
||||
|
||||
inline void waitForNetRequest(QNetworkReply *netReply)
|
||||
{
|
||||
QEventLoop loop;
|
||||
loop.connect(netReply, SIGNAL(finished()), SLOT(quit()));
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
|
||||
MCVListLoadTask::MCVListLoadTask(MinecraftVersionList *vlist)
|
||||
{
|
||||
m_list = vlist;
|
||||
m_currentStable = NULL;
|
||||
}
|
||||
|
||||
MCVListLoadTask::~MCVListLoadTask()
|
||||
{
|
||||
// delete netMgr;
|
||||
}
|
||||
|
||||
void MCVListLoadTask::executeTask()
|
||||
{
|
||||
setSubStatus();
|
||||
|
||||
QNetworkAccessManager networkMgr;
|
||||
netMgr = &networkMgr;
|
||||
|
||||
if (!loadFromVList())
|
||||
{
|
||||
qDebug() << "Failed to load from Mojang version list.";
|
||||
}
|
||||
if (!loadFromAssets())
|
||||
{
|
||||
qDebug() << "Failed to load assets version list.";
|
||||
}
|
||||
if (!loadMCNostalgia())
|
||||
{
|
||||
qDebug() << "Failed to load MCNostalgia version list.";
|
||||
}
|
||||
finalize();
|
||||
}
|
||||
|
||||
void MCVListLoadTask::setSubStatus(const QString msg)
|
||||
{
|
||||
if (msg.isEmpty())
|
||||
setStatus("Loading instance version list...");
|
||||
else
|
||||
setStatus("Loading instance version list: " + msg);
|
||||
}
|
||||
|
||||
bool MCVListLoadTask::loadFromVList()
|
||||
{
|
||||
QNetworkReply *vlistReply = netMgr->get(QNetworkRequest(QUrl(QString(MCVLIST_URLBASE) +
|
||||
"versions.json")));
|
||||
waitForNetRequest(vlistReply);
|
||||
|
||||
switch (vlistReply->error())
|
||||
{
|
||||
case QNetworkReply::NoError:
|
||||
{
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(vlistReply->readAll(), &jsonError);
|
||||
|
||||
if (jsonError.error == QJsonParseError::NoError)
|
||||
{
|
||||
Q_ASSERT_X(jsonDoc.isObject(), "loadFromVList", "jsonDoc is not an object");
|
||||
|
||||
QJsonObject root = jsonDoc.object();
|
||||
|
||||
// Get the ID of the latest release and the latest snapshot.
|
||||
Q_ASSERT_X(root.value("latest").isObject(), "loadFromVList",
|
||||
"version list is missing 'latest' object");
|
||||
QJsonObject latest = root.value("latest").toObject();
|
||||
|
||||
QString latestReleaseID = latest.value("release").toString("");
|
||||
QString latestSnapshotID = latest.value("snapshot").toString("");
|
||||
Q_ASSERT_X(!latestReleaseID.isEmpty(), "loadFromVList", "latest release field is missing");
|
||||
Q_ASSERT_X(!latestSnapshotID.isEmpty(), "loadFromVList", "latest snapshot field is missing");
|
||||
|
||||
// Now, get the array of versions.
|
||||
Q_ASSERT_X(root.value("versions").isArray(), "loadFromVList",
|
||||
"version list object is missing 'versions' array");
|
||||
QJsonArray versions = root.value("versions").toArray();
|
||||
|
||||
for (int i = 0; i < versions.count(); i++)
|
||||
{
|
||||
// Load the version info.
|
||||
Q_ASSERT_X(versions[i].isObject(), "loadFromVList",
|
||||
QString("in versions array, index %1 is not an object").
|
||||
arg(i).toUtf8());
|
||||
QJsonObject version = versions[i].toObject();
|
||||
|
||||
QString versionID = version.value("id").toString("");
|
||||
QString versionTimeStr = version.value("time").toString("");
|
||||
QString versionTypeStr = version.value("type").toString("");
|
||||
|
||||
Q_ASSERT_X(!versionID.isEmpty(), "loadFromVList",
|
||||
QString("in versions array, index %1's \"id\" field is not a valid string").
|
||||
arg(i).toUtf8());
|
||||
Q_ASSERT_X(!versionTimeStr.isEmpty(), "loadFromVList",
|
||||
QString("in versions array, index %1's \"time\" field is not a valid string").
|
||||
arg(i).toUtf8());
|
||||
Q_ASSERT_X(!versionTypeStr.isEmpty(), "loadFromVList",
|
||||
QString("in versions array, index %1's \"type\" field is not a valid string").
|
||||
arg(i).toUtf8());
|
||||
|
||||
|
||||
// Now, process that info and add the version to the list.
|
||||
|
||||
// Parse the timestamp.
|
||||
QDateTime versionTime = timeFromS3Time(versionTimeStr);
|
||||
|
||||
// Parse the type.
|
||||
MinecraftVersion::VersionType versionType;
|
||||
if (versionTypeStr == "release")
|
||||
{
|
||||
// Check if this version is the current stable version.
|
||||
if (versionID == latestReleaseID)
|
||||
versionType = MinecraftVersion::CurrentStable;
|
||||
else
|
||||
versionType = MinecraftVersion::Stable;
|
||||
}
|
||||
else
|
||||
{
|
||||
versionType = MinecraftVersion::Snapshot;
|
||||
}
|
||||
|
||||
// Get the download URL.
|
||||
QString dlUrl = QString(MCVLIST_URLBASE) + versionID + "/";
|
||||
|
||||
|
||||
// Now, we construct the version object and add it to the list.
|
||||
MinecraftVersion *mcVersion = new MinecraftVersion(
|
||||
versionID, versionID, versionTime.toMSecsSinceEpoch(),
|
||||
dlUrl, "");
|
||||
mcVersion->setVersionType(versionType);
|
||||
tempList.append(mcVersion);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Error parsing version list JSON:" << jsonError.errorString();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO: Network error handling.
|
||||
qDebug() << "Failed to load Minecraft main version list" << vlistReply->errorString();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MCVListLoadTask::loadFromAssets()
|
||||
{
|
||||
setSubStatus("Loading versions from assets.minecraft.net...");
|
||||
|
||||
bool succeeded = false;
|
||||
|
||||
QNetworkReply *assetsReply = netMgr->get(QNetworkRequest(QUrl(ASSETS_URLBASE)));
|
||||
waitForNetRequest(assetsReply);
|
||||
|
||||
switch (assetsReply->error())
|
||||
{
|
||||
case QNetworkReply::NoError:
|
||||
{
|
||||
// Get the XML string.
|
||||
QString xmlString = assetsReply->readAll();
|
||||
|
||||
QString xmlErrorMsg;
|
||||
|
||||
QDomDocument doc;
|
||||
if (!doc.setContent(xmlString, false, &xmlErrorMsg))
|
||||
{
|
||||
// TODO: Display error message to the user.
|
||||
qDebug() << "Failed to process assets.minecraft.net. XML error:" <<
|
||||
xmlErrorMsg << xmlString;
|
||||
}
|
||||
|
||||
QDomNodeList contents = doc.elementsByTagName("Contents");
|
||||
|
||||
QRegExp mcRegex("/minecraft.jar$");
|
||||
QRegExp snapshotRegex("[0-9][0-9]w[0-9][0-9][a-z]|pre|rc");
|
||||
|
||||
for (int i = 0; i < contents.length(); i++)
|
||||
{
|
||||
QDomElement element = contents.at(i).toElement();
|
||||
|
||||
if (element.isNull())
|
||||
continue;
|
||||
|
||||
QDomElement keyElement = getDomElementByTagName(element, "Key");
|
||||
QDomElement lastmodElement = getDomElementByTagName(element, "LastModified");
|
||||
QDomElement etagElement = getDomElementByTagName(element, "ETag");
|
||||
|
||||
if (keyElement.isNull() || lastmodElement.isNull() || etagElement.isNull())
|
||||
continue;
|
||||
|
||||
QString key = keyElement.text();
|
||||
QString lastModStr = lastmodElement.text();
|
||||
QString etagStr = etagElement.text();
|
||||
|
||||
if (!key.contains(mcRegex))
|
||||
continue;
|
||||
|
||||
QString versionDirName = key.left(key.length() - 14);
|
||||
QString dlUrl = QString("http://assets.minecraft.net/%1/").arg(versionDirName);
|
||||
|
||||
QString versionName = versionDirName.replace("_", ".");
|
||||
|
||||
QDateTime versionTimestamp = timeFromS3Time(lastModStr);
|
||||
if (!versionTimestamp.isValid())
|
||||
{
|
||||
qDebug(QString("Failed to parse timestamp for version %1 %2").
|
||||
arg(versionName, lastModStr).toUtf8());
|
||||
versionTimestamp = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
if (m_currentStable)
|
||||
{
|
||||
{
|
||||
bool older = versionTimestamp.toMSecsSinceEpoch() < m_currentStable->timestamp();
|
||||
bool newer = versionTimestamp.toMSecsSinceEpoch() > m_currentStable->timestamp();
|
||||
bool isSnapshot = versionName.contains(snapshotRegex);
|
||||
|
||||
MinecraftVersion *version = new MinecraftVersion(
|
||||
versionName, versionName,
|
||||
versionTimestamp.toMSecsSinceEpoch(),
|
||||
dlUrl, etagStr);
|
||||
|
||||
if (newer)
|
||||
{
|
||||
version->setVersionType(MinecraftVersion::Snapshot);
|
||||
}
|
||||
else if (older && isSnapshot)
|
||||
{
|
||||
version->setVersionType(MinecraftVersion::OldSnapshot);
|
||||
}
|
||||
else if (older)
|
||||
{
|
||||
version->setVersionType(MinecraftVersion::Stable);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shouldn't happen, but just in case...
|
||||
version->setVersionType(MinecraftVersion::CurrentStable);
|
||||
}
|
||||
|
||||
assetsList.push_back(version);
|
||||
}
|
||||
}
|
||||
else // If there isn't a current stable version.
|
||||
{
|
||||
bool isSnapshot = versionName.contains(snapshotRegex);
|
||||
|
||||
MinecraftVersion *version = new MinecraftVersion(
|
||||
versionName, versionName,
|
||||
versionTimestamp.toMSecsSinceEpoch(),
|
||||
dlUrl, etagStr);
|
||||
version->setVersionType(isSnapshot? MinecraftVersion::Snapshot :
|
||||
MinecraftVersion::Stable);
|
||||
assetsList.push_back(version);
|
||||
}
|
||||
}
|
||||
|
||||
setSubStatus("Loaded assets.minecraft.net");
|
||||
succeeded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO: Network error handling.
|
||||
qDebug() << "Failed to load assets.minecraft.net" << assetsReply->errorString();
|
||||
break;
|
||||
}
|
||||
|
||||
processedAssetsReply = true;
|
||||
updateStuff();
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
bool MCVListLoadTask::loadMCNostalgia()
|
||||
{
|
||||
QNetworkReply *mcnReply = netMgr->get(QNetworkRequest(QUrl(QString(MCN_URLBASE) + "?pversion=1&list=True")));
|
||||
waitForNetRequest(mcnReply);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MCVListLoadTask::finalize()
|
||||
{
|
||||
// First, we need to do some cleanup. We loaded assets versions into assetsList,
|
||||
// MCNostalgia versions into mcnList and all the others into tempList. MCNostalgia
|
||||
// provides some versions that are on assets.minecraft.net and we want to ignore
|
||||
// those, so we remove and delete them from mcnList. assets.minecraft.net also provides
|
||||
// versions that are on Mojang's version list and we want to ignore those as well.
|
||||
|
||||
// To start, we get a list of the descriptors in tmpList.
|
||||
QStringList tlistDescriptors;
|
||||
for (int i = 0; i < tempList.count(); i++)
|
||||
tlistDescriptors.append(tempList.at(i)->descriptor());
|
||||
|
||||
// Now, we go through our assets version list and remove anything with
|
||||
// a descriptor that matches one we already have in tempList.
|
||||
for (int i = 0; i < assetsList.count(); i++)
|
||||
if (tlistDescriptors.contains(assetsList.at(i)->descriptor()))
|
||||
delete assetsList.takeAt(i--); // We need to decrement here because we're removing an item.
|
||||
|
||||
// We also need to rebuild the list of descriptors.
|
||||
tlistDescriptors.clear();
|
||||
for (int i = 0; i < tempList.count(); i++)
|
||||
tlistDescriptors.append(tempList.at(i)->descriptor());
|
||||
|
||||
// Next, we go through our MCNostalgia version list and do the same thing.
|
||||
for (int i = 0; i < mcnList.count(); i++)
|
||||
if (tlistDescriptors.contains(mcnList.at(i)->descriptor()))
|
||||
delete mcnList.takeAt(i--); // We need to decrement here because we're removing an item.
|
||||
|
||||
// Now that the duplicates are gone, we need to merge the lists. This is
|
||||
// simple enough.
|
||||
tempList.append(assetsList);
|
||||
tempList.append(mcnList);
|
||||
|
||||
// We're done with these lists now, but the items have been moved over to
|
||||
// tempList, so we don't need to delete them yet.
|
||||
|
||||
// Now, we invoke the updateListData slot on the GUI thread. This will copy all
|
||||
// the versions we loaded and set their parents to the version list.
|
||||
// Then, it will swap the new list with the old one and free the old list's memory.
|
||||
QMetaObject::invokeMethod(m_list, "updateListData", Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QList<InstVersion*>, tempList));
|
||||
|
||||
// Once that's finished, we can delete the versions in our temp list.
|
||||
while (!tempList.isEmpty())
|
||||
delete tempList.takeFirst();
|
||||
|
||||
#ifdef PRINT_VERSIONS
|
||||
m_list->printToStdOut();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void MCVListLoadTask::updateStuff()
|
||||
{
|
||||
const int totalReqs = 3;
|
||||
int reqsComplete = 0;
|
||||
|
||||
if (processedMCVListReply)
|
||||
reqsComplete++;
|
||||
if (processedAssetsReply)
|
||||
reqsComplete++;
|
||||
if (processedMCNReply)
|
||||
reqsComplete++;
|
||||
|
||||
calcProgress(reqsComplete, totalReqs);
|
||||
|
||||
if (reqsComplete >= totalReqs)
|
||||
{
|
||||
quit();
|
||||
}
|
||||
}
|
6
main.cpp
6
main.cpp
@ -32,8 +32,6 @@
|
||||
#include "logintask.h"
|
||||
#include "minecraftprocess.h"
|
||||
|
||||
#include "pluginmanager.h"
|
||||
|
||||
#include "pathutils.h"
|
||||
#include "cmdutils.h"
|
||||
|
||||
@ -206,10 +204,6 @@ int main(int argc, char *argv[])
|
||||
// Register meta types.
|
||||
qRegisterMetaType<LoginResponse>("LoginResponse");
|
||||
|
||||
// Initialize plugins.
|
||||
PluginManager::get().loadPlugins(PathCombine(qApp->applicationDirPath(), "plugins"));
|
||||
PluginManager::get().initInstanceTypes();
|
||||
|
||||
// launch instance.
|
||||
if (!args["launch"].isNull())
|
||||
return InstanceLauncher(args["launch"].toString()).launch();
|
||||
|
Loading…
Reference in New Issue
Block a user