diff options
| -rw-r--r-- | CMakeLists.txt | 20 | ||||
| -rw-r--r-- | data/minecraftprocess.cpp | 246 | ||||
| -rw-r--r-- | data/minecraftprocess.h | 98 | ||||
| -rw-r--r-- | gui/aboutdialog.cpp | 23 | ||||
| -rw-r--r-- | gui/aboutdialog.h | 22 | ||||
| -rw-r--r-- | gui/aboutdialog.ui | 288 | ||||
| -rw-r--r-- | gui/browserdialog.cpp | 76 | ||||
| -rw-r--r-- | gui/browserdialog.h | 41 | ||||
| -rw-r--r-- | gui/browserdialog.ui | 92 | ||||
| -rw-r--r-- | gui/consolewindow.cpp | 73 | ||||
| -rw-r--r-- | gui/consolewindow.h | 69 | ||||
| -rw-r--r-- | gui/consolewindow.ui | 66 | ||||
| -rw-r--r-- | gui/mainwindow.cpp | 41 | ||||
| -rw-r--r-- | gui/mainwindow.h | 5 | ||||
| -rw-r--r-- | libinstance/include/instance.h | 3 | ||||
| -rw-r--r-- | libinstance/src/instance.cpp | 10 | ||||
| -rw-r--r-- | libutil/CMakeLists.txt | 19 | ||||
| -rw-r--r-- | libutil/include/cmdutils.h | 239 | ||||
| -rw-r--r-- | libutil/include/siglist.h | 2 | ||||
| -rw-r--r-- | libutil/include/userutils.h | 17 | ||||
| -rw-r--r-- | libutil/src/cmdutils.cpp | 434 | ||||
| -rw-r--r-- | libutil/src/userutils.cpp | 113 | ||||
| -rw-r--r-- | main.cpp | 203 | ||||
| -rw-r--r-- | multimc.qrc | 6 | ||||
| -rw-r--r-- | resources/XdgIcon.theme | 12 |
25 files changed, 2196 insertions, 22 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 754c073e..0022b29e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,7 @@ IF(DEFINED MultiMC_BUILD_TAG) MESSAGE(STATUS "Build tag: ${MultiMC_BUILD_TAG}") ELSE() MESSAGE(STATUS "No build tag specified.") + SET(MultiMC_BUILD_TAG custom) ENDIF() # Architecture detection @@ -162,11 +163,15 @@ gui/settingsdialog.h gui/newinstancedialog.h gui/logindialog.h gui/taskdialog.h +gui/browserdialog.h +gui/aboutdialog.h +gui/consolewindow.h data/version.h data/userinfo.h data/loginresponse.h data/appsettings.h +data/minecraftprocess.h data/plugin/pluginmanager.h @@ -196,6 +201,7 @@ data/loginresponse.cpp data/appsettings.cpp data/plugin/pluginmanager.cpp +data/minecraftprocess.cpp gui/mainwindow.cpp gui/modeditwindow.cpp @@ -203,6 +209,9 @@ gui/settingsdialog.cpp gui/newinstancedialog.cpp gui/logindialog.cpp gui/taskdialog.cpp +gui/browserdialog.cpp +gui/aboutdialog.cpp +gui/consolewindow.cpp java/javautils.cpp java/annotations.cpp @@ -221,6 +230,9 @@ gui/settingsdialog.ui gui/newinstancedialog.ui gui/logindialog.ui gui/taskdialog.ui +gui/browserdialog.ui +gui/aboutdialog.ui +gui/consolewindow.ui ) @@ -258,7 +270,7 @@ ADD_EXECUTABLE(MultiMC MACOSX_BUNDLE WIN32 ${MULTIMC_SOURCES} ${MULTIMC_HEADERS} ${MULTIMC_UI} ${MULTIMC_QRC} ${MULTIMC_RCS}) # Link -QT5_USE_MODULES(MultiMC Widgets Network) +QT5_USE_MODULES(MultiMC Widgets Network WebKitWidgets) TARGET_LINK_LIBRARIES(MultiMC quazip patchlib libmmcutil libmmcsettings libmmcinst ${MultiMC_LINK_ADDITIONAL_LIBS}) @@ -266,6 +278,10 @@ ADD_DEPENDENCIES(MultiMC MultiMCLauncher libmmcutil libmmcsettings libmmcinst) ################################ INSTALLATION AND PACKAGING ################################ +# use QtCreator's QTDIR var +IF(DEFINED ENV{QTDIR}) + SET(Qt5_DIR $ENV{QTDIR}) +ENDIF() ######## Plugin and library folders ######## @@ -282,7 +298,7 @@ ENDIF() IF(APPLE) SET(PLUGIN_DEST_DIR MultiMC.app/Contents/MacOS) SET(QTCONF_DEST_DIR MultiMC.app/Contents/Resources) - SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.app") + SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.app") ENDIF() SET(QT_PLUGINS_DIR ${Qt5_DIR}/plugins) diff --git a/data/minecraftprocess.cpp b/data/minecraftprocess.cpp new file mode 100644 index 00000000..d08b767c --- /dev/null +++ b/data/minecraftprocess.cpp @@ -0,0 +1,246 @@ +/* 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 "instance.h" + +#include "osutils.h" +#include "pathutils.h" + +#define LAUNCHER_FILE "MultiMCLauncher.jar" +#define IBUS "@im=ibus" + +// commandline splitter +QStringList MinecraftProcess::splitArgs(QString args) +{ + QStringList argv; + QString current; + bool escape = false; + QChar inquotes; + for (int i=0; i<args.length(); i++) + { + QChar cchar = args.at(i); + + // \ escaped + if (escape) { + current += cchar; + escape = false; + // in "quotes" + } else if (!inquotes.isNull()) { + if (cchar == 0x5C) + escape = true; + else if (cchar == inquotes) + inquotes = 0; + else + current += cchar; + // otherwise + } else { + if (cchar == 0x20) { + if (!current.isEmpty()) { + argv << current; + current.clear(); + } + } else if (cchar == 0x22 || cchar == 0x27) + inquotes = cchar; + else + current += cchar; + } + } + if (!current.isEmpty()) + argv << current; + return argv; +} + +// prepare tools +inline void MinecraftProcess::extractIcon(InstancePtr 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(InstancePtr inst) +{ + extractLauncher(PathCombine(inst->minecraftDir(), LAUNCHER_FILE)); + extractIcon(inst, PathCombine(inst->minecraftDir(), "icon.png")); +} + +// constructor +MinecraftProcess::MinecraftProcess(InstancePtr inst, QString user, QString session, ConsoleWindow *console) : + m_instance(inst), m_user(user), m_session(session), m_console(console) +{ + 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() +{ + if (m_console != nullptr) + m_console->write(readAllStandardError(), ConsoleWindow::ERROR); +} + +void MinecraftProcess::on_stdOut() +{ + if (m_console != nullptr) + m_console->write(readAllStandardOutput(), ConsoleWindow::DEFAULT); +} + +void MinecraftProcess::log(QString text) +{ + if (m_console != nullptr) + m_console->write(text); + else + qDebug(qPrintable(text)); +} + +// exit handler +void MinecraftProcess::finish(int code, ExitStatus status) +{ + if (status != NormalExit) + { + //TODO: error handling + } + + log("Minecraft exited."); + + m_prepostlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(code)); + + // run post-exit + if (!m_instance->getPostExitCommand().isEmpty()) + { + m_prepostlaunchprocess.start(m_instance->getPostExitCommand()); + 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->getPreLaunchCommand().isEmpty()) + { + m_prepostlaunchprocess.start(m_instance->getPreLaunchCommand()); + m_prepostlaunchprocess.waitForFinished(); + if (m_prepostlaunchprocess.exitStatus() != NormalExit) + { + //TODO: error handling + return; + } + } + + m_instance->setLastLaunch(); + + prepare(m_instance); + + genArgs(); + + log(QString("Minecraft folder is: '%1'").arg(workingDirectory())); + log(QString("Instance launched with arguments: '%1'").arg(m_arguments.join("' '"))); + + start(m_instance->getJavaPath(), m_arguments); + if (!waitForStarted()) + { + //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->getLaunchMaximized()) + windowSize = "max"; + else + windowSize = QString("%1x%2").arg(m_instance->getMinecraftWinWidth()).arg(m_instance->getMinecraftWinHeight()); + + // window title + QString windowTitle; + windowTitle.append("MultiMC: ").append(m_instance->name()); + + // Java arguments + m_arguments.append(splitArgs(m_instance->getJvmArgs())); + +#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 = m_instance->lwjglVersion(); + if (lwjgl != "Mojang") + lwjgl = QDir(settings->getLWJGLDir() + "/" + lwjgl).absolutePath(); + + // launcher arguments + m_arguments << QString("-Xms%1m").arg(m_instance->getMinMemAlloc()); + m_arguments << QString("-Xmx%1m").arg(m_instance->getMaxMemAlloc()); + 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/data/minecraftprocess.h b/data/minecraftprocess.h new file mode 100644 index 00000000..bede9486 --- /dev/null +++ b/data/minecraftprocess.h @@ -0,0 +1,98 @@ +/* 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. + */ +#ifndef MINECRAFTPROCESS_H +#define MINECRAFTPROCESS_H + +#include <QProcess> + +#include "gui/consolewindow.h" + +#include "instance.h" + +/** + * @file data/minecraftprocess.h + * @brief The MinecraftProcess class + */ +class 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(InstancePtr inst, QString user, QString session, ConsoleWindow *console); + + /** + * @brief launch minecraft + */ + void launch(); + + /** + * @brief extract the instance icon + * @param inst the instance + * @param destination the destination path + */ + static inline void extractIcon(InstancePtr 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(InstancePtr inst); + + /** + * @brief split a string into argv items like a shell would do + * @param args the argument string + * @return a QStringList containing all arguments + */ + static QStringList splitArgs(QString args); + +signals: + /** + * @brief emitted when mc has finished and the PostLaunchCommand was run + */ + void ended(); + +protected: + ConsoleWindow *m_console; + InstancePtr m_instance; + QString m_user; + QString m_session; + QProcess m_prepostlaunchprocess; + QStringList m_arguments; + + void genArgs(); + void log(QString text); + +protected slots: + void finish(int, QProcess::ExitStatus status); + void on_stdErr(); + void on_stdOut(); + +}; + +#endif // MINECRAFTPROCESS_H diff --git a/gui/aboutdialog.cpp b/gui/aboutdialog.cpp new file mode 100644 index 00000000..876f3044 --- /dev/null +++ b/gui/aboutdialog.cpp @@ -0,0 +1,23 @@ +#include "aboutdialog.h" +#include "ui_aboutdialog.h" + +#include <QIcon> +#include <QApplication> + +AboutDialog::AboutDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AboutDialog) +{ + ui->setupUi(this); + + ui->icon->setPixmap(QIcon(":/icons/multimc/scalable/apps/multimc.svg").pixmap(64)); + + connect(ui->closeButton, SIGNAL(clicked()), SLOT(close())); + + QApplication::instance()->connect(ui->aboutQt, SIGNAL(clicked()), SLOT(aboutQt())); +} + +AboutDialog::~AboutDialog() +{ + delete ui; +} diff --git a/gui/aboutdialog.h b/gui/aboutdialog.h new file mode 100644 index 00000000..d462de28 --- /dev/null +++ b/gui/aboutdialog.h @@ -0,0 +1,22 @@ +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H + +#include <QDialog> + +namespace Ui { +class AboutDialog; +} + +class AboutDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AboutDialog(QWidget *parent = 0); + ~AboutDialog(); + +private: + Ui::AboutDialog *ui; +}; + +#endif // ABOUTDIALOG_H diff --git a/gui/aboutdialog.ui b/gui/aboutdialog.ui new file mode 100644 index 00000000..6b8f906d --- /dev/null +++ b/gui/aboutdialog.ui @@ -0,0 +1,288 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AboutDialog</class> + <widget class="QDialog" name="AboutDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>450</width> + <height>400</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>450</width> + <height>400</height> + </size> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="icon"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>64</width> + <height>64</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>64</width> + <height>64</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QLabel" name="title"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="text"> + <string>MultiMC</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QToolBox" name="toolBox"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="aboutPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>432</width> + <height>153</height> + </rect> + </property> + <attribute name="label"> + <string>About</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="aboutLabel"> + <property name="text"> + <string>MultiMC is a custom launcher that makes managing Minecraft easier by allowing you to have multiple installations of Minecraft at once.</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="copyLabel"> + <property name="font"> + <font> + <pointsize>8</pointsize> + <kerning>true</kerning> + </font> + </property> + <property name="text"> + <string>© 2013 MultiMC Contributors</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="urlLabel"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="text"> + <string><html><head/><body><p><a href="http://github.com/Forkk/MultiMC5"><span style=" text-decoration: underline; color:#0000ff;">http://github.com/Forkk/MultiMC5</span></a></p></body></html></string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="creditsPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>432</width> + <height>153</height> + </rect> + </property> + <attribute name="label"> + <string>Credits</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QTextEdit" name="creditsText"> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="html"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Andrew Okin &lt;<a href="mailto:forkk@forkk.net"><span style=" text-decoration: underline; color:#0000ff;">forkk@forkk.net</span></a>&gt;</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Petr Mrázek &lt;<a href="mailto:peterix@gmail.com"><span style=" text-decoration: underline; color:#0000ff;">peterix@gmail.com</span></a>&gt;</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Orochimarufan &lt;<a href="mailto:orochimarufan.x3@gmail.com"><span style=" text-decoration: underline; color:#0000ff;">orochimarufan.x3@gmail.com</span></a>&gt;</p></body></html></string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="licensePage"> + <attribute name="label"> + <string>License</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QTextEdit" name="licenseText"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="html"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright 2012 MultiMC Contributors</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">you may not use this file except in compliance with the License.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may obtain a copy of the License at</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;"> http://www.apache.org/licenses/LICENSE-2.0</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Unless required by applicable law or agreed to in writing, software</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">See the License for the specific language governing permissions and</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">limitations under the License.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">MultiMC uses bspatch, </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright 2003-2005 Colin Percival</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights reserved</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Redistribution and use in source and binary forms, with or without</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">modification, are permitted providing that the following conditions</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">are met: </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Redistributions of source code must retain the above copyright</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;"> notice, this list of conditions and the following disclaimer.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Redistributions in binary form must reproduce the above copyright</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;"> notice, this list of conditions and the following disclaimer in the</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;"> documentation and/or other materials provided with the distribution.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY</span& |
