From 2e0cbf393a5320dbf5448ca44a9b5905314b0be8 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Mon, 29 Jul 2013 00:59:35 +0200 Subject: Massive renaming in the backend folder, all around restructure in the same. --- backend/BaseInstance.cpp | 199 +++++++++++++ backend/BaseInstance.h | 313 +++++++++++++++++++ backend/CMakeLists.txt | 91 ++++++ backend/InstanceFactory.cpp | 61 ++++ backend/InstanceFactory.h | 79 +++++ backend/InstanceVersion.cpp | 67 +++++ backend/InstanceVersion.h | 121 ++++++++ backend/LegacyInstance.cpp | 0 backend/LegacyInstance.h | 1 + backend/MinecraftProcess.cpp | 229 ++++++++++++++ backend/MinecraftProcess.h | 111 +++++++ backend/MinecraftVersion.cpp | 104 +++++++ backend/MinecraftVersion.h | 80 +++++ backend/OneSixInstance.cpp | 0 backend/OneSixInstance.h | 1 + backend/OneSixVersion.cpp | 91 ++++++ backend/OneSixVersion.h | 265 +++++++++++++++++ backend/VersionFactory.cpp | 194 ++++++++++++ backend/VersionFactory.h | 25 ++ backend/libmmc_config.h | 24 ++ backend/lists/InstVersionList.cpp | 129 ++++++++ backend/lists/InstVersionList.h | 121 ++++++++ backend/lists/InstanceList.cpp | 232 +++++++++++++++ backend/lists/InstanceList.h | 92 ++++++ backend/lists/LwjglVersionList.cpp | 204 +++++++++++++ backend/lists/LwjglVersionList.h | 132 +++++++++ backend/lists/MinecraftVersionList.cpp | 528 +++++++++++++++++++++++++++++++++ backend/lists/MinecraftVersionList.h | 106 +++++++ backend/tasks/GameUpdateTask.cpp | 283 ++++++++++++++++++ backend/tasks/GameUpdateTask.h | 157 ++++++++++ backend/tasks/LoginResponse.cpp | 69 +++++ backend/tasks/LoginResponse.h | 94 ++++++ backend/tasks/LoginTask.cpp | 121 ++++++++ backend/tasks/LoginTask.h | 49 +++ backend/tasks/Task.cpp | 83 ++++++ backend/tasks/Task.h | 78 +++++ backend/tasks/UserInfo.cpp | 49 +++ backend/tasks/UserInfo.h | 41 +++ 38 files changed, 4624 insertions(+) create mode 100644 backend/BaseInstance.cpp create mode 100644 backend/BaseInstance.h create mode 100644 backend/CMakeLists.txt create mode 100644 backend/InstanceFactory.cpp create mode 100644 backend/InstanceFactory.h create mode 100644 backend/InstanceVersion.cpp create mode 100644 backend/InstanceVersion.h create mode 100644 backend/LegacyInstance.cpp create mode 100644 backend/LegacyInstance.h create mode 100644 backend/MinecraftProcess.cpp create mode 100644 backend/MinecraftProcess.h create mode 100644 backend/MinecraftVersion.cpp create mode 100644 backend/MinecraftVersion.h create mode 100644 backend/OneSixInstance.cpp create mode 100644 backend/OneSixInstance.h create mode 100644 backend/OneSixVersion.cpp create mode 100644 backend/OneSixVersion.h create mode 100644 backend/VersionFactory.cpp create mode 100644 backend/VersionFactory.h create mode 100644 backend/libmmc_config.h create mode 100644 backend/lists/InstVersionList.cpp create mode 100644 backend/lists/InstVersionList.h create mode 100644 backend/lists/InstanceList.cpp create mode 100644 backend/lists/InstanceList.h create mode 100644 backend/lists/LwjglVersionList.cpp create mode 100644 backend/lists/LwjglVersionList.h create mode 100644 backend/lists/MinecraftVersionList.cpp create mode 100644 backend/lists/MinecraftVersionList.h create mode 100644 backend/tasks/GameUpdateTask.cpp create mode 100644 backend/tasks/GameUpdateTask.h create mode 100644 backend/tasks/LoginResponse.cpp create mode 100644 backend/tasks/LoginResponse.h create mode 100644 backend/tasks/LoginTask.cpp create mode 100644 backend/tasks/LoginTask.h create mode 100644 backend/tasks/Task.cpp create mode 100644 backend/tasks/Task.h create mode 100644 backend/tasks/UserInfo.cpp create mode 100644 backend/tasks/UserInfo.h (limited to 'backend') diff --git a/backend/BaseInstance.cpp b/backend/BaseInstance.cpp new file mode 100644 index 00000000..c2ffa664 --- /dev/null +++ b/backend/BaseInstance.cpp @@ -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 + +#include "inisettingsobject.h" +#include "setting.h" +#include "overridesetting.h" + +#include "pathutils.h" +#include + +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; +} diff --git a/backend/BaseInstance.h b/backend/BaseInstance.h new file mode 100644 index 00000000..51f55b5e --- /dev/null +++ b/backend/BaseInstance.h @@ -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 +#include + +#include + +#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(); } + virtual void setLastLaunch(qint64 val = QDateTime::currentMSecsSinceEpoch()) + { + settings().set("lastLaunchTime", val); + emit propertiesChanged(this); + } + + virtual qint64 lastCurrentVersionUpdate() const { return settings().get("lastVersionUpdate").value(); } + 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 InstancePtr; + diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt new file mode 100644 index 00000000..a17b7dfe --- /dev/null +++ b/backend/CMakeLists.txt @@ -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) diff --git a/backend/InstanceFactory.cpp b/backend/InstanceFactory.cpp new file mode 100644 index 00000000..318650ae --- /dev/null +++ b/backend/InstanceFactory.cpp @@ -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 +#include + +#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; +} diff --git a/backend/InstanceFactory.h b/backend/InstanceFactory.h new file mode 100644 index 00000000..0dd4c5d8 --- /dev/null +++ b/backend/InstanceFactory.h @@ -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 +#include +#include + +#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; +}; diff --git a/backend/InstanceVersion.cpp b/backend/InstanceVersion.cpp new file mode 100644 index 00000000..1b9b0a5b --- /dev/null +++ b/backend/InstanceVersion.cpp @@ -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; +} diff --git a/backend/InstanceVersion.h b/backend/InstanceVersion.h new file mode 100644 index 00000000..5ebae41e --- /dev/null +++ b/backend/InstanceVersion.h @@ -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 + +#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; +}; diff --git a/backend/LegacyInstance.cpp b/backend/LegacyInstance.cpp new file mode 100644 index 00000000..e69de29b diff --git a/backend/LegacyInstance.h b/backend/LegacyInstance.h new file mode 100644 index 00000000..7b9637ef --- /dev/null +++ b/backend/LegacyInstance.h @@ -0,0 +1 @@ +#pragma once \ No newline at end of file diff --git a/backend/MinecraftProcess.cpp b/backend/MinecraftProcess.cpp new file mode 100644 index 00000000..e53feb5b --- /dev/null +++ b/backend/MinecraftProcess.cpp @@ -0,0 +1,229 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan + * + * 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 +#include +#include +//#include +#include + +#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; +} diff --git a/backend/MinecraftProcess.h b/backend/MinecraftProcess.h new file mode 100644 index 00000000..c846f5f4 --- /dev/null +++ b/backend/MinecraftProcess.h @@ -0,0 +1,111 @@ +/* Copyright 2013 MultiMC Contributors + * + * Authors: Orochimarufan + * + * 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 + +#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(); + +}; diff --git a/backend/MinecraftVersion.cpp b/backend/MinecraftVersion.cpp new file mode 100644 index 00000000..6f3b1b86 --- /dev/null +++ b/backend/MinecraftVersion.cpp @@ -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; +} diff --git a/backend/MinecraftVersion.h b/backend/MinecraftVersion.h new file mode 100644 index 00000000..a69b4710 --- /dev/null +++ b/backend/MinecraftVersion.h @@ -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; +}; diff --git a/backend/OneSixInstance.cpp b/backend/OneSixInstance.cpp new file mode 100644 index 00000000..e69de29b diff --git a/backend/OneSixInstance.h b/backend/OneSixInstance.h new file mode 100644 index 00000000..7b9637ef --- /dev/null +++ b/backend/OneSixInstance.h @@ -0,0 +1 @@ +#pragma once \ No newline at end of file diff --git a/backend/OneSixVersion.cpp b/backend/OneSixVersion.cpp new file mode 100644 index 00000000..b58870ce --- /dev/null +++ b/backend/OneSixVersion.cpp @@ -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 > FullVersion::getActiveNormalLibs() +{ + QList > output; + for ( auto lib: libraries ) + { + if (lib->getIsActive() && !lib->getIsNative()) + { + output.append(lib); + } + } + return output; +} + +QList > FullVersion::getActiveNativeLibs() +{ + QList > output; + for ( auto lib: libraries ) + { + if (lib->getIsActive() && lib->getIsNative()) + { + output.append(lib); + } + } + return output; +} diff --git a/backend/OneSixVersion.h b/backend/OneSixVersion.h new file mode 100644 index 00000000..762e8f3e --- /dev/null +++ b/backend/OneSixVersion.h @@ -0,0 +1,265 @@ +#pragma once +#include + +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 create(RuleAction result, OpSys system, QString version_regexp) + { + return QSharedPointer (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 create(RuleAction result) + { + return QSharedPointer (new ImplicitRule(result)); + } +}; + +class Library +{ +private: + // basic values used internally (so far) + QString m_name; + QString m_base_url; + QList > 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 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 > 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 > 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 rules; + +public: + FullVersion() + { + minimumLauncherVersion = 0xDEADBEEF; + isLegacy = false; + } + + QList > getActiveNormalLibs(); + QList > getActiveNativeLibs(); +}; \ No newline at end of file diff --git a/backend/VersionFactory.cpp b/backend/VersionFactory.cpp new file mode 100644 index 00000000..d0242f17 --- /dev/null +++ b/backend/VersionFactory.cpp @@ -0,0 +1,194 @@ +#include "VersionFactory.h" +#include "OneSixVersion.h" + +// Library rules (if any) +QList > FullVersionFactory::parse4rules(QJsonObject & baseObj) +{ + QList > rules; + auto rulesVal = baseObj.value("rules"); + if(rulesVal.isArray()) + { + QJsonArray ruleList = rulesVal.toArray(); + for(auto ruleVal : ruleList) + { + QSharedPointer 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 FullVersionFactory::parse4(QJsonObject root, QSharedPointer 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(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 FullVersionFactory::parse(QByteArray data) +{ + QSharedPointer 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(); + } + + if(!jsonDoc.isObject()) + { + error_string = "Error reading version file."; + m_error = FullVersionFactory::ParseError; + return QSharedPointer(); + } + 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(); + } +} + + +FullVersionFactory::FullVersionFactory() +{ + m_error = FullVersionFactory::AllOK; + legacyWhitelist.append("1.5.1"); + legacyWhitelist.append("1.5.2"); +} diff --git a/backend/VersionFactory.h b/backend/VersionFactory.h new file mode 100644 index 00000000..60e5c983 --- /dev/null +++ b/backend/VersionFactory.h @@ -0,0 +1,25 @@ +#pragma once +#include + +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 parse(QByteArray data); +private: + QSharedPointer parse4(QJsonObject root, QSharedPointer product); + QList > parse4rules(QJsonObject & baseObj); + QStringList legacyWhitelist; +}; \ No newline at end of file diff --git a/backend/libmmc_config.h b/backend/libmmc_config.h new file mode 100644 index 00000000..6d967f5f --- /dev/null +++ b/backend/libmmc_config.h @@ -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 + +#ifdef LIBMULTIMC_LIBRARY +# define LIBMULTIMC_EXPORT Q_DECL_EXPORT +#else +# define LIBMULTIMC_EXPORT Q_DECL_IMPORT +#endif diff --git a/backend/lists/InstVersionList.cpp b/backend/lists/InstVersionList.cpp new file mode 100644 index 00000000..c65770a9 --- /dev/null +++ b/backend/lists/InstVersionList.cpp @@ -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