Massive renaming in the backend folder, all around restructure in the same.
This commit is contained in:
199
backend/BaseInstance.cpp
Normal file
199
backend/BaseInstance.cpp
Normal file
@ -0,0 +1,199 @@
|
||||
/* 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 "BaseInstance.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "inisettingsobject.h"
|
||||
#include "setting.h"
|
||||
#include "overridesetting.h"
|
||||
|
||||
#include "pathutils.h"
|
||||
#include <lists/MinecraftVersionList.h>
|
||||
|
||||
BaseInstance::BaseInstance(const QString &rootDir, QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_rootDir = rootDir;
|
||||
m_settings = new INISettingsObject(PathCombine(rootDir, "instance.cfg"), this);
|
||||
|
||||
settings().registerSetting(new Setting("name", "Unnamed Instance"));
|
||||
settings().registerSetting(new Setting("iconKey", "default"));
|
||||
settings().registerSetting(new Setting("notes", ""));
|
||||
settings().registerSetting(new Setting("NeedsRebuild", true));
|
||||
settings().registerSetting(new Setting("ShouldUpdate", false));
|
||||
settings().registerSetting(new Setting("JarVersion", "Unknown"));
|
||||
settings().registerSetting(new Setting("LwjglVersion", "2.9.0"));
|
||||
settings().registerSetting(new Setting("IntendedJarVersion", ""));
|
||||
settings().registerSetting(new Setting("lastLaunchTime", 0));
|
||||
|
||||
// Java Settings
|
||||
settings().registerSetting(new OverrideSetting("JavaPath", globalSettings->getSetting("JavaPath")));
|
||||
settings().registerSetting(new OverrideSetting("JvmArgs", globalSettings->getSetting("JvmArgs")));
|
||||
|
||||
// Custom Commands
|
||||
settings().registerSetting(new OverrideSetting("PreLaunchCommand",
|
||||
globalSettings->getSetting("PreLaunchCommand")));
|
||||
settings().registerSetting(new OverrideSetting("PostExitCommand",
|
||||
globalSettings->getSetting("PostExitCommand")));
|
||||
|
||||
// Window Size
|
||||
settings().registerSetting(new OverrideSetting("LaunchCompatMode", globalSettings->getSetting("LaunchCompatMode")));
|
||||
settings().registerSetting(new OverrideSetting("LaunchMaximized", globalSettings->getSetting("LaunchMaximized")));
|
||||
settings().registerSetting(new OverrideSetting("MinecraftWinWidth", globalSettings->getSetting("MinecraftWinWidth")));
|
||||
settings().registerSetting(new OverrideSetting("MinecraftWinHeight", globalSettings->getSetting("MinecraftWinHeight")));
|
||||
|
||||
// Memory
|
||||
settings().registerSetting(new OverrideSetting("MinMemAlloc", globalSettings->getSetting("MinMemAlloc")));
|
||||
settings().registerSetting(new OverrideSetting("MaxMemAlloc", globalSettings->getSetting("MaxMemAlloc")));
|
||||
|
||||
// Auto login
|
||||
settings().registerSetting(new OverrideSetting("AutoLogin", globalSettings->getSetting("AutoLogin")));
|
||||
|
||||
// Console
|
||||
settings().registerSetting(new OverrideSetting("ShowConsole", globalSettings->getSetting("ShowConsole")));
|
||||
settings().registerSetting(new OverrideSetting("AutoCloseConsole", globalSettings->getSetting("AutoCloseConsole")));
|
||||
|
||||
// Overrides
|
||||
settings().registerSetting(new Setting("OverrideConsole", false));
|
||||
settings().registerSetting(new Setting("OverrideWindow", false));
|
||||
settings().registerSetting(new Setting("OverrideLogin", false));
|
||||
settings().registerSetting(new Setting("OverrideMemory", false));
|
||||
settings().registerSetting(new Setting("OverrideJava", false));
|
||||
settings().registerSetting(new Setting("OverrideCommands", false));
|
||||
}
|
||||
|
||||
QString BaseInstance::id() const
|
||||
{
|
||||
return QFileInfo(rootDir()).fileName();
|
||||
}
|
||||
|
||||
QString BaseInstance::rootDir() const
|
||||
{
|
||||
return m_rootDir;
|
||||
}
|
||||
|
||||
InstanceList *BaseInstance::instList() const
|
||||
{
|
||||
if (parent()->inherits("InstanceList"))
|
||||
return (InstanceList *)parent();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QString BaseInstance::minecraftDir() const
|
||||
{
|
||||
QFileInfo mcDir(PathCombine(rootDir(), "minecraft"));
|
||||
QFileInfo dotMCDir(PathCombine(rootDir(), ".minecraft"));
|
||||
|
||||
if (dotMCDir.exists() && !mcDir.exists())
|
||||
return dotMCDir.filePath();
|
||||
else
|
||||
return mcDir.filePath();
|
||||
}
|
||||
|
||||
QString BaseInstance::instModsDir() const
|
||||
{
|
||||
return PathCombine(rootDir(), "instMods");
|
||||
}
|
||||
|
||||
QString BaseInstance::binDir() const
|
||||
{
|
||||
return PathCombine(minecraftDir(), "bin");
|
||||
}
|
||||
|
||||
QString BaseInstance::savesDir() const
|
||||
{
|
||||
return PathCombine(minecraftDir(), "saves");
|
||||
}
|
||||
|
||||
QString BaseInstance::mlModsDir() const
|
||||
{
|
||||
return PathCombine(minecraftDir(), "mods");
|
||||
}
|
||||
|
||||
QString BaseInstance::coreModsDir() const
|
||||
{
|
||||
return PathCombine(minecraftDir(), "coremods");
|
||||
}
|
||||
|
||||
QString BaseInstance::resourceDir() const
|
||||
{
|
||||
return PathCombine(minecraftDir(), "resources");
|
||||
}
|
||||
|
||||
QString BaseInstance::screenshotsDir() const
|
||||
{
|
||||
return PathCombine(minecraftDir(), "screenshots");
|
||||
}
|
||||
|
||||
QString BaseInstance::texturePacksDir() const
|
||||
{
|
||||
return PathCombine(minecraftDir(), "texturepacks");
|
||||
}
|
||||
|
||||
QString BaseInstance::mcJar() const
|
||||
{
|
||||
return PathCombine(binDir(), "minecraft.jar");
|
||||
}
|
||||
|
||||
QString BaseInstance::mcBackup() const
|
||||
{
|
||||
return PathCombine(binDir(), "mcbackup.jar");
|
||||
}
|
||||
|
||||
QString BaseInstance::modListFile() const
|
||||
{
|
||||
return PathCombine(rootDir(), "modlist");
|
||||
}
|
||||
|
||||
InstVersionList *BaseInstance::versionList() const
|
||||
{
|
||||
return &MinecraftVersionList::getMainList();
|
||||
}
|
||||
|
||||
bool BaseInstance::shouldUpdateCurrentVersion() const
|
||||
{
|
||||
QFileInfo jar(mcJar());
|
||||
return jar.lastModified().toUTC().toMSecsSinceEpoch() != lastCurrentVersionUpdate();
|
||||
}
|
||||
|
||||
void BaseInstance::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 &BaseInstance::settings() const
|
||||
{
|
||||
return *m_settings;
|
||||
}
|
313
backend/BaseInstance.h
Normal file
313
backend/BaseInstance.h
Normal file
@ -0,0 +1,313 @@
|
||||
/* 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 <QDateTime>
|
||||
|
||||
#include <settingsobject.h>
|
||||
|
||||
#include "inifile.h"
|
||||
#include "lists/InstVersionList.h"
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
class InstanceList;
|
||||
|
||||
/*!
|
||||
* \brief Base class for instances.
|
||||
* This class implements many functions that are common between instances and
|
||||
* provides a standard interface for all instances.
|
||||
*
|
||||
* To create a new instance type, create a new class inheriting from this class
|
||||
* and implement the pure virtual functions.
|
||||
*/
|
||||
class LIBMULTIMC_EXPORT BaseInstance : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
// Properties
|
||||
/*!
|
||||
* The instance's ID.
|
||||
* This is a unique identifier string that is, by default, set to the
|
||||
* instance's folder name. It's not always the instance's folder name,
|
||||
* however, as any class deriving from Instance can override the id()
|
||||
* method and change how the ID is determined. The instance's ID should
|
||||
* always remain constant. Undefined behavior results if an already loaded
|
||||
* instance's ID changes.
|
||||
*/
|
||||
Q_PROPERTY(QString id READ id STORED false)
|
||||
|
||||
//! Path to the instance's root directory.
|
||||
Q_PROPERTY(QString rootDir READ rootDir)
|
||||
|
||||
//! The name of the instance that is displayed to the user.
|
||||
Q_PROPERTY(QString name READ name WRITE setName)
|
||||
|
||||
//! The instance's icon key.
|
||||
Q_PROPERTY(QString iconKey READ iconKey WRITE setIconKey)
|
||||
|
||||
//! The instance's notes.
|
||||
Q_PROPERTY(QString notes READ notes WRITE setNotes)
|
||||
|
||||
//! The instance's group.
|
||||
Q_PROPERTY(QString group READ group WRITE setGroup)
|
||||
|
||||
/*!
|
||||
* Gets the time that the instance was last launched.
|
||||
* Stored in milliseconds since epoch.
|
||||
* This value is usually used for things like sorting instances by the time
|
||||
* they were last launched.
|
||||
*/
|
||||
Q_PROPERTY(qint64 lastLaunch READ lastLaunch WRITE setLastLaunch)
|
||||
|
||||
/*!
|
||||
* Whether or not the instance's minecraft.jar needs to be rebuilt.
|
||||
* If this is true, when the instance launches, its jar mods will be
|
||||
* re-added to a fresh minecraft.jar file.
|
||||
*/
|
||||
Q_PROPERTY(bool shouldRebuild READ shouldRebuild WRITE setShouldRebuild)
|
||||
|
||||
/*!
|
||||
* Whether or not Minecraft should be downloaded when the instance is launched.
|
||||
* This returns true if shouldForceUpdate game is true or if the intended and
|
||||
* current versions don't match.
|
||||
*/
|
||||
Q_PROPERTY(bool shouldUpdate READ shouldUpdate WRITE setShouldUpdate)
|
||||
|
||||
/*!
|
||||
* The instance's current version.
|
||||
* This value represents the instance's current version. If this value is
|
||||
* different from the intendedVersion, the instance should be updated.
|
||||
* \warning Don't change this value unless you know what you're doing.
|
||||
*/
|
||||
Q_PROPERTY(QString currentVersion READ currentVersion WRITE setCurrentVersion)
|
||||
|
||||
/*!
|
||||
* The version that the user has set for this instance to use.
|
||||
* If this is not the same as currentVersion, the instance's game updater
|
||||
* will be run on launch.
|
||||
*/
|
||||
Q_PROPERTY(QString intendedVersion READ intendedVersion WRITE setIntendedVersion)
|
||||
|
||||
//! The version of LWJGL that this instance uses.
|
||||
Q_PROPERTY(QString lwjglVersion READ lwjglVersion WRITE setLWJGLVersion)
|
||||
|
||||
|
||||
/*!
|
||||
* 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
|
||||
//! Path to the instance's .minecraft folder.
|
||||
Q_PROPERTY(QString minecraftDir READ minecraftDir STORED false)
|
||||
|
||||
//! Path to the instance's instMods folder.
|
||||
Q_PROPERTY(QString instModsDir READ instModsDir STORED false)
|
||||
|
||||
//! Path to the instance's bin folder.
|
||||
Q_PROPERTY(QString binDir READ binDir STORED false)
|
||||
|
||||
//! Path to the instance's saves folder.
|
||||
Q_PROPERTY(QString savesDir READ savesDir STORED false)
|
||||
|
||||
//! Path to the instance's mods folder (.minecraft/mods)
|
||||
Q_PROPERTY(QString mlModsDir READ mlModsDir STORED false)
|
||||
|
||||
//! Path to the instance's coremods folder.
|
||||
Q_PROPERTY(QString coreModsDir READ coreModsDir STORED false)
|
||||
|
||||
//! Path to the instance's resources folder.
|
||||
Q_PROPERTY(QString resourceDir READ resourceDir STORED false)
|
||||
|
||||
//! Path to the instance's screenshots folder.
|
||||
Q_PROPERTY(QString screenshotsDir READ screenshotsDir STORED false)
|
||||
|
||||
//! Path to the instance's texturepacks folder.
|
||||
Q_PROPERTY(QString texturePacksDir READ texturePacksDir STORED false)
|
||||
|
||||
|
||||
// Files
|
||||
//! Path to the instance's minecraft.jar
|
||||
Q_PROPERTY(QString mcJar READ mcJar STORED false)
|
||||
|
||||
//! Path to the instance's mcbackup.jar
|
||||
Q_PROPERTY(QString mcBackup READ mcBackup STORED false)
|
||||
|
||||
//! Path to the instance's modlist file.
|
||||
Q_PROPERTY(QString modListFile READ modListFile STORED false)
|
||||
|
||||
public:
|
||||
explicit BaseInstance(const QString &rootDir, QObject *parent = 0);
|
||||
|
||||
//////// STUFF ////////
|
||||
virtual QString id() const;
|
||||
|
||||
virtual QString rootDir() const;
|
||||
|
||||
/*!
|
||||
* \brief Gets the instance list that this instance is a part of.
|
||||
* Returns NULL if this instance is not in a list
|
||||
* (the parent is not an InstanceList).
|
||||
* \return A pointer to the InstanceList containing this instance.
|
||||
*/
|
||||
virtual InstanceList *instList() const;
|
||||
|
||||
|
||||
//////// INSTANCE INFO ////////
|
||||
|
||||
//// General Info ////
|
||||
virtual QString name() const { return settings().get("name").toString(); }
|
||||
virtual void setName(QString val)
|
||||
{
|
||||
settings().set("name", val);
|
||||
emit propertiesChanged(this);
|
||||
}
|
||||
|
||||
virtual QString iconKey() const { return settings().get("iconKey").toString(); }
|
||||
virtual void setIconKey(QString val)
|
||||
{
|
||||
settings().set("iconKey", val);
|
||||
emit propertiesChanged(this);
|
||||
}
|
||||
|
||||
virtual QString notes() const { return settings().get("notes").toString(); }
|
||||
virtual void setNotes(QString val) { settings().set("notes", val); }
|
||||
|
||||
virtual QString group() const { return m_group; }
|
||||
virtual void setGroup(QString val)
|
||||
{
|
||||
m_group = val;
|
||||
emit propertiesChanged(this);
|
||||
}
|
||||
|
||||
virtual bool shouldRebuild() const { return settings().get("NeedsRebuild").toBool(); }
|
||||
virtual void setShouldRebuild(bool val) { settings().set("NeedsRebuild", val); }
|
||||
|
||||
|
||||
//// Version Stuff ////
|
||||
|
||||
virtual QString currentVersion() const { return settings().get("JarVersion").toString(); }
|
||||
virtual void setCurrentVersion(QString val) { settings().set("JarVersion", val); }
|
||||
|
||||
virtual QString lwjglVersion() const { return settings().get("LwjglVersion").toString(); }
|
||||
virtual void setLWJGLVersion(QString val) { settings().set("LwjglVersion", val); }
|
||||
|
||||
virtual QString intendedVersion() const { return settings().get("IntendedJarVersion").toString(); }
|
||||
virtual void setIntendedVersion(QString val) { settings().set("IntendedJarVersion", val); }
|
||||
|
||||
virtual bool shouldUpdate() const
|
||||
{
|
||||
QVariant var = settings().get("ShouldUpdate");
|
||||
if(!var.isValid() || var.toBool() == false)
|
||||
{
|
||||
return intendedVersion() != currentVersion();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
virtual void setShouldUpdate(bool val) { settings().set("ShouldUpdate", val); }
|
||||
|
||||
//// Timestamps ////
|
||||
|
||||
virtual qint64 lastLaunch() const { return settings().get("lastLaunchTime").value<qint64>(); }
|
||||
virtual void setLastLaunch(qint64 val = QDateTime::currentMSecsSinceEpoch())
|
||||
{
|
||||
settings().set("lastLaunchTime", val);
|
||||
emit propertiesChanged(this);
|
||||
}
|
||||
|
||||
virtual qint64 lastCurrentVersionUpdate() const { return settings().get("lastVersionUpdate").value<qint64>(); }
|
||||
virtual void setLastCurrentVersionUpdate(qint64 val) { settings().set("lastVersionUpdate", val); }
|
||||
|
||||
////// Directories //////
|
||||
QString minecraftDir() const;
|
||||
QString instModsDir() const;
|
||||
QString binDir() const;
|
||||
QString savesDir() const;
|
||||
QString mlModsDir() const;
|
||||
QString coreModsDir() const;
|
||||
QString resourceDir() const;
|
||||
QString screenshotsDir() const;
|
||||
QString texturePacksDir() const;
|
||||
|
||||
|
||||
////// Files //////
|
||||
QString mcJar() const;
|
||||
QString mcBackup() const;
|
||||
QString modListFile() const;
|
||||
|
||||
|
||||
//////// LISTS, LISTS, AND MORE LISTS ////////
|
||||
/*!
|
||||
* \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;
|
||||
|
||||
|
||||
//////// OTHER FUNCTIONS ////////
|
||||
|
||||
//// Version System ////
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not the currentVersion of the instance needs to be updated.
|
||||
* If this returns true, updateCurrentVersion is called. In the
|
||||
* standard instance, this is determined by checking a timestamp
|
||||
* stored in the instance config file against the last modified time of Minecraft.jar.
|
||||
* \return True if updateCurrentVersion() should be called.
|
||||
*/
|
||||
virtual bool shouldUpdateCurrentVersion() const;
|
||||
|
||||
/*!
|
||||
* \brief Updates the current version.
|
||||
* This function should first set the current version timestamp
|
||||
* (setCurrentVersionTimestamp()) to the current time. Next, if
|
||||
* keepCurrent is false, this function should check what the
|
||||
* instance's current version is and call setCurrentVersion() to
|
||||
* update it. This function will automatically be called when the
|
||||
* instance is loaded if shouldUpdateCurrentVersion returns true.
|
||||
* \param keepCurrent If true, only the version timestamp will be updated.
|
||||
*/
|
||||
virtual void updateCurrentVersion(bool keepCurrent = false);
|
||||
|
||||
|
||||
//// Settings System ////
|
||||
|
||||
/*!
|
||||
* \brief Gets this instance's settings object.
|
||||
* This settings object stores instance-specific settings.
|
||||
* \return A pointer to this instance's settings object.
|
||||
*/
|
||||
virtual SettingsObject &settings() const;
|
||||
|
||||
signals:
|
||||
/*!
|
||||
* \brief Signal emitted when properties relevant to the instance view change
|
||||
*/
|
||||
void propertiesChanged(BaseInstance * inst);
|
||||
|
||||
private:
|
||||
QString m_rootDir;
|
||||
QString m_group;
|
||||
SettingsObject *m_settings;
|
||||
};
|
||||
|
||||
// pointer for lazy people
|
||||
typedef QSharedPointer<BaseInstance> InstancePtr;
|
||||
|
91
backend/CMakeLists.txt
Normal file
91
backend/CMakeLists.txt
Normal file
@ -0,0 +1,91 @@
|
||||
project(libMultiMC)
|
||||
|
||||
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})
|
||||
include_directories(${Qt5Network_INCLUDE_DIRS})
|
||||
|
||||
# Include utility library.
|
||||
include_directories(${CMAKE_SOURCE_DIR}/libutil/include)
|
||||
|
||||
# Include settings library.
|
||||
include_directories(${CMAKE_SOURCE_DIR}/libsettings/include)
|
||||
|
||||
SET(LIBINST_HEADERS
|
||||
libmmc_config.h
|
||||
|
||||
# Instance Stuff
|
||||
BaseInstance.h
|
||||
LegacyInstance.h
|
||||
OneSixInstance.h
|
||||
InstanceFactory.h
|
||||
|
||||
# Versions
|
||||
InstanceVersion.h
|
||||
MinecraftVersion.h
|
||||
OneSixVersion.h
|
||||
VersionFactory.h
|
||||
|
||||
# Lists
|
||||
lists/InstanceList.h
|
||||
lists/InstVersionList.h
|
||||
lists/MinecraftVersionList.h
|
||||
lists/LwjglVersionList.h
|
||||
|
||||
# Tasks
|
||||
tasks/Task.h
|
||||
tasks/LoginTask.h
|
||||
tasks/LoginResponse.h
|
||||
tasks/UserInfo.h
|
||||
tasks/GameUpdateTask.h
|
||||
|
||||
MinecraftProcess.h
|
||||
)
|
||||
|
||||
SET(LIBINST_SOURCES
|
||||
# Instance Stuff
|
||||
BaseInstance.cpp
|
||||
LegacyInstance.cpp
|
||||
OneSixInstance.cpp
|
||||
InstanceFactory.cpp
|
||||
|
||||
# Versions
|
||||
InstanceVersion.cpp
|
||||
MinecraftVersion.cpp
|
||||
OneSixVersion.cpp
|
||||
VersionFactory.cpp
|
||||
|
||||
# Lists
|
||||
lists/InstanceList.cpp
|
||||
lists/InstVersionList.cpp
|
||||
lists/MinecraftVersionList.cpp
|
||||
lists/LwjglVersionList.cpp
|
||||
|
||||
# Tasks
|
||||
tasks/Task.cpp
|
||||
tasks/LoginTask.cpp
|
||||
tasks/GameUpdateTask.cpp
|
||||
tasks/UserInfo.cpp
|
||||
tasks/LoginResponse.cpp
|
||||
|
||||
MinecraftProcess.cpp
|
||||
)
|
||||
|
||||
# Set the include dir path.
|
||||
SET(LIBMULTIMC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
|
||||
|
||||
# Include self.
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include_directories(${CMAKE_BINARY_DIR}/include)
|
||||
|
||||
add_definitions(-DLIBMULTIMC_LIBRARY)
|
||||
|
||||
add_library(backend SHARED ${LIBINST_SOURCES} ${LIBINST_HEADERS})
|
||||
qt5_use_modules(backend Core Network Xml)
|
||||
target_link_libraries(backend libUtil libSettings)
|
61
backend/InstanceFactory.cpp
Normal file
61
backend/InstanceFactory.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
/* 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 "InstanceFactory.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "BaseInstance.h"
|
||||
|
||||
#include "inifile.h"
|
||||
|
||||
#include "pathutils.h"
|
||||
|
||||
InstanceFactory InstanceFactory::loader;
|
||||
|
||||
InstanceFactory::InstanceFactory() :
|
||||
QObject(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst, const QString &instDir)
|
||||
{
|
||||
BaseInstance *loadedInst = new BaseInstance(instDir, this);
|
||||
|
||||
// TODO: Sanity checks to verify that the instance is valid.
|
||||
|
||||
inst = loadedInst;
|
||||
|
||||
return NoLoadError;
|
||||
}
|
||||
|
||||
|
||||
InstanceFactory::InstCreateError InstanceFactory::createInstance(BaseInstance *&inst, const QString &instDir)
|
||||
{
|
||||
QDir rootDir(instDir);
|
||||
|
||||
qDebug(instDir.toUtf8());
|
||||
if (!rootDir.exists() && !rootDir.mkpath("."))
|
||||
{
|
||||
return InstanceFactory::CantCreateDir;
|
||||
}
|
||||
|
||||
inst = new BaseInstance(instDir, this);
|
||||
|
||||
//FIXME: really, how do you even know?
|
||||
return InstanceFactory::NoCreateError;
|
||||
}
|
79
backend/InstanceFactory.h
Normal file
79
backend/InstanceFactory.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* 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 <QMap>
|
||||
#include <QList>
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
class BaseInstance;
|
||||
|
||||
/*!
|
||||
* The \bInstanceFactory\b is a singleton that manages loading and creating instances.
|
||||
*/
|
||||
class LIBMULTIMC_EXPORT InstanceFactory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/*!
|
||||
* \brief Gets a reference to the instance loader.
|
||||
*/
|
||||
static InstanceFactory &get() { return loader; }
|
||||
|
||||
enum InstLoadError
|
||||
{
|
||||
NoLoadError = 0,
|
||||
UnknownLoadError,
|
||||
NotAnInstance
|
||||
};
|
||||
|
||||
enum InstCreateError
|
||||
{
|
||||
NoCreateError = 0,
|
||||
UnknownCreateError,
|
||||
InstExists,
|
||||
CantCreateDir
|
||||
};
|
||||
|
||||
/*!
|
||||
* \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 InstCreateError error code.
|
||||
* - InstExists if the given instance directory is already an instance.
|
||||
* - CantCreateDir if the given instance directory cannot be created.
|
||||
*/
|
||||
InstCreateError createInstance(BaseInstance *&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 InstLoadError error code.
|
||||
* - NotAnInstance if the given instance directory isn't a valid instance.
|
||||
*/
|
||||
InstLoadError loadInstance(BaseInstance *&inst, const QString &instDir);
|
||||
|
||||
private:
|
||||
InstanceFactory();
|
||||
|
||||
static InstanceFactory loader;
|
||||
};
|
67
backend/InstanceVersion.cpp
Normal file
67
backend/InstanceVersion.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
/* 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 "InstanceVersion.h"
|
||||
#include "lists/InstVersionList.h"
|
||||
|
||||
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 either an InstVersionList or NULL.
|
||||
if (!parent() || !parent()->inherits("InstVersionList"))
|
||||
return NULL;
|
||||
else
|
||||
return (InstVersionList *)parent();
|
||||
}
|
||||
|
||||
bool InstVersion::isLessThan(const InstVersion &other) const
|
||||
{
|
||||
return timestamp() < other.timestamp();
|
||||
}
|
||||
|
||||
bool InstVersion::isGreaterThan(const InstVersion &other) const
|
||||
{
|
||||
return timestamp() > other.timestamp();
|
||||
}
|
||||
|
||||
QString InstVersion::descriptor() const
|
||||
{
|
||||
return m_descriptor;
|
||||
}
|
||||
|
||||
QString InstVersion::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
qint64 InstVersion::timestamp() const
|
||||
{
|
||||
return m_timestamp;
|
||||
}
|
121
backend/InstanceVersion.h
Normal file
121
backend/InstanceVersion.h
Normal file
@ -0,0 +1,121 @@
|
||||
/* 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 "libmmc_config.h"
|
||||
|
||||
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)
|
||||
|
||||
/*!
|
||||
* 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 will be added to the list immediately after being created.
|
||||
*/
|
||||
explicit InstVersion(const QString &descriptor,
|
||||
const QString &name,
|
||||
qint64 timestamp,
|
||||
InstVersionList *parent = 0);
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*/
|
||||
InstVersion(const InstVersion &other, QObject *parent = 0);
|
||||
|
||||
virtual QString descriptor() const;
|
||||
virtual QString name() const;
|
||||
virtual QString typeName() const = 0;
|
||||
virtual qint64 timestamp() const;
|
||||
|
||||
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;
|
||||
|
||||
/*!
|
||||
* 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 isLessThan(const InstVersion &other) const;
|
||||
|
||||
/*!
|
||||
* 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 isGreaterThan(const InstVersion &other) const;
|
||||
|
||||
/*!
|
||||
* \sa shouldSortBefore()
|
||||
*/
|
||||
virtual bool operator<(const InstVersion &rhs) { return isLessThan(rhs); }
|
||||
|
||||
/*!
|
||||
* \sa shouldSortAfter()
|
||||
*/
|
||||
virtual bool operator>(const InstVersion &rhs) { return isGreaterThan(rhs); }
|
||||
|
||||
protected:
|
||||
QString m_descriptor;
|
||||
QString m_name;
|
||||
qint64 m_timestamp;
|
||||
};
|
0
backend/LegacyInstance.cpp
Normal file
0
backend/LegacyInstance.cpp
Normal file
1
backend/LegacyInstance.h
Normal file
1
backend/LegacyInstance.h
Normal file
@ -0,0 +1 @@
|
||||
#pragma once
|
229
backend/MinecraftProcess.cpp
Normal file
229
backend/MinecraftProcess.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
* 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 "MinecraftProcess.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
//#include <QImage>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
#include "BaseInstance.h"
|
||||
|
||||
#include "osutils.h"
|
||||
#include "pathutils.h"
|
||||
#include "cmdutils.h"
|
||||
|
||||
#define LAUNCHER_FILE "MultiMCLauncher.jar"
|
||||
#define IBUS "@im=ibus"
|
||||
|
||||
// prepare tools
|
||||
inline void MinecraftProcess::extractIcon(BaseInstance *inst, QString destination)
|
||||
{
|
||||
// QImage(":/icons/instances/" + inst->iconKey()).save(destination);
|
||||
}
|
||||
|
||||
inline void MinecraftProcess::extractLauncher(QString destination)
|
||||
{
|
||||
QFile(":/launcher/launcher.jar").copy(destination);
|
||||
}
|
||||
|
||||
void MinecraftProcess::prepare(BaseInstance *inst)
|
||||
{
|
||||
extractLauncher(PathCombine(inst->minecraftDir(), LAUNCHER_FILE));
|
||||
extractIcon(inst, PathCombine(inst->minecraftDir(), "icon.png"));
|
||||
}
|
||||
|
||||
// constructor
|
||||
MinecraftProcess::MinecraftProcess(BaseInstance *inst, QString user, QString session) :
|
||||
m_instance(inst), m_user(user), m_session(session)
|
||||
{
|
||||
connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(finish(int, QProcess::ExitStatus)));
|
||||
|
||||
// prepare the process environment
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
|
||||
#ifdef LINUX
|
||||
// Strip IBus
|
||||
if (env.value("XMODIFIERS").contains(IBUS))
|
||||
env.insert("XMODIFIERS", env.value("XMODIFIERS").replace(IBUS, ""));
|
||||
#endif
|
||||
|
||||
// export some infos
|
||||
env.insert("INST_NAME", inst->name());
|
||||
env.insert("INST_ID", inst->id());
|
||||
env.insert("INST_DIR", QDir(inst->rootDir()).absolutePath());
|
||||
|
||||
this->setProcessEnvironment(env);
|
||||
m_prepostlaunchprocess.setProcessEnvironment(env);
|
||||
|
||||
// set the cwd
|
||||
QDir mcDir(inst->minecraftDir());
|
||||
this->setWorkingDirectory(mcDir.absolutePath());
|
||||
m_prepostlaunchprocess.setWorkingDirectory(mcDir.absolutePath());
|
||||
|
||||
// std channels
|
||||
connect(this, SIGNAL(readyReadStandardError()), SLOT(on_stdErr()));
|
||||
connect(this, SIGNAL(readyReadStandardOutput()), SLOT(on_stdOut()));
|
||||
}
|
||||
|
||||
// console window
|
||||
void MinecraftProcess::on_stdErr()
|
||||
{
|
||||
QByteArray data = readAllStandardError();
|
||||
QString str = m_err_leftover + QString::fromLocal8Bit(data);
|
||||
m_err_leftover.clear();
|
||||
QStringList lines = str.split("\n");
|
||||
bool complete = str.endsWith("\n");
|
||||
|
||||
for(int i = 0; i < lines.size() - 1; i++)
|
||||
{
|
||||
QString & line = lines[i];
|
||||
MessageLevel::Enum level = MessageLevel::Error;
|
||||
if(line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || line.contains("[FINER]") || line.contains("[FINEST]") )
|
||||
level = MessageLevel::Message;
|
||||
if(line.contains("[SEVERE]") || line.contains("[WARNING]") || line.contains("[STDERR]"))
|
||||
level = MessageLevel::Error;
|
||||
emit log(lines[i].toLocal8Bit(), level);
|
||||
}
|
||||
if(!complete)
|
||||
m_err_leftover = lines.last();
|
||||
}
|
||||
|
||||
void MinecraftProcess::on_stdOut()
|
||||
{
|
||||
QByteArray data = readAllStandardOutput();
|
||||
QString str = m_out_leftover + QString::fromLocal8Bit(data);
|
||||
m_out_leftover.clear();
|
||||
QStringList lines = str.split("\n");
|
||||
bool complete = str.endsWith("\n");
|
||||
|
||||
for(int i = 0; i < lines.size() - 1; i++)
|
||||
{
|
||||
QString & line = lines[i];
|
||||
emit log(lines[i].toLocal8Bit(), MessageLevel::Message);
|
||||
}
|
||||
if(!complete)
|
||||
m_out_leftover = lines.last();
|
||||
}
|
||||
|
||||
// exit handler
|
||||
void MinecraftProcess::finish(int code, ExitStatus status)
|
||||
{
|
||||
if (status != NormalExit)
|
||||
{
|
||||
//TODO: error handling
|
||||
}
|
||||
|
||||
emit log("Minecraft exited.");
|
||||
|
||||
m_prepostlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(code));
|
||||
|
||||
// run post-exit
|
||||
if (!m_instance->settings().get("PostExitCommand").toString().isEmpty())
|
||||
{
|
||||
m_prepostlaunchprocess.start(m_instance->settings().get("PostExitCommand").toString());
|
||||
m_prepostlaunchprocess.waitForFinished();
|
||||
if (m_prepostlaunchprocess.exitStatus() != NormalExit)
|
||||
{
|
||||
//TODO: error handling
|
||||
}
|
||||
}
|
||||
|
||||
// if (m_console != nullptr)
|
||||
// m_console->setMayClose(true);
|
||||
|
||||
emit ended();
|
||||
}
|
||||
|
||||
void MinecraftProcess::launch()
|
||||
{
|
||||
if (!m_instance->settings().get("PreLaunchCommand").toString().isEmpty())
|
||||
{
|
||||
m_prepostlaunchprocess.start(m_instance->settings().get("PreLaunchCommand").toString());
|
||||
m_prepostlaunchprocess.waitForFinished();
|
||||
if (m_prepostlaunchprocess.exitStatus() != NormalExit)
|
||||
{
|
||||
//TODO: error handling
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_instance->setLastLaunch();
|
||||
|
||||
prepare(m_instance);
|
||||
|
||||
genArgs();
|
||||
|
||||
emit log(QString("Minecraft folder is: '%1'").arg(workingDirectory()));
|
||||
QString JavaPath = m_instance->settings().get("JavaPath").toString();
|
||||
emit log(QString("Java path: '%1'").arg(JavaPath));
|
||||
emit log(QString("Arguments: '%1'").arg(m_arguments.join("' '")));
|
||||
start(JavaPath, m_arguments);
|
||||
if (!waitForStarted())
|
||||
{
|
||||
emit log("Could not launch minecraft!");
|
||||
return;
|
||||
//TODO: error handling
|
||||
}
|
||||
|
||||
// if(m_console != nullptr)
|
||||
// m_console->setMayClose(false);
|
||||
}
|
||||
|
||||
void MinecraftProcess::genArgs()
|
||||
{
|
||||
// start fresh
|
||||
m_arguments.clear();
|
||||
|
||||
// window size
|
||||
QString windowSize;
|
||||
if (m_instance->settings().get("LaunchMaximized").toBool())
|
||||
windowSize = "max";
|
||||
else
|
||||
windowSize = QString("%1x%2").
|
||||
arg(m_instance->settings().get("MinecraftWinWidth").toInt()).
|
||||
arg(m_instance->settings().get("MinecraftWinHeight").toInt());
|
||||
|
||||
// window title
|
||||
QString windowTitle;
|
||||
windowTitle.append("MultiMC: ").append(m_instance->name());
|
||||
|
||||
// Java arguments
|
||||
m_arguments.append(Util::Commandline::splitArgs(m_instance->settings().get("JvmArgs").toString()));
|
||||
|
||||
#ifdef OSX
|
||||
// OSX dock icon and name
|
||||
m_arguments << "-Xdock:icon=icon.png";
|
||||
m_arguments << QString("-Xdock:name=\"%1\"").arg(windowTitle);
|
||||
#endif
|
||||
|
||||
// lwjgl
|
||||
QString lwjgl = QDir(globalSettings->get("LWJGLDir").toString() + "/" +
|
||||
m_instance->lwjglVersion()).absolutePath();
|
||||
|
||||
// launcher arguments
|
||||
m_arguments << QString("-Xms%1m").arg(m_instance->settings().get("MinMemAlloc").toInt());
|
||||
m_arguments << QString("-Xmx%1m").arg(m_instance->settings().get("MaxMemAlloc").toInt());
|
||||
m_arguments << "-jar" << LAUNCHER_FILE;
|
||||
m_arguments << m_user;
|
||||
m_arguments << m_session;
|
||||
m_arguments << windowTitle;
|
||||
m_arguments << windowSize;
|
||||
m_arguments << lwjgl;
|
||||
}
|
111
backend/MinecraftProcess.h
Normal file
111
backend/MinecraftProcess.h
Normal file
@ -0,0 +1,111 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
* 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 <QProcess>
|
||||
|
||||
#include "BaseInstance.h"
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
/**
|
||||
* @brief the MessageLevel Enum
|
||||
* defines what level a message is
|
||||
*/
|
||||
namespace MessageLevel {
|
||||
enum LIBMULTIMC_EXPORT Enum {
|
||||
MultiMC, /**< MultiMC Messages */
|
||||
Debug, /**< Debug Messages */
|
||||
Info, /**< Info Messages */
|
||||
Message, /**< Standard Messages */
|
||||
Warning, /**< Warnings */
|
||||
Error, /**< Errors */
|
||||
Fatal /**< Fatal Errors */
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @file data/minecraftprocess.h
|
||||
* @brief The MinecraftProcess class
|
||||
*/
|
||||
class LIBMULTIMC_EXPORT MinecraftProcess : public QProcess
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief MinecraftProcess constructor
|
||||
* @param inst the Instance pointer to launch
|
||||
* @param user the minecraft username
|
||||
* @param session the minecraft session id
|
||||
* @param console the instance console window
|
||||
*/
|
||||
MinecraftProcess(BaseInstance *inst, QString user, QString session);
|
||||
|
||||
/**
|
||||
* @brief launch minecraft
|
||||
*/
|
||||
void launch();
|
||||
|
||||
/**
|
||||
* @brief extract the instance icon
|
||||
* @param inst the instance
|
||||
* @param destination the destination path
|
||||
*/
|
||||
static inline void extractIcon(BaseInstance *inst, QString destination);
|
||||
|
||||
/**
|
||||
* @brief extract the MultiMC launcher.jar
|
||||
* @param destination the destination path
|
||||
*/
|
||||
static inline void extractLauncher(QString destination);
|
||||
|
||||
/**
|
||||
* @brief prepare the launch by extracting icon and launcher
|
||||
* @param inst the instance
|
||||
*/
|
||||
static void prepare(BaseInstance *inst);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief emitted when mc has finished and the PostLaunchCommand was run
|
||||
*/
|
||||
void ended();
|
||||
|
||||
/**
|
||||
* @brief emitted when we want to log something
|
||||
* @param text the text to log
|
||||
* @param level the level to log at
|
||||
*/
|
||||
void log(QString text, MessageLevel::Enum level=MessageLevel::MultiMC);
|
||||
|
||||
protected:
|
||||
BaseInstance *m_instance;
|
||||
QString m_user;
|
||||
QString m_session;
|
||||
QString m_err_leftover;
|
||||
QString m_out_leftover;
|
||||
QProcess m_prepostlaunchprocess;
|
||||
QStringList m_arguments;
|
||||
|
||||
void genArgs();
|
||||
|
||||
protected slots:
|
||||
void finish(int, QProcess::ExitStatus status);
|
||||
void on_stdErr();
|
||||
void on_stdOut();
|
||||
|
||||
};
|
104
backend/MinecraftVersion.cpp
Normal file
104
backend/MinecraftVersion.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
/* 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)
|
||||
{
|
||||
}
|
||||
|
||||
QString MinecraftVersion::descriptor() const
|
||||
{
|
||||
return m_descriptor;
|
||||
}
|
||||
|
||||
QString MinecraftVersion::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
QString MinecraftVersion::typeName() const
|
||||
{
|
||||
switch (versionType())
|
||||
{
|
||||
case OldSnapshot:
|
||||
return "Snapshot";
|
||||
|
||||
case Stable:
|
||||
return "Stable";
|
||||
|
||||
case CurrentStable:
|
||||
return "Current Stable";
|
||||
|
||||
case Snapshot:
|
||||
return "Snapshot";
|
||||
|
||||
case MCNostalgia:
|
||||
return "MCNostalgia";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
MinecraftVersion::VersionSource MinecraftVersion::versionSource() const
|
||||
{
|
||||
return m_versionSource;
|
||||
};
|
||||
|
||||
void MinecraftVersion::setVersionSource(VersionSource launcherVersion)
|
||||
{
|
||||
m_versionSource = launcherVersion;
|
||||
}
|
||||
|
||||
InstVersion *MinecraftVersion::copyVersion(InstVersionList *newParent) const
|
||||
{
|
||||
MinecraftVersion *version = new MinecraftVersion(
|
||||
descriptor(), name(), timestamp(), downloadURL(), etag(), newParent);
|
||||
version->setVersionType(versionType());
|
||||
version->setVersionSource(VersionSource());
|
||||
return version;
|
||||
}
|
80
backend/MinecraftVersion.h
Normal file
80
backend/MinecraftVersion.h
Normal file
@ -0,0 +1,80 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
#include "InstanceVersion.h"
|
||||
|
||||
class LIBMULTIMC_EXPORT MinecraftVersion : public InstVersion
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MinecraftVersion(QString descriptor,
|
||||
QString name,
|
||||
qint64 timestamp,
|
||||
QString dlUrl,
|
||||
QString etag,
|
||||
InstVersionList *parent = 0);
|
||||
|
||||
static InstVersion *mcnVersion(QString rawName, QString niceName);
|
||||
|
||||
enum VersionType
|
||||
{
|
||||
OldSnapshot,
|
||||
Stable,
|
||||
CurrentStable,
|
||||
Snapshot,
|
||||
MCNostalgia
|
||||
};
|
||||
|
||||
enum VersionSource
|
||||
{
|
||||
Unknown = -1,
|
||||
Legacy = 0, // the legacy launcher that's been around since ... forever
|
||||
Launcher16 = 1, // current launcher as of 26/06/2013
|
||||
};
|
||||
|
||||
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 VersionSource versionSource() const;
|
||||
virtual void setVersionSource(VersionSource launcherVersion);
|
||||
|
||||
virtual QString downloadURL() const;
|
||||
virtual QString etag() const;
|
||||
|
||||
virtual InstVersion *copyVersion(InstVersionList *newParent) const;
|
||||
|
||||
private:
|
||||
/// The URL that this version will be downloaded from. maybe.
|
||||
QString m_dlUrl;
|
||||
|
||||
/// ETag/MD5 Used to verify the integrity of the downloaded minecraft.jar.
|
||||
QString m_etag;
|
||||
|
||||
/// This version's type. Used internally to identify what kind of version this is.
|
||||
VersionType m_type;
|
||||
|
||||
/// Whete to get the full version info (or, where did we get this version from originally)
|
||||
VersionSource m_versionSource;
|
||||
};
|
0
backend/OneSixInstance.cpp
Normal file
0
backend/OneSixInstance.cpp
Normal file
1
backend/OneSixInstance.h
Normal file
1
backend/OneSixInstance.h
Normal file
@ -0,0 +1 @@
|
||||
#pragma once
|
91
backend/OneSixVersion.cpp
Normal file
91
backend/OneSixVersion.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
#include "OneSixVersion.h"
|
||||
|
||||
RuleAction RuleAction_fromString(QString name)
|
||||
{
|
||||
if(name == "allow")
|
||||
return Allow;
|
||||
if(name == "disallow")
|
||||
return Disallow;
|
||||
return Defer;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void Library::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_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 );
|
||||
}
|
||||
}
|
||||
|
||||
QList<QSharedPointer<Library> > FullVersion::getActiveNormalLibs()
|
||||
{
|
||||
QList<QSharedPointer<Library> > output;
|
||||
for ( auto lib: libraries )
|
||||
{
|
||||
if (lib->getIsActive() && !lib->getIsNative())
|
||||
{
|
||||
output.append(lib);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
QList<QSharedPointer<Library> > FullVersion::getActiveNativeLibs()
|
||||
{
|
||||
QList<QSharedPointer<Library> > output;
|
||||
for ( auto lib: libraries )
|
||||
{
|
||||
if (lib->getIsActive() && lib->getIsNative())
|
||||
{
|
||||
output.append(lib);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
265
backend/OneSixVersion.h
Normal file
265
backend/OneSixVersion.h
Normal file
@ -0,0 +1,265 @@
|
||||
#pragma once
|
||||
#include <QtCore>
|
||||
|
||||
class Library;
|
||||
|
||||
enum OpSys
|
||||
{
|
||||
Os_Windows,
|
||||
Os_Linux,
|
||||
Os_OSX,
|
||||
Os_Other
|
||||
};
|
||||
|
||||
OpSys OpSys_fromString(QString);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#define currentSystem Os_OSX
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#define currentSystem Os_Linux
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#define currentSystem Os_Windows
|
||||
#endif
|
||||
|
||||
#ifndef currentSystem
|
||||
#define currentSystem Os_Other
|
||||
#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
|
||||
{
|
||||
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 actuall active on the current OS?
|
||||
bool m_is_active;
|
||||
|
||||
// native lib?
|
||||
bool m_is_native;
|
||||
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)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the url base for downloads
|
||||
*/
|
||||
void setBaseUrl(QString base_url)
|
||||
{
|
||||
m_base_url = base_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to mark the library as 'native' (it's a zip archive with DLLs)
|
||||
*/
|
||||
void setIsNative()
|
||||
{
|
||||
m_is_native = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a name suffix to the specified OS native
|
||||
*/
|
||||
void addNative(OpSys os, QString suffix)
|
||||
{
|
||||
m_is_native = true;
|
||||
m_native_suffixes[os] = suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the load rules
|
||||
*/
|
||||
void setRules(QList<QSharedPointer<Rule> > rules)
|
||||
{
|
||||
m_rules = rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the library should be loaded (or extracted, in case of natives)
|
||||
*/
|
||||
bool getIsActive()
|
||||
{
|
||||
return m_is_active;
|
||||
}
|
||||
/**
|
||||
* Returns true if the library is native
|
||||
*/
|
||||
bool getIsNative()
|
||||
{
|
||||
return m_is_native;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class FullVersion
|
||||
{
|
||||
public:
|
||||
/// the ID - determines which jar to use! ACTUALLY IMPORTANT!
|
||||
QString id;
|
||||
/// Last updated time - as a string
|
||||
QString time;
|
||||
/// Release time - as a string
|
||||
QString releaseTime;
|
||||
/// Release type - "release" or "snapshot"
|
||||
QString type;
|
||||
/**
|
||||
* DEPRECATED: Old versions of the new vanilla launcher used this
|
||||
* ex: "username_session_version"
|
||||
*/
|
||||
QString processArguments;
|
||||
/**
|
||||
* arguments that should be used for launching minecraft
|
||||
*
|
||||
* ex: "--username ${auth_player_name} --session ${auth_session}
|
||||
* --version ${version_name} --gameDir ${game_directory} --assetsDir ${game_assets}"
|
||||
*/
|
||||
QString minecraftArguments;
|
||||
/**
|
||||
* the minimum launcher version required by this version ... current is 4 (at point of writing)
|
||||
*/
|
||||
int minimumLauncherVersion;
|
||||
/**
|
||||
* The main class to load first
|
||||
*/
|
||||
QString mainClass;
|
||||
|
||||
/// the list of libs - both active and inactive, native and java
|
||||
QList<QSharedPointer<Library> > libraries;
|
||||
|
||||
/**
|
||||
* is this actually a legacy version? if so, none of the other stuff here will be ever used.
|
||||
* added by FullVersionFactory
|
||||
*/
|
||||
bool isLegacy;
|
||||
|
||||
/*
|
||||
FIXME: add support for those rules here? Looks like a pile of quick hacks to me though.
|
||||
|
||||
"rules": [
|
||||
{
|
||||
"action": "allow"
|
||||
},
|
||||
{
|
||||
"action": "disallow",
|
||||
"os": {
|
||||
"name": "osx",
|
||||
"version": "^10\\.5\\.\\d$"
|
||||
}
|
||||
}
|
||||
],
|
||||
"incompatibilityReason": "There is a bug in LWJGL which makes it incompatible with OSX 10.5.8. Please go to New Profile and use 1.5.2 for now. Sorry!"
|
||||
}
|
||||
*/
|
||||
// QList<Rule> rules;
|
||||
|
||||
public:
|
||||
FullVersion()
|
||||
{
|
||||
minimumLauncherVersion = 0xDEADBEEF;
|
||||
isLegacy = false;
|
||||
}
|
||||
|
||||
QList<QSharedPointer<Library> > getActiveNormalLibs();
|
||||
QList<QSharedPointer<Library> > getActiveNativeLibs();
|
||||
};
|
194
backend/VersionFactory.cpp
Normal file
194
backend/VersionFactory.cpp
Normal file
@ -0,0 +1,194 @@
|
||||
#include "VersionFactory.h"
|
||||
#include "OneSixVersion.h"
|
||||
|
||||
// Library rules (if any)
|
||||
QList<QSharedPointer<Rule> > FullVersionFactory::parse4rules(QJsonObject & baseObj)
|
||||
{
|
||||
QList<QSharedPointer<Rule> > rules;
|
||||
auto rulesVal = baseObj.value("rules");
|
||||
if(rulesVal.isArray())
|
||||
{
|
||||
QJsonArray ruleList = rulesVal.toArray();
|
||||
for(auto ruleVal : ruleList)
|
||||
{
|
||||
QSharedPointer<Rule> rule;
|
||||
if(!ruleVal.isObject())
|
||||
continue;
|
||||
auto ruleObj = ruleVal.toObject();
|
||||
auto actionVal = ruleObj.value("action");
|
||||
if(!actionVal.isString())
|
||||
continue;
|
||||
auto action = RuleAction_fromString(actionVal.toString());
|
||||
if(action == Defer)
|
||||
continue;
|
||||
|
||||
auto osVal = ruleObj.value("os");
|
||||
if(!osVal.isObject())
|
||||
{
|
||||
// add a new implicit action rule
|
||||
rules.append(ImplicitRule::create(action));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto osObj = osVal.toObject();
|
||||
auto osNameVal = osObj.value("name");
|
||||
if(!osNameVal.isString())
|
||||
continue;
|
||||
OpSys requiredOs = OpSys_fromString(osNameVal.toString());
|
||||
QString versionRegex = osObj.value("version").toString();
|
||||
// add a new OS rule
|
||||
rules.append(OsRule::create(action, requiredOs, versionRegex));
|
||||
}
|
||||
}
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
|
||||
QSharedPointer<FullVersion> FullVersionFactory::parse4(QJsonObject root, QSharedPointer<FullVersion> fullVersion)
|
||||
{
|
||||
fullVersion->id = root.value("id").toString();
|
||||
|
||||
// if it's on our legacy list, it's legacy
|
||||
if(legacyWhitelist.contains(fullVersion->id))
|
||||
fullVersion->isLegacy = true;
|
||||
|
||||
fullVersion->mainClass = root.value("mainClass").toString();
|
||||
auto procArgsValue = root.value("processArguments");
|
||||
if(procArgsValue.isString())
|
||||
{
|
||||
fullVersion->processArguments = procArgsValue.toString();
|
||||
QString toCompare = fullVersion->processArguments.toLower();
|
||||
if(toCompare == "legacy")
|
||||
{
|
||||
fullVersion->minecraftArguments = " ${auth_player_name} ${auth_session}";
|
||||
fullVersion->isLegacy = true;
|
||||
}
|
||||
else if(toCompare == "username_session")
|
||||
{
|
||||
fullVersion->minecraftArguments = "--username ${auth_player_name} --session ${auth_session}";
|
||||
}
|
||||
else if(toCompare == "username_session_version")
|
||||
{
|
||||
fullVersion->minecraftArguments = "--username ${auth_player_name} --session ${auth_session} --version ${profile_name}";
|
||||
}
|
||||
}
|
||||
|
||||
auto minecraftArgsValue = root.value("minecraftArguments");
|
||||
if(minecraftArgsValue.isString())
|
||||
{
|
||||
fullVersion->minecraftArguments = minecraftArgsValue.toString();
|
||||
}
|
||||
|
||||
fullVersion->releaseTime = root.value("releaseTime").toString();
|
||||
fullVersion->time = root.value("time").toString();
|
||||
|
||||
// Iterate through the list, if it's a list.
|
||||
auto librariesValue = root.value("libraries");
|
||||
if(!librariesValue.isArray())
|
||||
return fullVersion;
|
||||
|
||||
QJsonArray libList = root.value("libraries").toArray();
|
||||
for (auto libVal : libList)
|
||||
{
|
||||
if (!libVal.isObject())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QJsonObject libObj = libVal.toObject();
|
||||
|
||||
// Library name
|
||||
auto nameVal = libObj.value("name");
|
||||
if(!nameVal.isString())
|
||||
continue;
|
||||
QSharedPointer<Library> library(new Library(nameVal.toString()));
|
||||
|
||||
// Extract excludes (if any)
|
||||
auto extractVal = libObj.value("extract");
|
||||
if(extractVal.isObject())
|
||||
{
|
||||
QStringList excludes;
|
||||
auto extractObj = extractVal.toObject();
|
||||
auto excludesVal = extractObj.value("exclude");
|
||||
if(!excludesVal.isArray())
|
||||
goto SKIP_EXTRACTS;
|
||||
auto excludesList = excludesVal.toArray();
|
||||
for(auto excludeVal : excludesList)
|
||||
{
|
||||
if(excludeVal.isString())
|
||||
excludes.append(excludeVal.toString());
|
||||
}
|
||||
library->extract_excludes = excludes;
|
||||
}
|
||||
SKIP_EXTRACTS:
|
||||
|
||||
auto nativesVal = libObj.value("natives");
|
||||
if(nativesVal.isObject())
|
||||
{
|
||||
library->setIsNative();
|
||||
auto nativesObj = nativesVal.toObject();
|
||||
auto iter = nativesObj.begin();
|
||||
while(iter != nativesObj.end())
|
||||
{
|
||||
auto osType = OpSys_fromString(iter.key());
|
||||
if(osType == Os_Other)
|
||||
continue;
|
||||
if(!iter.value().isString())
|
||||
continue;
|
||||
library->addNative(osType, iter.value().toString());
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
library->setRules(parse4rules(libObj));
|
||||
library->finalize();
|
||||
fullVersion->libraries.append(library);
|
||||
}
|
||||
return fullVersion;
|
||||
}
|
||||
|
||||
QSharedPointer<FullVersion> FullVersionFactory::parse(QByteArray data)
|
||||
{
|
||||
QSharedPointer<FullVersion> readVersion(new FullVersion());
|
||||
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
||||
|
||||
if (jsonError.error != QJsonParseError::NoError)
|
||||
{
|
||||
error_string = QString( "Error reading version file :") + " " + jsonError.errorString();
|
||||
m_error = FullVersionFactory::ParseError;
|
||||
return QSharedPointer<FullVersion>();
|
||||
}
|
||||
|
||||
if(!jsonDoc.isObject())
|
||||
{
|
||||
error_string = "Error reading version file.";
|
||||
m_error = FullVersionFactory::ParseError;
|
||||
return QSharedPointer<FullVersion>();
|
||||
}
|
||||
QJsonObject root = jsonDoc.object();
|
||||
|
||||
readVersion->minimumLauncherVersion = root.value("minimumLauncherVersion").toDouble();
|
||||
switch(readVersion->minimumLauncherVersion)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
return parse4(root, readVersion);
|
||||
// ADD MORE HERE :D
|
||||
default:
|
||||
error_string = "Version file was for an unrecognized launcher version. RIP";
|
||||
m_error = FullVersionFactory::UnsupportedVersion;
|
||||
return QSharedPointer<FullVersion>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FullVersionFactory::FullVersionFactory()
|
||||
{
|
||||
m_error = FullVersionFactory::AllOK;
|
||||
legacyWhitelist.append("1.5.1");
|
||||
legacyWhitelist.append("1.5.2");
|
||||
}
|
25
backend/VersionFactory.h
Normal file
25
backend/VersionFactory.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include <QtCore>
|
||||
|
||||
struct FullVersion;
|
||||
class Rule;
|
||||
|
||||
class FullVersionFactory
|
||||
{
|
||||
public:
|
||||
enum Error
|
||||
{
|
||||
AllOK, // all parsed OK
|
||||
ParseError, // the file was corrupted somehow
|
||||
UnsupportedVersion // the file was meant for a launcher version we don't support (yet)
|
||||
} m_error;
|
||||
QString error_string;
|
||||
|
||||
public:
|
||||
FullVersionFactory();
|
||||
QSharedPointer<FullVersion> parse(QByteArray data);
|
||||
private:
|
||||
QSharedPointer<FullVersion> parse4(QJsonObject root, QSharedPointer<FullVersion> product);
|
||||
QList<QSharedPointer<Rule> > parse4rules(QJsonObject & baseObj);
|
||||
QStringList legacyWhitelist;
|
||||
};
|
24
backend/libmmc_config.h
Normal file
24
backend/libmmc_config.h
Normal file
@ -0,0 +1,24 @@
|
||||
/* 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 <QtCore/QtGlobal>
|
||||
|
||||
#ifdef LIBMULTIMC_LIBRARY
|
||||
# define LIBMULTIMC_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define LIBMULTIMC_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
129
backend/lists/InstVersionList.cpp
Normal file
129
backend/lists/InstVersionList.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
/* 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 "InstVersionList.h"
|
||||
#include "InstanceVersion.h"
|
||||
|
||||
InstVersionList::InstVersionList(QObject *parent) :
|
||||
QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
const InstVersion *InstVersionList::findVersion(const QString &descriptor)
|
||||
{
|
||||
for (int i = 0; i < count(); i++)
|
||||
{
|
||||
if (at(i)->descriptor() == descriptor)
|
||||
return at(i);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const InstVersion *InstVersionList::getLatestStable() const
|
||||
{
|
||||
if (count() <= 0)
|
||||
return NULL;
|
||||
else
|
||||
return at(0);
|
||||
}
|
||||
|
||||
QVariant InstVersionList::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (index.row() > count())
|
||||
return QVariant();
|
||||
|
||||
|
||||
const InstVersion *version = at(index.row());
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column())
|
||||
{
|
||||
case NameColumn:
|
||||
return version->name();
|
||||
|
||||
case TypeColumn:
|
||||
return version->typeName();
|
||||
|
||||
case TimeColumn:
|
||||
return version->timestamp();
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
case Qt::ToolTipRole:
|
||||
return version->descriptor();
|
||||
|
||||
case VersionPointerRole:
|
||||
return qVariantFromValue((void *) version);
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant InstVersionList::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
switch (section)
|
||||
{
|
||||
case NameColumn:
|
||||
return "Name";
|
||||
|
||||
case TypeColumn:
|
||||
return "Type";
|
||||
|
||||
case TimeColumn:
|
||||
return "Time";
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
case Qt::ToolTipRole:
|
||||
switch (section)
|
||||
{
|
||||
case NameColumn:
|
||||
return "The name of the version.";
|
||||
|
||||
case TypeColumn:
|
||||
return "The version's type.";
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
int InstVersionList::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
// Return count
|
||||
return count();
|
||||
}
|
||||
|
||||
int InstVersionList::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 2;
|
||||
}
|
121
backend/lists/InstVersionList.h
Normal file
121
backend/lists/InstVersionList.h
Normal file
@ -0,0 +1,121 @@
|
||||
/* 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 <QVariant>
|
||||
#include <QAbstractListModel>
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
class InstVersion;
|
||||
class Task;
|
||||
|
||||
/*!
|
||||
* \brief Class that each instance type's version list derives from.
|
||||
* Version lists are the lists that keep track of the available game versions
|
||||
* for that instance. This list will not be loaded on startup. It will be loaded
|
||||
* when the list's load function is called. Before using the version list, you
|
||||
* should check to see if it has been loaded yet and if not, load the list.
|
||||
*
|
||||
* Note that this class also inherits from QAbstractListModel. Methods from that
|
||||
* class determine how this version list shows up in a list view. Said methods
|
||||
* all have a default implementation, but they can be overridden by plugins to
|
||||
* change the behavior of the list.
|
||||
*/
|
||||
class LIBMULTIMC_EXPORT InstVersionList : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ModelRoles
|
||||
{
|
||||
VersionPointerRole = 0x34B1CB48
|
||||
};
|
||||
|
||||
enum VListColumns
|
||||
{
|
||||
// First column - Name
|
||||
NameColumn = 0,
|
||||
|
||||
// Second column - Type
|
||||
TypeColumn,
|
||||
|
||||
// Third column - Timestamp
|
||||
TimeColumn
|
||||
};
|
||||
|
||||
explicit InstVersionList(QObject *parent = 0);
|
||||
|
||||
/*!
|
||||
* \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.
|
||||
*/
|
||||
virtual Task *getLoadTask() = 0;
|
||||
|
||||
//! Checks whether or not the list is loaded. If this returns false, the list should be loaded.
|
||||
virtual bool isLoaded() = 0;
|
||||
|
||||
//! Gets the version at the given index.
|
||||
virtual const InstVersion *at(int i) const = 0;
|
||||
|
||||
//! Returns the number of versions in the list.
|
||||
virtual int count() const = 0;
|
||||
|
||||
|
||||
//////// List Model Functions ////////
|
||||
virtual QVariant data(const QModelIndex &index, int role) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||
virtual int rowCount(const QModelIndex &parent) const;
|
||||
virtual int columnCount(const QModelIndex &parent) const;
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Finds a version by its descriptor.
|
||||
* \param The descriptor of the version to find.
|
||||
* \return A const pointer to the version with the given descriptor. NULL if
|
||||
* one doesn't exist.
|
||||
*/
|
||||
virtual const InstVersion *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 const InstVersion *getLatestStable() const;
|
||||
|
||||
/*!
|
||||
* Sorts the version list.
|
||||
*/
|
||||
virtual void sort() = 0;
|
||||
|
||||
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;
|
||||
};
|
232
backend/lists/InstanceList.cpp
Normal file
232
backend/lists/InstanceList.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
/* 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 <QDir>
|
||||
#include <QFile>
|
||||
#include <QDirIterator>
|
||||
#include <QThread>
|
||||
#include <QTextStream>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include "lists/InstanceList.h"
|
||||
#include "BaseInstance.h"
|
||||
#include "InstanceFactory.h"
|
||||
|
||||
#include "pathutils.h"
|
||||
|
||||
const static int GROUP_FILE_FORMAT_VERSION = 1;
|
||||
|
||||
InstanceList::InstanceList(const QString &instDir, QObject *parent) :
|
||||
QObject(parent), m_instDir("instances")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void InstanceList::loadGroupList(QMap<QString, QString> & groupMap)
|
||||
{
|
||||
QString groupFileName = m_instDir + "/instgroups.json";
|
||||
|
||||
// if there's no group file, fail
|
||||
if(!QFileInfo(groupFileName).exists())
|
||||
return;
|
||||
|
||||
QFile groupFile(groupFileName);
|
||||
|
||||
// if you can't open the file, fail
|
||||
if (!groupFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
// An error occurred. Ignore it.
|
||||
qDebug("Failed to read instance group file.");
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream in(&groupFile);
|
||||
QString jsonStr = in.readAll();
|
||||
groupFile.close();
|
||||
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonStr.toUtf8(), &error);
|
||||
|
||||
// if the json was bad, fail
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
{
|
||||
qWarning(QString("Failed to parse instance group file: %1 at offset %2").
|
||||
arg(error.errorString(), QString::number(error.offset)).toUtf8());
|
||||
return;
|
||||
}
|
||||
|
||||
// if the root of the json wasn't an object, fail
|
||||
if (!jsonDoc.isObject())
|
||||
{
|
||||
qWarning("Invalid group file. Root entry should be an object.");
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject rootObj = jsonDoc.object();
|
||||
|
||||
// Make sure the format version matches, otherwise fail.
|
||||
if (rootObj.value("formatVersion").toVariant().toInt() != GROUP_FILE_FORMAT_VERSION)
|
||||
return;
|
||||
|
||||
// Get the groups. if it's not an object, fail
|
||||
if (!rootObj.value("groups").isObject())
|
||||
{
|
||||
qWarning("Invalid group list JSON: 'groups' should be an object.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate through all the groups.
|
||||
QJsonObject groupMapping = rootObj.value("groups").toObject();
|
||||
for (QJsonObject::iterator iter = groupMapping.begin(); iter != groupMapping.end(); iter++)
|
||||
{
|
||||
QString groupName = iter.key();
|
||||
|
||||
// If not an object, complain and skip to the next one.
|
||||
if (!iter.value().isObject())
|
||||
{
|
||||
qWarning(QString("Group '%1' in the group list should "
|
||||
"be an object.").arg(groupName).toUtf8());
|
||||
continue;
|
||||
}
|
||||
|
||||
QJsonObject groupObj = iter.value().toObject();
|
||||
if (!groupObj.value("instances").isArray())
|
||||
{
|
||||
qWarning(QString("Group '%1' in the group list is invalid. "
|
||||
"It should contain an array "
|
||||
"called 'instances'.").arg(groupName).toUtf8());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Iterate through the list of instances in the group.
|
||||
QJsonArray instancesArray = groupObj.value("instances").toArray();
|
||||
|
||||
for (QJsonArray::iterator iter2 = instancesArray.begin();
|
||||
iter2 != instancesArray.end(); iter2++)
|
||||
{
|
||||
groupMap[(*iter2).toString()] = groupName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstanceList::InstListError InstanceList::loadList()
|
||||
{
|
||||
// load the instance groups
|
||||
QMap<QString, QString> groupMap;
|
||||
loadGroupList(groupMap);
|
||||
|
||||
m_instances.clear();
|
||||
QDir dir(m_instDir);
|
||||
QDirIterator iter(dir);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
QString subDir = iter.next();
|
||||
if (!QFileInfo(PathCombine(subDir, "instance.cfg")).exists())
|
||||
continue;
|
||||
|
||||
BaseInstance *instPtr = NULL;
|
||||
auto &loader = InstanceFactory::get();
|
||||
auto error = loader.loadInstance(instPtr, subDir);
|
||||
|
||||
switch(error)
|
||||
{
|
||||
case InstanceFactory::NoLoadError:
|
||||
break;
|
||||
case InstanceFactory::NotAnInstance:
|
||||
break;
|
||||
}
|
||||
|
||||
if (error != InstanceFactory::NoLoadError &&
|
||||
error != InstanceFactory::NotAnInstance)
|
||||
{
|
||||
QString errorMsg = QString("Failed to load instance %1: ").
|
||||
arg(QFileInfo(subDir).baseName()).toUtf8();
|
||||
|
||||
switch (error)
|
||||
{
|
||||
default:
|
||||
errorMsg += QString("Unknown instance loader error %1").
|
||||
arg(error);
|
||||
break;
|
||||
}
|
||||
qDebug(errorMsg.toUtf8());
|
||||
}
|
||||
else if (!instPtr)
|
||||
{
|
||||
qDebug(QString("Error loading instance %1. Instance loader returned null.").
|
||||
arg(QFileInfo(subDir).baseName()).toUtf8());
|
||||
}
|
||||
else
|
||||
{
|
||||
QSharedPointer<BaseInstance> inst(instPtr);
|
||||
auto iter = groupMap.find(inst->id());
|
||||
if(iter != groupMap.end())
|
||||
{
|
||||
inst->setGroup((*iter));
|
||||
}
|
||||
qDebug(QString("Loaded instance %1").arg(inst->name()).toUtf8());
|
||||
inst->setParent(this);
|
||||
m_instances.append(inst);
|
||||
connect(instPtr, SIGNAL(propertiesChanged(BaseInstance*)),this, SLOT(propertiesChanged(BaseInstance*)));
|
||||
}
|
||||
}
|
||||
emit invalidated();
|
||||
return NoError;
|
||||
}
|
||||
|
||||
/// Clear all instances. Triggers notifications.
|
||||
void InstanceList::clear()
|
||||
{
|
||||
m_instances.clear();
|
||||
emit invalidated();
|
||||
};
|
||||
|
||||
/// Add an instance. Triggers notifications, returns the new index
|
||||
int InstanceList::add(InstancePtr t)
|
||||
{
|
||||
m_instances.append(t);
|
||||
emit instanceAdded(count() - 1);
|
||||
return count() - 1;
|
||||
}
|
||||
|
||||
InstancePtr InstanceList::getInstanceById(QString instId)
|
||||
{
|
||||
QListIterator<InstancePtr> iter(m_instances);
|
||||
InstancePtr inst;
|
||||
while(iter.hasNext())
|
||||
{
|
||||
inst = iter.next();
|
||||
if (inst->id() == instId)
|
||||
break;
|
||||
}
|
||||
if (inst->id() != instId)
|
||||
return InstancePtr();
|
||||
else
|
||||
return iter.peekPrevious();
|
||||
}
|
||||
|
||||
void InstanceList::propertiesChanged(BaseInstance * inst)
|
||||
{
|
||||
for(int i = 0; i < m_instances.count(); i++)
|
||||
{
|
||||
if(inst == m_instances[i].data())
|
||||
{
|
||||
emit instanceChanged(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
92
backend/lists/InstanceList.h
Normal file
92
backend/lists/InstanceList.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* 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 <QSharedPointer>
|
||||
|
||||
#include "BaseInstance.h"
|
||||
#include "libmmc_config.h"
|
||||
|
||||
class BaseInstance;
|
||||
|
||||
class LIBMULTIMC_EXPORT InstanceList : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
/*!
|
||||
* \brief Get the instance groups
|
||||
*/
|
||||
void loadGroupList(QMap<QString, QString> & groupList);
|
||||
|
||||
public:
|
||||
explicit InstanceList(const QString &instDir, QObject *parent = 0);
|
||||
|
||||
/*!
|
||||
* \brief Error codes returned by functions in the InstanceList class.
|
||||
* NoError Indicates that no error occurred.
|
||||
* UnknownError indicates that an unspecified error occurred.
|
||||
*/
|
||||
enum InstListError
|
||||
{
|
||||
NoError = 0,
|
||||
UnknownError
|
||||
};
|
||||
|
||||
QString instDir() const { return m_instDir; }
|
||||
|
||||
/*!
|
||||
* \brief Loads the instance list. Triggers notifications.
|
||||
*/
|
||||
InstListError loadList();
|
||||
|
||||
/*!
|
||||
* \brief Get the instance at index
|
||||
*/
|
||||
InstancePtr at(int i) const
|
||||
{
|
||||
return m_instances.at(i);
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Get the count of loaded instances
|
||||
*/
|
||||
int count() const
|
||||
{
|
||||
return m_instances.count();
|
||||
};
|
||||
|
||||
/// Clear all instances. Triggers notifications.
|
||||
void clear();
|
||||
|
||||
/// Add an instance. Triggers notifications, returns the new index
|
||||
int add(InstancePtr t);
|
||||
|
||||
/// Get an instance by ID
|
||||
InstancePtr getInstanceById (QString id);
|
||||
|
||||
signals:
|
||||
void instanceAdded(int index);
|
||||
void instanceChanged(int index);
|
||||
void invalidated();
|
||||
|
||||
private slots:
|
||||
void propertiesChanged(BaseInstance * inst);
|
||||
|
||||
protected:
|
||||
QString m_instDir;
|
||||
QList< InstancePtr > m_instances;
|
||||
};
|
204
backend/lists/LwjglVersionList.cpp
Normal file
204
backend/lists/LwjglVersionList.cpp
Normal file
@ -0,0 +1,204 @@
|
||||
/* 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 "LwjglVersionList.h"
|
||||
|
||||
#include <QtNetwork>
|
||||
|
||||
#include <QtXml>
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
#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)
|
||||
{
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
QVariant LWJGLVersionList::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (index.row() > count())
|
||||
return QVariant();
|
||||
|
||||
const PtrLWJGLVersion version = at(index.row());
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
return version->name();
|
||||
|
||||
case Qt::ToolTipRole:
|
||||
return version->url().toString();
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant LWJGLVersionList::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
return "Version";
|
||||
|
||||
case Qt::ToolTipRole:
|
||||
return "LWJGL version name.";
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
int LWJGLVersionList::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool LWJGLVersionList::isLoading() const
|
||||
{
|
||||
return m_loading;
|
||||
}
|
||||
|
||||
void LWJGLVersionList::loadList()
|
||||
{
|
||||
Q_ASSERT_X(!m_loading, "loadList", "list is already loading (m_loading is true)");
|
||||
|
||||
setLoading(true);
|
||||
reply = netMgr.get(QNetworkRequest(QUrl(RSS_URL)));
|
||||
connect(reply, SIGNAL(finished()), SLOT(netRequestComplete()));
|
||||
}
|
||||
|
||||
inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname)
|
||||
{
|
||||
QDomNodeList elementList = parent.elementsByTagName(tagname);
|
||||
if (elementList.count())
|
||||
return elementList.at(0).toElement();
|
||||
else
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
void LWJGLVersionList::netRequestComplete()
|
||||
{
|
||||
if (reply->error() == QNetworkReply::NoError)
|
||||
{
|
||||
QRegExp lwjglRegex("lwjgl-(([0-9]\\.?)+)\\.zip");
|
||||
Q_ASSERT_X(lwjglRegex.isValid(), "load LWJGL list",
|
||||
"LWJGL regex is invalid");
|
||||
|
||||
QDomDocument doc;
|
||||
|
||||
QString xmlErrorMsg;
|
||||
int errorLine;
|
||||
if (!doc.setContent(reply->readAll(), false, &xmlErrorMsg, &errorLine))
|
||||
{
|
||||
failed("Failed to load LWJGL list. XML error: " + xmlErrorMsg +
|
||||
" at line " + QString::number(errorLine));
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QDomNodeList items = doc.elementsByTagName("item");
|
||||
|
||||
QList<PtrLWJGLVersion> tempList;
|
||||
|
||||
for (int i = 0; i < items.length(); i++)
|
||||
{
|
||||
Q_ASSERT_X(items.at(i).isElement(), "load LWJGL list",
|
||||
"XML element isn't an element... wat?");
|
||||
|
||||
QDomElement linkElement = getDomElementByTagName(items.at(i).toElement(), "link");
|
||||
if (linkElement.isNull())
|
||||
{
|
||||
qWarning() << "Link element" << i << "in RSS feed doesn't exist! Skipping.";
|
||||
continue;
|
||||
}
|
||||
|
||||
QString link = linkElement.text();
|
||||
|
||||
// Make sure it's a download link.
|
||||
if (link.endsWith("/download") && link.contains(lwjglRegex))
|
||||
{
|
||||
QString name = link.mid(lwjglRegex.indexIn(link));
|
||||
// Subtract 4 here to remove the .zip file extension.
|
||||
name = name.left(lwjglRegex.matchedLength() - 4);
|
||||
|
||||
QUrl url(link);
|
||||
if (!url.isValid())
|
||||
{
|
||||
qWarning() << "LWJGL version URL isn't valid:" << link << "Skipping.";
|
||||
continue;
|
||||
}
|
||||
|
||||
tempList.append(LWJGLVersion::Create(name, link));
|
||||
}
|
||||
}
|
||||
|
||||
beginResetModel();
|
||||
m_vlist.swap(tempList);
|
||||
endResetModel();
|
||||
|
||||
qDebug("Loaded LWJGL list.");
|
||||
finished();
|
||||
}
|
||||
else
|
||||
{
|
||||
failed("Failed to load LWJGL list. Network error: " + reply->errorString());
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
const PtrLWJGLVersion LWJGLVersionList::getVersion(const QString &versionName)
|
||||
{
|
||||
for (int i = 0; i < count(); i++)
|
||||
{
|
||||
if (at(i)->name() == versionName)
|
||||
return at(i);
|
||||
}
|
||||
return PtrLWJGLVersion();
|
||||
}
|
||||
|
||||
|
||||
void LWJGLVersionList::failed(QString msg)
|
||||
{
|
||||
qWarning() << msg;
|
||||
emit loadListFailed(msg);
|
||||
}
|
||||
|
||||
void LWJGLVersionList::finished()
|
||||
{
|
||||
emit loadListFinished();
|
||||
}
|
||||
|
||||
void LWJGLVersionList::setLoading(bool loading)
|
||||
{
|
||||
m_loading = loading;
|
||||
emit loadingStateUpdated(m_loading);
|
||||
}
|
132
backend/lists/LwjglVersionList.h
Normal file
132
backend/lists/LwjglVersionList.h
Normal file
@ -0,0 +1,132 @@
|
||||
/* 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 <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
class LWJGLVersion;
|
||||
typedef QSharedPointer<LWJGLVersion> PtrLWJGLVersion;
|
||||
|
||||
class LIBMULTIMC_EXPORT LWJGLVersion : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/*!
|
||||
* The name of the LWJGL version.
|
||||
*/
|
||||
Q_PROPERTY(QString name READ name)
|
||||
|
||||
/*!
|
||||
* The URL for this version of LWJGL.
|
||||
*/
|
||||
Q_PROPERTY(QUrl url READ url)
|
||||
|
||||
LWJGLVersion(const QString &name, const QUrl &url, QObject *parent = 0) :
|
||||
QObject(parent), m_name(name), m_url(url) { }
|
||||
public:
|
||||
|
||||
static PtrLWJGLVersion Create(const QString &name, const QUrl &url, QObject *parent = 0)
|
||||
{
|
||||
return PtrLWJGLVersion(new LWJGLVersion(name, url, parent));
|
||||
};
|
||||
|
||||
QString name() const { return m_name; }
|
||||
|
||||
QUrl url() const { return m_url; }
|
||||
|
||||
protected:
|
||||
QString m_name;
|
||||
QUrl m_url;
|
||||
};
|
||||
|
||||
class LIBMULTIMC_EXPORT LWJGLVersionList : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LWJGLVersionList(QObject *parent = 0);
|
||||
|
||||
static LWJGLVersionList &get();
|
||||
|
||||
bool isLoaded() { return m_vlist.length() > 0; }
|
||||
|
||||
const PtrLWJGLVersion getVersion(const QString &versionName);
|
||||
PtrLWJGLVersion at(int index) { return m_vlist[index]; }
|
||||
const PtrLWJGLVersion at(int index) const { return m_vlist[index]; }
|
||||
|
||||
int count() const { return m_vlist.length(); }
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||
virtual int rowCount(const QModelIndex &parent) const { return count(); }
|
||||
virtual int columnCount(const QModelIndex &parent) const;
|
||||
|
||||
virtual bool isLoading() const;
|
||||
virtual bool errored() const { return m_errored; }
|
||||
|
||||
virtual QString lastErrorMsg() const { return m_lastErrorMsg; }
|
||||
|
||||
public slots:
|
||||
/*!
|
||||
* Loads the version list.
|
||||
* This is done asynchronously. On success, the loadListFinished() signal will
|
||||
* be emitted. The list model will be reset as well, resulting in the modelReset()
|
||||
* signal being emitted. Note that the model will be reset before loadListFinished() is emitted.
|
||||
* If loading the list failed, the loadListFailed(QString msg),
|
||||
* signal will be emitted.
|
||||
*/
|
||||
virtual void loadList();
|
||||
|
||||
signals:
|
||||
/*!
|
||||
* Emitted when the list either starts or finishes loading.
|
||||
* \param loading Whether or not the list is loading.
|
||||
*/
|
||||
void loadingStateUpdated(bool loading);
|
||||
|
||||
void loadListFinished();
|
||||
|
||||
void loadListFailed(QString msg);
|
||||
|
||||
private:
|
||||
QList<PtrLWJGLVersion> m_vlist;
|
||||
|
||||
QNetworkReply *m_netReply;
|
||||
|
||||
QNetworkAccessManager netMgr;
|
||||
QNetworkReply *reply;
|
||||
|
||||
bool m_loading;
|
||||
bool m_errored;
|
||||
QString m_lastErrorMsg;
|
||||
|
||||
void failed(QString msg);
|
||||
|
||||
void finished();
|
||||
|
||||
void setLoading(bool loading);
|
||||
|
||||
private slots:
|
||||
virtual void netRequestComplete();
|
||||
};
|
||||
|
528
backend/lists/MinecraftVersionList.cpp
Normal file
528
backend/lists/MinecraftVersionList.cpp
Normal file
@ -0,0 +1,528 @@
|
||||
/* 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 "MinecraftVersionList.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <QtXml>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonParseError>
|
||||
|
||||
#include <QtAlgorithms>
|
||||
|
||||
#include <QtNetwork>
|
||||
|
||||
#include "netutils.h"
|
||||
|
||||
#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() << "----------------------------------------------";
|
||||
}
|
||||
}
|
||||
|
||||
bool cmpVersions(const InstVersion *first, const InstVersion *second)
|
||||
{
|
||||
return !first->isLessThan(*second);
|
||||
}
|
||||
|
||||
void MinecraftVersionList::sort()
|
||||
{
|
||||
beginResetModel();
|
||||
qSort(m_vlist.begin(), m_vlist.end(), cmpVersions);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
InstVersion *MinecraftVersionList::getLatestStable() const
|
||||
{
|
||||
for (int i = 0; i < m_vlist.length(); i++)
|
||||
{
|
||||
if (((MinecraftVersion *)m_vlist.at(i))->versionType() == MinecraftVersion::CurrentStable)
|
||||
{
|
||||
return m_vlist.at(i);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// NOW SORT!!
|
||||
sort();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return QDateTime::fromString(str, Qt::ISODate);
|
||||
}
|
||||
|
||||
|
||||
MCVListLoadTask::MCVListLoadTask(MinecraftVersionList *vlist)
|
||||
{
|
||||
m_list = vlist;
|
||||
m_currentStable = NULL;
|
||||
processedAssetsReply = false;
|
||||
processedMCNReply = false;
|
||||
processedMCVListReply = false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// FIXME: we should have a local cache of the version list and a local cache of version data
|
||||
bool MCVListLoadTask::loadFromVList()
|
||||
{
|
||||
QNetworkReply *vlistReply = netMgr->get(QNetworkRequest(QUrl(QString(MCVLIST_URLBASE) +
|
||||
"versions.json")));
|
||||
NetUtils::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("releaseTime").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);
|
||||
|
||||
Q_ASSERT_X(versionTime.isValid(), "loadFromVList",
|
||||
QString("in versions array, index %1's timestamp failed to parse").
|
||||
arg(i).toUtf8());
|
||||
|
||||
// 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 if(versionTypeStr == "snapshot")
|
||||
{
|
||||
versionType = MinecraftVersion::Snapshot;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we don't know what to do with this...
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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->setVersionSource(MinecraftVersion::Launcher16);
|
||||
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)));
|
||||
NetUtils::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")));
|
||||
NetUtils::waitForNetRequest(mcnReply);
|
||||
processedMCNReply = true;
|
||||
updateStuff();
|
||||
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();
|
||||
}
|
||||
}
|
106
backend/lists/MinecraftVersionList.h
Normal file
106
backend/lists/MinecraftVersionList.h
Normal file
@ -0,0 +1,106 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#include <QList>
|
||||
|
||||
#include "InstVersionList.h"
|
||||
|
||||
#include "tasks/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;
|
||||
virtual void sort();
|
||||
|
||||
virtual InstVersion *getLatestStable() 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;
|
||||
};
|
||||
|
283
backend/tasks/GameUpdateTask.cpp
Normal file
283
backend/tasks/GameUpdateTask.cpp
Normal file
@ -0,0 +1,283 @@
|
||||
/* 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 "GameUpdateTask.h"
|
||||
|
||||
#include <QtNetwork>
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QTextStream>
|
||||
#include <QDataStream>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "lists/MinecraftVersionList.h"
|
||||
#include "VersionFactory.h"
|
||||
#include "OneSixVersion.h"
|
||||
|
||||
#include "pathutils.h"
|
||||
|
||||
|
||||
GameUpdateTask::GameUpdateTask(const LoginResponse &response, BaseInstance *inst, QObject *parent) :
|
||||
Task(parent), m_response(response)
|
||||
{
|
||||
m_inst = inst;
|
||||
m_updateState = StateInit;
|
||||
}
|
||||
|
||||
void GameUpdateTask::executeTask()
|
||||
{
|
||||
updateStatus();
|
||||
|
||||
// Get a pointer to the version object that corresponds to the instance's version.
|
||||
targetVersion = (MinecraftVersion *)MinecraftVersionList::getMainList().
|
||||
findVersion(m_inst->intendedVersion());
|
||||
if(targetVersion == NULL)
|
||||
{
|
||||
//Q_ASSERT_X(targetVersion != NULL, "game update", "instance's intended version is not an actual version");
|
||||
setState(StateFinished);
|
||||
emit gameUpdateComplete(m_response);
|
||||
return;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// BUILD DOWNLOAD LIST //
|
||||
/////////////////////////
|
||||
// Build a list of URLs that will need to be downloaded.
|
||||
|
||||
setState(StateDetermineURLs);
|
||||
|
||||
if (targetVersion->versionSource() == MinecraftVersion::Launcher16)
|
||||
{
|
||||
determineNewVersion();
|
||||
}
|
||||
else
|
||||
{
|
||||
getLegacyJar();
|
||||
}
|
||||
QEventLoop loop;
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
void GameUpdateTask::determineNewVersion()
|
||||
{
|
||||
QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/");
|
||||
urlstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".json";
|
||||
auto dljob = DownloadJob::create(QUrl(urlstr));
|
||||
specificVersionDownloadJob.reset(new JobList());
|
||||
specificVersionDownloadJob->add(dljob);
|
||||
connect(specificVersionDownloadJob.data(), SIGNAL(finished()), SLOT(versionFileFinished()));
|
||||
connect(specificVersionDownloadJob.data(), SIGNAL(failed()), SLOT(versionFileFailed()));
|
||||
connect(specificVersionDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
|
||||
download_queue.enqueue(specificVersionDownloadJob);
|
||||
}
|
||||
|
||||
void GameUpdateTask::versionFileFinished()
|
||||
{
|
||||
JobPtr firstJob = specificVersionDownloadJob->getFirstJob();
|
||||
auto DlJob = firstJob.dynamicCast<DownloadJob>();
|
||||
FullVersionFactory parser;
|
||||
auto version = parser.parse(DlJob->m_data);
|
||||
|
||||
if(!version)
|
||||
{
|
||||
error(parser.error_string);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(version->isLegacy)
|
||||
{
|
||||
getLegacyJar();
|
||||
return;
|
||||
}
|
||||
|
||||
// save the version file in $instanceId/version.json and versions/$version/$version.json
|
||||
QString version_id = targetVersion->descriptor();
|
||||
QString mc_dir = m_inst->minecraftDir();
|
||||
QString inst_dir = m_inst->rootDir();
|
||||
QString version1 = PathCombine(inst_dir, "/version.json");
|
||||
QString version2 = QString("versions/") + version_id + "/" + version_id + ".json";
|
||||
DownloadJob::ensurePathExists(version1);
|
||||
DownloadJob::ensurePathExists(version2);
|
||||
QFile vfile1 (version1);
|
||||
QFile vfile2 (version2);
|
||||
vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly );
|
||||
vfile2.open(QIODevice::Truncate | QIODevice::WriteOnly );
|
||||
vfile1.write(DlJob->m_data);
|
||||
vfile2.write(DlJob->m_data);
|
||||
vfile1.close();
|
||||
vfile2.close();
|
||||
|
||||
// download the right jar, save it in versions/$version/$version.jar
|
||||
QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/");
|
||||
urlstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".jar";
|
||||
QString targetstr ("versions/");
|
||||
targetstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".jar";
|
||||
auto dljob = DownloadJob::create(QUrl(urlstr), targetstr);
|
||||
|
||||
jarlibDownloadJob.reset(new JobList());
|
||||
jarlibDownloadJob->add(dljob);
|
||||
connect(jarlibDownloadJob.data(), SIGNAL(finished()), SLOT(jarlibFinished()));
|
||||
connect(jarlibDownloadJob.data(), SIGNAL(failed()), SLOT(jarlibFailed()));
|
||||
connect(jarlibDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
|
||||
// determine and download all the libraries, save them in libraries/whatever...
|
||||
download_queue.enqueue(jarlibDownloadJob);
|
||||
}
|
||||
|
||||
void GameUpdateTask::jarlibFinished()
|
||||
{
|
||||
m_inst->setCurrentVersion(targetVersion->descriptor());
|
||||
m_inst->setShouldUpdate(false);
|
||||
// m_inst->setIsForNewLauncher(true);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void GameUpdateTask::jarlibFailed()
|
||||
{
|
||||
error("Failed to download the binary garbage. Try again. Maybe. IF YOU DARE");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void GameUpdateTask::versionFileFailed()
|
||||
{
|
||||
error("Failed to download the version description. Try again.");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
// this is legacy minecraft...
|
||||
void GameUpdateTask::getLegacyJar()
|
||||
{
|
||||
// Make directories
|
||||
QDir binDir(m_inst->binDir());
|
||||
if (!binDir.exists() && !binDir.mkpath("."))
|
||||
{
|
||||
error("Failed to create bin folder.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the URL for minecraft.jar
|
||||
// This will be either 'minecraft' or the version number, depending on where
|
||||
// we're downloading from.
|
||||
QString jarFilename = "minecraft";
|
||||
if (targetVersion->versionSource() == MinecraftVersion::Launcher16)
|
||||
{
|
||||
jarFilename = targetVersion->descriptor();
|
||||
}
|
||||
|
||||
QUrl mcJarURL = targetVersion->downloadURL() + jarFilename + ".jar";
|
||||
qDebug() << mcJarURL.toString();
|
||||
auto dljob = DownloadJob::create(mcJarURL, PathCombine(m_inst->minecraftDir(), "bin/minecraft.jar"));
|
||||
|
||||
legacyDownloadJob.reset(new JobList());
|
||||
legacyDownloadJob->add(dljob);
|
||||
connect(legacyDownloadJob.data(), SIGNAL(finished()), SLOT(legacyJarFinished()));
|
||||
connect(legacyDownloadJob.data(), SIGNAL(failed()), SLOT(legacyJarFailed()));
|
||||
connect(legacyDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
|
||||
|
||||
download_queue.enqueue(legacyDownloadJob);
|
||||
}
|
||||
|
||||
|
||||
void GameUpdateTask::legacyJarFinished()
|
||||
{
|
||||
setState(StateFinished);
|
||||
emit gameUpdateComplete(m_response);
|
||||
// m_inst->setIsForNewLauncher(true);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void GameUpdateTask::legacyJarFailed()
|
||||
{
|
||||
emit gameUpdateError("failed to download the minecraft.jar");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int GameUpdateTask::state() const
|
||||
{
|
||||
return m_updateState;
|
||||
}
|
||||
|
||||
void GameUpdateTask::setState(int state, bool resetSubStatus)
|
||||
{
|
||||
m_updateState = state;
|
||||
if (resetSubStatus)
|
||||
setSubStatus("");
|
||||
else // We only need to update if we're not resetting substatus becasue setSubStatus updates status for us.
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
QString GameUpdateTask::subStatus() const
|
||||
{
|
||||
return m_subStatusMsg;
|
||||
}
|
||||
|
||||
void GameUpdateTask::setSubStatus(const QString &msg)
|
||||
{
|
||||
m_subStatusMsg = msg;
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
QString GameUpdateTask::getStateMessage(int state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case StateInit:
|
||||
return "Initializing";
|
||||
|
||||
case StateDetermineURLs:
|
||||
return "Determining files to download";
|
||||
|
||||
case StateDownloadFiles:
|
||||
return "Downloading files";
|
||||
|
||||
case StateInstall:
|
||||
return "Installing";
|
||||
|
||||
case StateFinished:
|
||||
return "Finished";
|
||||
|
||||
default:
|
||||
return "Downloading instance files";
|
||||
}
|
||||
}
|
||||
|
||||
void GameUpdateTask::updateStatus()
|
||||
{
|
||||
QString newStatus;
|
||||
|
||||
newStatus = getStateMessage(state());
|
||||
if (!subStatus().isEmpty())
|
||||
newStatus += ": " + subStatus();
|
||||
else
|
||||
newStatus += "...";
|
||||
|
||||
setStatus(newStatus);
|
||||
}
|
||||
|
||||
|
||||
void GameUpdateTask::error(const QString &msg)
|
||||
{
|
||||
emit gameUpdateError(msg);
|
||||
}
|
||||
|
||||
void GameUpdateTask::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
|
||||
}
|
||||
|
157
backend/tasks/GameUpdateTask.h
Normal file
157
backend/tasks/GameUpdateTask.h
Normal file
@ -0,0 +1,157 @@
|
||||
/* 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 <QList>
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QUrl>
|
||||
#include "dlqueue.h"
|
||||
|
||||
#include "Task.h"
|
||||
#include "tasks/LoginResponse.h"
|
||||
#include "BaseInstance.h"
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
class MinecraftVersion;
|
||||
|
||||
/*!
|
||||
* The game update task is the task that handles downloading instances' files.
|
||||
*/
|
||||
class LIBMULTIMC_EXPORT GameUpdateTask : public Task
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/*!
|
||||
* The task's state.
|
||||
* A certain state message will be shown depending on what this is set to.
|
||||
*/
|
||||
Q_PROPERTY(int state READ state WRITE setState)
|
||||
|
||||
/*!
|
||||
* The substatus message.
|
||||
* This will be next to the the state message in the task's status.
|
||||
*/
|
||||
Q_PROPERTY(QString subStatus READ subStatus WRITE setSubStatus)
|
||||
public:
|
||||
explicit GameUpdateTask(const LoginResponse &response, BaseInstance *inst, QObject *parent = 0);
|
||||
|
||||
|
||||
/////////////////////////
|
||||
// EXECUTION FUNCTIONS //
|
||||
/////////////////////////
|
||||
|
||||
virtual void executeTask();
|
||||
|
||||
//////////////////////
|
||||
// STATE AND STATUS //
|
||||
//////////////////////
|
||||
|
||||
virtual int state() const;
|
||||
virtual void setState(int state, bool resetSubStatus = true);
|
||||
|
||||
virtual QString subStatus() const;
|
||||
virtual void setSubStatus(const QString &msg);
|
||||
|
||||
/*!
|
||||
* Gets the message that will be displated for the given state.
|
||||
*/
|
||||
virtual QString getStateMessage(int state);
|
||||
|
||||
private:
|
||||
void getLegacyJar();
|
||||
void determineNewVersion();
|
||||
|
||||
public slots:
|
||||
|
||||
/*!
|
||||
* Updates the status message based on the state and substatus message.
|
||||
*/
|
||||
virtual void updateStatus();
|
||||
|
||||
|
||||
virtual void error(const QString &msg);
|
||||
|
||||
|
||||
private slots:
|
||||
void updateDownloadProgress(qint64 current, qint64 total);
|
||||
void legacyJarFinished();
|
||||
void legacyJarFailed();
|
||||
|
||||
void versionFileFinished();
|
||||
void versionFileFailed();
|
||||
|
||||
void jarlibFinished();
|
||||
void jarlibFailed();
|
||||
|
||||
signals:
|
||||
/*!
|
||||
* \brief Signal emitted when the game update is complete.
|
||||
* \param response The login response received from login task.
|
||||
*/
|
||||
void gameUpdateComplete(const LoginResponse &response);
|
||||
|
||||
/*!
|
||||
* \brief Signal emitted if an error occurrs during the update.
|
||||
* \param errorMsg An error message to be displayed to the user.
|
||||
*/
|
||||
void gameUpdateError(const QString &errorMsg);
|
||||
|
||||
private:
|
||||
///////////
|
||||
// STUFF //
|
||||
///////////
|
||||
|
||||
BaseInstance *m_inst;
|
||||
LoginResponse m_response;
|
||||
|
||||
////////////////////////////
|
||||
// STATE AND STATUS STUFF //
|
||||
////////////////////////////
|
||||
|
||||
int m_updateState;
|
||||
QString m_subStatusMsg;
|
||||
|
||||
enum UpdateState
|
||||
{
|
||||
// Initializing
|
||||
StateInit = 0,
|
||||
|
||||
// Determining files to download
|
||||
StateDetermineURLs,
|
||||
|
||||
// Downloading files
|
||||
StateDownloadFiles,
|
||||
|
||||
// Installing files
|
||||
StateInstall,
|
||||
|
||||
// Finished
|
||||
StateFinished
|
||||
};
|
||||
JobListPtr legacyDownloadJob;
|
||||
JobListPtr specificVersionDownloadJob;
|
||||
JobListPtr jarlibDownloadJob;
|
||||
JobListQueue download_queue;
|
||||
|
||||
// target version, determined during this task
|
||||
MinecraftVersion *targetVersion;
|
||||
};
|
||||
|
||||
|
69
backend/tasks/LoginResponse.cpp
Normal file
69
backend/tasks/LoginResponse.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
/* 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 "tasks/LoginResponse.h"
|
||||
|
||||
LoginResponse::LoginResponse(const QString& username, const QString& sessionID,
|
||||
qint64 latestVersion, QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
this->m_username = username;
|
||||
this->m_sessionID = sessionID;
|
||||
this->m_latestVersion = latestVersion;
|
||||
}
|
||||
|
||||
LoginResponse::LoginResponse()
|
||||
{
|
||||
this->m_username = "";
|
||||
this->m_sessionID = "";
|
||||
this->m_latestVersion = 0;
|
||||
}
|
||||
|
||||
LoginResponse::LoginResponse(const LoginResponse &other)
|
||||
{
|
||||
this->m_username = other.username();
|
||||
this->m_sessionID = other.sessionID();
|
||||
this->m_latestVersion = other.latestVersion();
|
||||
}
|
||||
|
||||
QString LoginResponse::username() const
|
||||
{
|
||||
return m_username;
|
||||
}
|
||||
|
||||
void LoginResponse::setUsername(const QString& username)
|
||||
{
|
||||
this->m_username = username;
|
||||
}
|
||||
|
||||
QString LoginResponse::sessionID() const
|
||||
{
|
||||
return m_sessionID;
|
||||
}
|
||||
|
||||
void LoginResponse::setSessionID(const QString& sessionID)
|
||||
{
|
||||
this->m_sessionID = sessionID;
|
||||
}
|
||||
|
||||
qint64 LoginResponse::latestVersion() const
|
||||
{
|
||||
return m_latestVersion;
|
||||
}
|
||||
|
||||
void LoginResponse::setLatestVersion(qint64 v)
|
||||
{
|
||||
this->m_latestVersion = v;
|
||||
}
|
94
backend/tasks/LoginResponse.h
Normal file
94
backend/tasks/LoginResponse.h
Normal file
@ -0,0 +1,94 @@
|
||||
/* 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 "libmmc_config.h"
|
||||
|
||||
/*!
|
||||
* \brief The LoginResponse class represents a response received from Minecraft's login servers.
|
||||
*/
|
||||
class LIBMULTIMC_EXPORT LoginResponse : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/*!
|
||||
* \brief Creates a new instance of the LoginResponse class.
|
||||
* \param username The user's username.
|
||||
* \param sessionID The user's session ID.
|
||||
* \param latestVersion The latest version of Minecraft.
|
||||
* \param parent The parent object.
|
||||
*/
|
||||
explicit LoginResponse(const QString &username, const QString &sessionID,
|
||||
qint64 latestVersion, QObject *parent = 0);
|
||||
LoginResponse();
|
||||
LoginResponse(const LoginResponse& other);
|
||||
|
||||
/*!
|
||||
* \brief Gets the username.
|
||||
* This one should go without saying.
|
||||
* \return The username.
|
||||
* \sa setUsername()
|
||||
*/
|
||||
QString username() const;
|
||||
|
||||
/*!
|
||||
* \brief setUsername Sets the username.
|
||||
* \param username The new username.
|
||||
* \sa username()
|
||||
*/
|
||||
void setUsername(const QString& username);
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Gets the session ID.
|
||||
* \return The session ID.
|
||||
* \sa setSessionID()
|
||||
*/
|
||||
QString sessionID() const;
|
||||
|
||||
/*!
|
||||
* \brief Sets the session ID.
|
||||
* \param sessionID The new session ID.
|
||||
* \sa sessionID()
|
||||
*/
|
||||
void setSessionID(const QString& sessionID);
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Gets the latest version.
|
||||
* This is a value returned by the login servers when a user logs in.
|
||||
* \return The latest version.
|
||||
* \sa setLatestVersion()
|
||||
*/
|
||||
qint64 latestVersion() const;
|
||||
|
||||
/*!
|
||||
* \brief Sets the latest version.
|
||||
* \param v The new latest version.
|
||||
* \sa latestVersion()
|
||||
*/
|
||||
void setLatestVersion(qint64 v);
|
||||
|
||||
private:
|
||||
QString m_username;
|
||||
QString m_sessionID;
|
||||
qint64 m_latestVersion;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(LoginResponse)
|
||||
|
121
backend/tasks/LoginTask.cpp
Normal file
121
backend/tasks/LoginTask.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/* 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 "LoginTask.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
|
||||
LoginTask::LoginTask( const UserInfo& uInfo, QObject* parent ) :
|
||||
Task(parent), uInfo(uInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LoginTask::executeTask()
|
||||
{
|
||||
setStatus("Logging in...");
|
||||
|
||||
QNetworkAccessManager netMgr;
|
||||
connect(&netMgr, SIGNAL(finished(QNetworkReply*)),
|
||||
SLOT(processNetReply(QNetworkReply*)));
|
||||
|
||||
QUrl loginURL("https://login.minecraft.net/");
|
||||
QNetworkRequest netRequest(loginURL);
|
||||
netRequest.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||
"application/x-www-form-urlencoded");
|
||||
|
||||
QUrlQuery params;
|
||||
params.addQueryItem("user", uInfo.username());
|
||||
params.addQueryItem("password", uInfo.password());
|
||||
params.addQueryItem("version", "13");
|
||||
|
||||
netReply = netMgr.post(netRequest, params.query(QUrl::EncodeSpaces).toUtf8());
|
||||
exec();
|
||||
}
|
||||
|
||||
void LoginTask::processNetReply(QNetworkReply *reply)
|
||||
{
|
||||
// Check for errors.
|
||||
switch (reply->error())
|
||||
{
|
||||
case QNetworkReply::NoError:
|
||||
{
|
||||
// Check the response code.
|
||||
int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
||||
if (responseCode == 200)
|
||||
{
|
||||
QString responseStr(reply->readAll());
|
||||
|
||||
QStringList strings = responseStr.split(":");
|
||||
if (strings.count() >= 4)
|
||||
{
|
||||
bool parseSuccess;
|
||||
qint64 latestVersion = strings[0].toLongLong(&parseSuccess);
|
||||
if (parseSuccess)
|
||||
{
|
||||
// strings[1] is the download ticket. It isn't used anymore.
|
||||
QString username = strings[2];
|
||||
QString sessionID = strings[3];
|
||||
|
||||
LoginResponse response(username, sessionID, latestVersion);
|
||||
emit loginComplete(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit loginFailed("Failed to parse Minecraft version string.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (responseStr.toLower() == "bad login")
|
||||
emit loginFailed("Invalid username or password.");
|
||||
else if (responseStr.toLower() == "old version")
|
||||
emit loginFailed("Launcher outdated, please update.");
|
||||
else
|
||||
emit loginFailed("Login failed: " + responseStr);
|
||||
}
|
||||
}
|
||||
else if (responseCode == 503)
|
||||
{
|
||||
emit loginFailed("The login servers are currently unavailable. "
|
||||
"Check http://help.mojang.com/ for more info.");
|
||||
}
|
||||
else
|
||||
{
|
||||
emit loginFailed(QString("Login failed: Unknown HTTP error %1 occurred.").
|
||||
arg(QString::number(responseCode)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case QNetworkReply::OperationCanceledError:
|
||||
emit loginFailed("Login canceled.");
|
||||
break;
|
||||
|
||||
default:
|
||||
emit loginFailed("Login failed: " + reply->errorString());
|
||||
break;
|
||||
}
|
||||
|
||||
quit();
|
||||
}
|
49
backend/tasks/LoginTask.h
Normal file
49
backend/tasks/LoginTask.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef LOGINTASK_H
|
||||
#define LOGINTASK_H
|
||||
|
||||
#include "Task.h"
|
||||
|
||||
#include "UserInfo.h"
|
||||
#include "tasks/LoginResponse.h"
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
//class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
|
||||
class LIBMULTIMC_EXPORT LoginTask : public Task
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LoginTask(const UserInfo& uInfo, QObject *parent = 0);
|
||||
|
||||
public slots:
|
||||
void processNetReply(QNetworkReply* reply);
|
||||
|
||||
signals:
|
||||
void loginComplete(LoginResponse loginResponse);
|
||||
void loginFailed(const QString& errorMsg);
|
||||
|
||||
protected:
|
||||
void executeTask();
|
||||
|
||||
QNetworkReply* netReply;
|
||||
UserInfo uInfo;
|
||||
};
|
||||
|
||||
#endif // LOGINTASK_H
|
83
backend/tasks/Task.cpp
Normal file
83
backend/tasks/Task.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/* 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 "Task.h"
|
||||
|
||||
Task::Task(QObject *parent) :
|
||||
QThread(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString Task::getStatus() const
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
void Task::setStatus(const QString &status)
|
||||
{
|
||||
this->status = status;
|
||||
emitStatusChange(status);
|
||||
}
|
||||
|
||||
int Task::getProgress() const
|
||||
{
|
||||
return progress;
|
||||
}
|
||||
|
||||
void Task::calcProgress(int parts, int whole)
|
||||
{
|
||||
setProgress((int)((((float)parts) / ((float)whole))*100)); // Not sure if C++ or LISP...
|
||||
}
|
||||
|
||||
void Task::setProgress(int progress)
|
||||
{
|
||||
this->progress = progress;
|
||||
emitProgressChange(progress);
|
||||
}
|
||||
|
||||
void Task::startTask()
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
void Task::run()
|
||||
{
|
||||
emitStarted();
|
||||
executeTask();
|
||||
emitEnded();
|
||||
}
|
||||
|
||||
void Task::emitStarted()
|
||||
{
|
||||
emit started();
|
||||
emit started(this);
|
||||
}
|
||||
|
||||
void Task::emitEnded()
|
||||
{
|
||||
emit ended();
|
||||
emit ended(this);
|
||||
}
|
||||
|
||||
void Task::emitStatusChange(const QString &status)
|
||||
{
|
||||
emit statusChanged(status);
|
||||
}
|
||||
|
||||
void Task::emitProgressChange(int progress)
|
||||
{
|
||||
emit progressChanged(progress);
|
||||
}
|
78
backend/tasks/Task.h
Normal file
78
backend/tasks/Task.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef TASK_H
|
||||
#define TASK_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QString>
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
class LIBMULTIMC_EXPORT Task : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Task(QObject *parent = 0);
|
||||
|
||||
// Starts the task.
|
||||
void startTask();
|
||||
|
||||
QString getStatus() const;
|
||||
int getProgress() const;
|
||||
|
||||
/*!
|
||||
* \brief Calculates and sets the task's progress based on the number of parts completed out of the total number to complete.
|
||||
* This is essentially just shorthand for setProgress((parts / whole) * 100);
|
||||
* \param parts The parts out of the whole completed. This parameter should
|
||||
* be less than whole. If it is greater than whole, progress is set to 100.
|
||||
* \param whole The total number of things that need to be completed.
|
||||
*/
|
||||
void calcProgress(int parts, int whole);
|
||||
|
||||
public slots:
|
||||
void setStatus(const QString& status);
|
||||
void setProgress(int progress);
|
||||
|
||||
signals:
|
||||
void started(Task* task);
|
||||
void ended(Task* task);
|
||||
|
||||
void started();
|
||||
void ended();
|
||||
|
||||
|
||||
void statusChanged(Task* task, const QString& status);
|
||||
void progressChanged(Task* task, int progress);
|
||||
|
||||
void statusChanged(const QString& status);
|
||||
void progressChanged(int progress);
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
virtual void executeTask() = 0;
|
||||
|
||||
virtual void emitStarted();
|
||||
virtual void emitEnded();
|
||||
|
||||
virtual void emitStatusChange(const QString &status);
|
||||
virtual void emitProgressChange(int progress);
|
||||
|
||||
QString status;
|
||||
int progress;
|
||||
};
|
||||
|
||||
#endif // TASK_H
|
49
backend/tasks/UserInfo.cpp
Normal file
49
backend/tasks/UserInfo.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
/* 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 "UserInfo.h"
|
||||
|
||||
UserInfo::UserInfo(const QString &username, const QString &password, QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
this->m_username = username;
|
||||
this->m_password = password;
|
||||
}
|
||||
|
||||
UserInfo::UserInfo(const UserInfo &other)
|
||||
{
|
||||
this->m_username = other.m_username;
|
||||
this->m_password = other.m_password;
|
||||
}
|
||||
|
||||
QString UserInfo::username() const
|
||||
{
|
||||
return m_username;
|
||||
}
|
||||
|
||||
void UserInfo::setUsername(const QString &username)
|
||||
{
|
||||
this->m_username = username;
|
||||
}
|
||||
|
||||
QString UserInfo::password() const
|
||||
{
|
||||
return m_password;
|
||||
}
|
||||
|
||||
void UserInfo::setPassword(const QString &password)
|
||||
{
|
||||
this->m_password = password;
|
||||
}
|
41
backend/tasks/UserInfo.h
Normal file
41
backend/tasks/UserInfo.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef USERINFO_H
|
||||
#define USERINFO_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
class LIBMULTIMC_EXPORT UserInfo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit UserInfo(const QString& username, const QString& password, QObject *parent = 0);
|
||||
explicit UserInfo(const UserInfo& other);
|
||||
|
||||
QString username() const;
|
||||
void setUsername(const QString& username);
|
||||
|
||||
QString password() const;
|
||||
void setPassword(const QString& password);
|
||||
|
||||
protected:
|
||||
QString m_username;
|
||||
QString m_password;
|
||||
};
|
||||
|
||||
#endif // USERINFO_H
|
Reference in New Issue
Block a user