Merge remote-tracking branch 'upstream/master'
Conflicts: gui/mainwindow.cpp
This commit is contained in:
commit
dc39d09339
@ -176,6 +176,7 @@ gui/instancedelegate.h
|
||||
gui/versionselectdialog.h
|
||||
gui/lwjglselectdialog.h
|
||||
gui/iconcache.h
|
||||
gui/instancesettings.h
|
||||
|
||||
multimc_pragma.h
|
||||
|
||||
@ -208,6 +209,7 @@ gui/instancedelegate.cpp
|
||||
gui/versionselectdialog.cpp
|
||||
gui/lwjglselectdialog.cpp
|
||||
gui/iconcache.cpp
|
||||
gui/instancesettings.cpp
|
||||
|
||||
java/javautils.cpp
|
||||
java/annotations.cpp
|
||||
@ -228,6 +230,7 @@ gui/aboutdialog.ui
|
||||
gui/consolewindow.ui
|
||||
gui/versionselectdialog.ui
|
||||
gui/lwjglselectdialog.ui
|
||||
gui/instancesettings.ui
|
||||
)
|
||||
|
||||
|
||||
|
@ -21,7 +21,8 @@ SOURCES += main.cpp\
|
||||
data/inifile.cpp \
|
||||
gui/settingsdialog.cpp \
|
||||
gui/modeditwindow.cpp \
|
||||
util/appsettings.cpp
|
||||
util/appsettings.cpp \
|
||||
gui/instancesettings.cpp
|
||||
|
||||
HEADERS += gui/mainwindow.h \
|
||||
data/instancebase.h \
|
||||
@ -32,11 +33,13 @@ HEADERS += gui/mainwindow.h \
|
||||
gui/settingsdialog.h \
|
||||
gui/modeditwindow.h \
|
||||
util/apputils.h \
|
||||
util/appsettings.h
|
||||
util/appsettings.h \
|
||||
gui/instancesettings.h
|
||||
|
||||
FORMS += gui/mainwindow.ui \
|
||||
gui/settingsdialog.ui \
|
||||
gui/modeditwindow.ui
|
||||
gui/modeditwindow.ui \
|
||||
gui/instancesettings.ui
|
||||
|
||||
RESOURCES += \
|
||||
multimc.qrc
|
||||
|
@ -13,19 +13,11 @@ inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname)
|
||||
return QDomElement();
|
||||
}
|
||||
|
||||
// a job that removes all files from the base folder that don't match the whitelist
|
||||
// runs in whatever thread owns the queue. it is fast though.
|
||||
class NukeAndPaveJob: public Job
|
||||
class ThreadedDeleter : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NukeAndPaveJob(QString base, QStringList whitelist)
|
||||
:Job()
|
||||
{
|
||||
QDir dir(base);
|
||||
m_base = dir.absolutePath();
|
||||
m_whitelist = whitelist;
|
||||
};
|
||||
virtual void start()
|
||||
void run()
|
||||
{
|
||||
QDirIterator iter(m_base, QDirIterator::Subdirectories);
|
||||
QStringList nuke_list;
|
||||
@ -51,13 +43,37 @@ public:
|
||||
f.remove();
|
||||
}
|
||||
}
|
||||
emit finish();
|
||||
};
|
||||
private:
|
||||
QString m_base;
|
||||
QStringList m_whitelist;
|
||||
};
|
||||
|
||||
class NukeAndPaveJob: public Job
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
explicit NukeAndPaveJob(QString base, QStringList whitelist)
|
||||
:Job()
|
||||
{
|
||||
QDir dir(base);
|
||||
deleterThread.m_base = dir.absolutePath();
|
||||
deleterThread.m_whitelist = whitelist;
|
||||
};
|
||||
public slots:
|
||||
virtual void start()
|
||||
{
|
||||
connect(&deleterThread, SIGNAL(finished()), SLOT(threadFinished()));
|
||||
deleterThread.start();
|
||||
};
|
||||
void threadFinished()
|
||||
{
|
||||
emit finish();
|
||||
}
|
||||
private:
|
||||
ThreadedDeleter deleterThread;
|
||||
};
|
||||
|
||||
class DlMachine : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -84,7 +100,7 @@ public slots:
|
||||
qDebug() << "Failed to process s3.amazonaws.com/Minecraft.Resources. XML error:" <<
|
||||
xmlErrorMsg << ba;
|
||||
}
|
||||
QRegExp etag_match(".*([a-f0-9]{32}).*");
|
||||
//QRegExp etag_match(".*([a-f0-9]{32}).*");
|
||||
QDomNodeList contents = doc.elementsByTagName("Contents");
|
||||
|
||||
JobList *job = new JobList();
|
||||
|
180
gui/instancesettings.cpp
Normal file
180
gui/instancesettings.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Authors: Andrew Okin
|
||||
* Peterix
|
||||
* 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 "instancesettings.h"
|
||||
#include "ui_instancesettings.h"
|
||||
|
||||
InstanceSettings::InstanceSettings( SettingsObject * obj, QWidget *parent) :
|
||||
m_obj(obj),
|
||||
QDialog(parent),
|
||||
ui(new Ui::InstanceSettings)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
InstanceSettings::~InstanceSettings()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void InstanceSettings::on_customCommandsGroupBox_toggled(bool state)
|
||||
{
|
||||
ui->labelCustomCmdsDescription->setEnabled(state);
|
||||
}
|
||||
|
||||
void InstanceSettings::on_buttonBox_accepted()
|
||||
{
|
||||
applySettings();
|
||||
accept();
|
||||
}
|
||||
|
||||
void InstanceSettings::on_buttonBox_rejected()
|
||||
{
|
||||
reject();
|
||||
}
|
||||
|
||||
|
||||
void InstanceSettings::applySettings()
|
||||
{
|
||||
// Console
|
||||
bool console = ui->consoleSettingsBox->isChecked();
|
||||
m_obj->set("OverrideConsole", console);
|
||||
if(console)
|
||||
{
|
||||
m_obj->set("ShowConsole", ui->showConsoleCheck->isChecked());
|
||||
m_obj->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("ShowConsole");
|
||||
m_obj->reset("AutoCloseConsole");
|
||||
}
|
||||
|
||||
// Window Size
|
||||
bool window = ui->windowSizeGroupBox->isChecked();
|
||||
m_obj->set("OverrideWindow", window);
|
||||
if(window)
|
||||
{
|
||||
m_obj->set("LaunchCompatMode", ui->compatModeCheckBox->isChecked());
|
||||
m_obj->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
|
||||
m_obj->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
|
||||
m_obj->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("LaunchCompatMode");
|
||||
m_obj->reset("LaunchMaximized");
|
||||
m_obj->reset("MinecraftWinWidth");
|
||||
m_obj->reset("MinecraftWinHeight");
|
||||
}
|
||||
|
||||
|
||||
// Auto Login
|
||||
bool login = ui->accountSettingsGroupBox->isChecked();
|
||||
m_obj->set("OverrideLogin", login);
|
||||
if(login)
|
||||
{
|
||||
m_obj->set("AutoLogin", ui->autoLoginChecBox->isChecked());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("AutoLogin");
|
||||
}
|
||||
|
||||
|
||||
// Memory
|
||||
bool memory = ui->memoryGroupBox->isChecked();
|
||||
m_obj->set("OverrideMemory", memory);
|
||||
if(memory)
|
||||
{
|
||||
m_obj->set("MinMemAlloc", ui->minMemSpinBox->value());
|
||||
m_obj->set("MaxMemAlloc", ui->maxMemSpinBox->value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("MinMemAlloc");
|
||||
m_obj->reset("MaxMemAlloc");
|
||||
}
|
||||
|
||||
|
||||
// Java Settings
|
||||
bool java = ui->javaSettingsGroupBox->isChecked();
|
||||
m_obj->set("OverrideJava", java);
|
||||
if(java)
|
||||
{
|
||||
m_obj->set("JavaPath", ui->javaPathTextBox->text());
|
||||
m_obj->set("JvmArgs", ui->jvmArgsTextBox->text());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("JavaPath");
|
||||
m_obj->reset("JvmArgs");
|
||||
}
|
||||
|
||||
|
||||
// Custom Commands
|
||||
bool custcmd = ui->customCommandsGroupBox->isChecked();
|
||||
m_obj->set("OverrideCommands", custcmd);
|
||||
if(custcmd)
|
||||
{
|
||||
m_obj->set("PreLaunchCommand", ui->preLaunchCmdTextBox->text());
|
||||
m_obj->set("PostExitCommand", ui->postExitCmdTextBox->text());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("PreLaunchCommand");
|
||||
m_obj->reset("PostExitCommand");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InstanceSettings::loadSettings()
|
||||
{
|
||||
// Console
|
||||
ui->showConsoleCheck->setChecked(m_obj->get("ShowConsole").toBool());
|
||||
ui->autoCloseConsoleCheck->setChecked(m_obj->get("AutoCloseConsole").toBool());
|
||||
ui->consoleSettingsBox->setChecked(m_obj->get("OverrideConsole").toBool());
|
||||
|
||||
// Window Size
|
||||
ui->compatModeCheckBox->setChecked(m_obj->get("LaunchCompatMode").toBool());
|
||||
ui->maximizedCheckBox->setChecked(m_obj->get("LaunchMaximized").toBool());
|
||||
ui->windowWidthSpinBox->setValue(m_obj->get("MinecraftWinWidth").toInt());
|
||||
ui->windowHeightSpinBox->setValue(m_obj->get("MinecraftWinHeight").toInt());
|
||||
ui->windowSizeGroupBox->setChecked(m_obj->get("OverrideWindow").toBool());
|
||||
|
||||
// Auto Login
|
||||
ui->autoLoginChecBox->setChecked(m_obj->get("AutoLogin").toBool());
|
||||
ui->accountSettingsGroupBox->setChecked(m_obj->get("OverrideLogin").toBool());
|
||||
|
||||
// Memory
|
||||
ui->minMemSpinBox->setValue(m_obj->get("MinMemAlloc").toInt());
|
||||
ui->maxMemSpinBox->setValue(m_obj->get("MaxMemAlloc").toInt());
|
||||
ui->memoryGroupBox->setChecked(m_obj->get("OverrideMemory").toBool());
|
||||
|
||||
// Java Settings
|
||||
ui->javaPathTextBox->setText(m_obj->get("JavaPath").toString());
|
||||
ui->jvmArgsTextBox->setText(m_obj->get("JvmArgs").toString());
|
||||
ui->javaSettingsGroupBox->setChecked(m_obj->get("OverrideJava").toBool());
|
||||
|
||||
// Custom Commands
|
||||
ui->preLaunchCmdTextBox->setText(m_obj->get("PreLaunchCommand").toString());
|
||||
ui->postExitCmdTextBox->setText(m_obj->get("PostExitCommand").toString());
|
||||
ui->customCommandsGroupBox->setChecked(m_obj->get("OverrideCommands").toBool());
|
||||
}
|
34
gui/instancesettings.h
Normal file
34
gui/instancesettings.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef INSTANCESETTINGS_H
|
||||
#define INSTANCESETTINGS_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "settingsobject.h"
|
||||
|
||||
namespace Ui {
|
||||
class InstanceSettings;
|
||||
}
|
||||
|
||||
class InstanceSettings : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InstanceSettings(SettingsObject *s, QWidget *parent = 0);
|
||||
~InstanceSettings();
|
||||
|
||||
void updateCheckboxStuff();
|
||||
|
||||
void applySettings();
|
||||
void loadSettings();
|
||||
|
||||
private slots:
|
||||
void on_customCommandsGroupBox_toggled(bool arg1);
|
||||
void on_buttonBox_accepted();
|
||||
void on_buttonBox_rejected();
|
||||
|
||||
private:
|
||||
Ui::InstanceSettings *ui;
|
||||
SettingsObject * m_obj;
|
||||
};
|
||||
|
||||
#endif // INSTANCESETTINGS_H
|
416
gui/instancesettings.ui
Normal file
416
gui/instancesettings.ui
Normal file
@ -0,0 +1,416 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>InstanceSettings</class>
|
||||
<widget class="QDialog" name="InstanceSettings">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>453</width>
|
||||
<height>563</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<widget class="QTabWidget" name="settingsTabs">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>9</x>
|
||||
<y>9</y>
|
||||
<width>435</width>
|
||||
<height>516</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="tabShape">
|
||||
<enum>QTabWidget::Rounded</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="minecraftTab">
|
||||
<attribute name="title">
|
||||
<string>Minecraft</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="windowSizeGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Window Size</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="compatModeCheckBox">
|
||||
<property name="text">
|
||||
<string>Compatibility mode?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="maximizedCheckBox">
|
||||
<property name="text">
|
||||
<string>Start Minecraft maximized?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayoutWindowSize">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelWindowHeight">
|
||||
<property name="text">
|
||||
<string>Window height:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelWindowWidth">
|
||||
<property name="text">
|
||||
<string>Window width:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="windowWidthSpinBox">
|
||||
<property name="minimum">
|
||||
<number>854</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>854</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="windowHeightSpinBox">
|
||||
<property name="minimum">
|
||||
<number>480</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>480</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="consoleSettingsBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Console Settings</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showConsoleCheck">
|
||||
<property name="text">
|
||||
<string>Show console while the game is running?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCloseConsoleCheck">
|
||||
<property name="text">
|
||||
<string>Automatically close console when the game quits?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="accountSettingsGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Account Settings</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoLoginChecBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Login automatically when an instance icon is double clicked?</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacerMinecraft">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="javaTab">
|
||||
<attribute name="title">
|
||||
<string>Java</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="memoryGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Memory</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="maxMemSpinBox">
|
||||
<property name="minimum">
|
||||
<number>512</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelMinMem">
|
||||
<property name="text">
|
||||
<string>Minimum memory allocation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelMaxMem">
|
||||
<property name="text">
|
||||
<string>Maximum memory allocation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="minMemSpinBox">
|
||||
<property name="minimum">
|
||||
<number>256</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>256</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="javaSettingsGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Java Settings</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelJavaPath">
|
||||
<property name="text">
|
||||
<string>Java path:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="javaPathTextBox"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelJVMArgs">
|
||||
<property name="text">
|
||||
<string>JVM arguments:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>Auto-detect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="jvmArgsTextBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="customCommandsGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Custom Commands</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="preLaunchCmdTextBox"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelPostExitCmd">
|
||||
<property name="text">
|
||||
<string>Post-exit command:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelPreLaunchCmd">
|
||||
<property name="text">
|
||||
<string>Pre-launch command:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="postExitCmdTextBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelCustomCmdsDescription">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pre-launch command runs before the instance launches and post-exit command runs after it exits. Both will be run in MultiMC's working directory with INST_ID, INST_DIR, and INST_NAME as environment variables.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>9</x>
|
||||
<y>530</y>
|
||||
<width>435</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>settingsTabs</tabstop>
|
||||
<tabstop>windowSizeGroupBox</tabstop>
|
||||
<tabstop>compatModeCheckBox</tabstop>
|
||||
<tabstop>maximizedCheckBox</tabstop>
|
||||
<tabstop>windowWidthSpinBox</tabstop>
|
||||
<tabstop>windowHeightSpinBox</tabstop>
|
||||
<tabstop>consoleSettingsBox</tabstop>
|
||||
<tabstop>showConsoleCheck</tabstop>
|
||||
<tabstop>autoCloseConsoleCheck</tabstop>
|
||||
<tabstop>accountSettingsGroupBox</tabstop>
|
||||
<tabstop>autoLoginChecBox</tabstop>
|
||||
<tabstop>memoryGroupBox</tabstop>
|
||||
<tabstop>minMemSpinBox</tabstop>
|
||||
<tabstop>maxMemSpinBox</tabstop>
|
||||
<tabstop>javaSettingsGroupBox</tabstop>
|
||||
<tabstop>javaPathTextBox</tabstop>
|
||||
<tabstop>pushButton</tabstop>
|
||||
<tabstop>jvmArgsTextBox</tabstop>
|
||||
<tabstop>customCommandsGroupBox</tabstop>
|
||||
<tabstop>preLaunchCmdTextBox</tabstop>
|
||||
<tabstop>postExitCmdTextBox</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -43,6 +43,7 @@
|
||||
#include "gui/lwjglselectdialog.h"
|
||||
#include "gui/consolewindow.h"
|
||||
#include "gui/legacymodeditdialog.h"
|
||||
#include "gui/instancesettings.h"
|
||||
|
||||
#include "kcategorizedview.h"
|
||||
#include "kcategorydrawer.h"
|
||||
@ -130,6 +131,9 @@ MainWindow::MainWindow ( QWidget *parent ) :
|
||||
view->setModel ( proxymodel );
|
||||
connect(view, SIGNAL(doubleClicked(const QModelIndex &)),
|
||||
this, SLOT(instanceActivated(const QModelIndex &)));
|
||||
|
||||
connect(view, SIGNAL(clicked(const QModelIndex &)),
|
||||
this, SLOT(instanceChanged(const QModelIndex &)));
|
||||
|
||||
// Load the instances.
|
||||
instList.loadList();
|
||||
@ -417,7 +421,7 @@ void MainWindow::onLoginComplete(LoginResponse response)
|
||||
{
|
||||
Q_ASSERT_X(m_activeInst != NULL, "onLoginComplete", "no active instance is set");
|
||||
|
||||
if (!m_activeInst->shouldUpdateGame())
|
||||
if (!m_activeInst->shouldUpdate())
|
||||
{
|
||||
launchInstance(m_activeInst, response);
|
||||
}
|
||||
@ -554,3 +558,20 @@ void MainWindow::on_actionChangeInstLWJGLVersion_triggered()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionInstanceSettings_triggered()
|
||||
{
|
||||
if (view->selectionModel()->selectedIndexes().count() < 1)
|
||||
return;
|
||||
|
||||
Instance *inst = selectedInstance();
|
||||
SettingsObject *s;
|
||||
s = &inst->settings();
|
||||
InstanceSettings settings(s, this);
|
||||
settings.setWindowTitle(QString("Instance settings"));
|
||||
settings.exec();
|
||||
}
|
||||
|
||||
void MainWindow::instanceChanged(QModelIndex idx) {
|
||||
ui->instanceToolBar->setEnabled(idx.isValid());
|
||||
}
|
||||
|
@ -108,8 +108,12 @@ private slots:
|
||||
|
||||
void on_actionChangeInstLWJGLVersion_triggered();
|
||||
|
||||
void on_actionInstanceSettings_triggered();
|
||||
|
||||
public slots:
|
||||
void instanceActivated ( QModelIndex );
|
||||
|
||||
void instanceChanged ( QModelIndex );
|
||||
|
||||
void startTask(Task *task);
|
||||
|
||||
|
@ -65,6 +65,9 @@
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
<widget class="QToolBar" name="instanceToolBar">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Instance Toolbar</string>
|
||||
</property>
|
||||
@ -300,7 +303,7 @@
|
||||
</action>
|
||||
<action name="actionInstanceSettings">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Settings</string>
|
||||
|
@ -32,6 +32,9 @@ include/instversionlist.h
|
||||
include/minecraftversion.h
|
||||
include/minecraftversionlist.h
|
||||
|
||||
include/library.h
|
||||
include/fullversion.h
|
||||
include/fullversionfactory.h
|
||||
|
||||
# Tasks
|
||||
include/task.h
|
||||
@ -63,6 +66,9 @@ src/instversionlist.cpp
|
||||
src/minecraftversion.cpp
|
||||
src/minecraftversionlist.cpp
|
||||
|
||||
src/library.cpp
|
||||
src/fullversion.cpp
|
||||
src/fullversionfactory.cpp
|
||||
|
||||
# Tasks
|
||||
src/task.cpp
|
||||
|
69
libmultimc/include/fullversion.h
Normal file
69
libmultimc/include/fullversion.h
Normal file
@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
#include <QString>
|
||||
|
||||
class Library;
|
||||
|
||||
class FullVersion
|
||||
{
|
||||
public:
|
||||
FullVersion()
|
||||
{
|
||||
minimumLauncherVersion = 0xDEADBEEF;
|
||||
isLegacy = false;
|
||||
}
|
||||
// the ID - determines which jar to use! ACTUALLY IMPORTANT!
|
||||
QString id;
|
||||
// do we actually care about parsing this?
|
||||
QString time;
|
||||
// I don't think we do.
|
||||
QString releaseTime;
|
||||
// eh, not caring - "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. just the names for now. expand to full-blown strutures!
|
||||
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;
|
||||
};
|
25
libmultimc/include/fullversionfactory.h
Normal file
25
libmultimc/include/fullversionfactory.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;
|
||||
};
|
@ -22,47 +22,15 @@
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QUrl>
|
||||
#include "dlqueue.h"
|
||||
|
||||
#include "task.h"
|
||||
#include "loginresponse.h"
|
||||
#include "instance.h"
|
||||
|
||||
#include "libmmc_config.h"
|
||||
class FileToDownload;
|
||||
typedef QSharedPointer<FileToDownload> FileToDownloadPtr;
|
||||
|
||||
class FileToDownload : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/*!
|
||||
* The URL to download the file from.
|
||||
*/
|
||||
Q_PROPERTY(QUrl url READ url WRITE setURL)
|
||||
|
||||
/*!
|
||||
* The path to download to.
|
||||
* This path is relative to the instance's root directory.
|
||||
*/
|
||||
Q_PROPERTY(QString path READ path WRITE setPath)
|
||||
|
||||
private:
|
||||
FileToDownload(const QUrl &url, const QString &path, QObject *parent = 0);
|
||||
public:
|
||||
static FileToDownloadPtr Create(const QUrl &url, const QString &path, QObject *parent = 0);
|
||||
|
||||
virtual QUrl url() const { return m_dlURL; }
|
||||
virtual void setURL(const QUrl &url) { m_dlURL = url; }
|
||||
|
||||
virtual QString path() const { return m_dlPath; }
|
||||
virtual void setPath(const QString &path) { m_dlPath = path; }
|
||||
|
||||
private:
|
||||
QUrl m_dlURL;
|
||||
QString m_dlPath;
|
||||
};
|
||||
|
||||
|
||||
class MinecraftVersion;
|
||||
|
||||
/*!
|
||||
* The game update task is the task that handles downloading instances' files.
|
||||
@ -92,9 +60,6 @@ public:
|
||||
|
||||
virtual void executeTask();
|
||||
|
||||
virtual bool downloadFile(const FileToDownloadPtr file);
|
||||
|
||||
|
||||
//////////////////////
|
||||
// STATE AND STATUS //
|
||||
//////////////////////
|
||||
@ -110,6 +75,10 @@ public:
|
||||
*/
|
||||
virtual QString getStateMessage(int state);
|
||||
|
||||
private:
|
||||
void getLegacyJar();
|
||||
void determineNewVersion();
|
||||
|
||||
public slots:
|
||||
|
||||
/*!
|
||||
@ -122,7 +91,15 @@ public slots:
|
||||
|
||||
|
||||
private slots:
|
||||
virtual void updateDownloadProgress(qint64 current, qint64 total);
|
||||
void updateDownloadProgress(qint64 current, qint64 total);
|
||||
void legacyJarFinished();
|
||||
void legacyJarFailed();
|
||||
|
||||
void versionFileFinished();
|
||||
void versionFileFailed();
|
||||
|
||||
void jarlibFinished();
|
||||
void jarlibFailed();
|
||||
|
||||
signals:
|
||||
/*!
|
||||
@ -143,23 +120,8 @@ private:
|
||||
///////////
|
||||
|
||||
Instance *m_inst;
|
||||
|
||||
LoginResponse m_response;
|
||||
|
||||
QNetworkAccessManager *netMgr;
|
||||
|
||||
|
||||
|
||||
////////////////////////
|
||||
// FILE DOWNLOAD LIST //
|
||||
////////////////////////
|
||||
|
||||
// List of URLs that the game updater will need to download.
|
||||
QList<FileToDownloadPtr> m_downloadList;
|
||||
int m_currentDownload;
|
||||
|
||||
|
||||
|
||||
////////////////////////////
|
||||
// STATE AND STATUS STUFF //
|
||||
////////////////////////////
|
||||
@ -184,6 +146,13 @@ private:
|
||||
// Finished
|
||||
StateFinished
|
||||
};
|
||||
JobListPtr legacyDownloadJob;
|
||||
JobListPtr specificVersionDownloadJob;
|
||||
JobListPtr jarlibDownloadJob;
|
||||
JobListQueue download_queue;
|
||||
|
||||
// target version, determined during this task
|
||||
MinecraftVersion *targetVersion;
|
||||
};
|
||||
|
||||
|
||||
|
@ -80,16 +80,7 @@ class LIBMULTIMC_EXPORT Instance : public QObject
|
||||
* This returns true if shouldForceUpdate game is true or if the intended and
|
||||
* current versions don't match.
|
||||
*/
|
||||
Q_PROPERTY(bool shouldUpdateGame READ shouldUpdateGame STORED false)
|
||||
|
||||
/*!
|
||||
* Whether or not the game will be forced to update on the next launch.
|
||||
* If this is set to true, shouldUpdateGame will be true, regardless of whether or not
|
||||
* the current and intended versions match.
|
||||
* It should be noted that this is set to false automatically when game updates are run.
|
||||
*/
|
||||
Q_PROPERTY(bool shouldForceUpdateGame READ shouldForceUpdateGame WRITE setShouldForceUpdateGame)
|
||||
|
||||
Q_PROPERTY(bool shouldUpdate READ shouldUpdate WRITE setShouldUpdate)
|
||||
|
||||
/*!
|
||||
* The instance's current version.
|
||||
@ -125,8 +116,11 @@ class LIBMULTIMC_EXPORT Instance : public QObject
|
||||
*/
|
||||
Q_PROPERTY(qint64 lastCurrentVersionUpdate READ lastCurrentVersionUpdate WRITE setLastCurrentVersionUpdate)
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* Is the instance a new launcher instance? Get/Set
|
||||
*/
|
||||
Q_PROPERTY(bool isForNewLauncher READ isForNewLauncher WRITE setIsForNewLauncher)
|
||||
|
||||
// Dirs
|
||||
//! Path to the instance's .minecraft folder.
|
||||
Q_PROPERTY(QString minecraftDir READ minecraftDir STORED false)
|
||||
@ -236,14 +230,17 @@ public:
|
||||
virtual QString intendedVersion() const { return settings().get("IntendedJarVersion").toString(); }
|
||||
virtual void setIntendedVersion(QString val) { settings().set("IntendedJarVersion", val); }
|
||||
|
||||
virtual bool shouldUpdateGame() const
|
||||
{ return shouldForceUpdateGame() || intendedVersion() != currentVersion(); }
|
||||
|
||||
virtual bool shouldForceUpdateGame() const { return settings().get("ShouldForceUpdate").toBool(); }
|
||||
virtual void setShouldForceUpdateGame(bool val) { settings().set("ShouldForceUpdate", 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>(); }
|
||||
@ -256,6 +253,15 @@ public:
|
||||
virtual qint64 lastCurrentVersionUpdate() const { return settings().get("lastVersionUpdate").value<qint64>(); }
|
||||
virtual void setLastCurrentVersionUpdate(qint64 val) { settings().set("lastVersionUpdate", val); }
|
||||
|
||||
virtual bool isForNewLauncher()
|
||||
{
|
||||
return settings().get("IsForNewLauncher").value<bool>();
|
||||
}
|
||||
|
||||
virtual void setIsForNewLauncher(bool value = true)
|
||||
{
|
||||
settings().set("IsForNewLauncher", value);
|
||||
}
|
||||
|
||||
////// Directories //////
|
||||
QString minecraftDir() const;
|
||||
|
219
libmultimc/include/library.h
Normal file
219
libmultimc/include/library.h
Normal file
@ -0,0 +1,219 @@
|
||||
/* 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>
|
||||
|
||||
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:
|
||||
/// finalize the library, processing the input values into derived values and state
|
||||
void 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);
|
||||
}
|
||||
};
|
||||
|
||||
Library(QString name)
|
||||
{
|
||||
m_is_native = false;
|
||||
m_is_native = false;
|
||||
m_name = name;
|
||||
m_base_url = "https://s3.amazonaws.com/Minecraft.Download/libraries/";
|
||||
}
|
||||
|
||||
void setName(QString name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
void setBaseUrl(QString base_url)
|
||||
{
|
||||
m_base_url = base_url;
|
||||
}
|
||||
|
||||
void setIsNative()
|
||||
{
|
||||
m_is_native = true;
|
||||
}
|
||||
|
||||
void addNative(OpSys os, QString suffix)
|
||||
{
|
||||
m_is_native = true;
|
||||
m_native_suffixes[os] = suffix;
|
||||
}
|
||||
|
||||
void setRules(QList<QSharedPointer<Rule> > rules)
|
||||
{
|
||||
m_rules = rules;
|
||||
}
|
||||
|
||||
bool applies()
|
||||
{
|
||||
return m_is_active;
|
||||
}
|
||||
};
|
5
libmultimc/src/fullversion.cpp
Normal file
5
libmultimc/src/fullversion.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include <QtCore>
|
||||
#include "fullversion.h"
|
||||
#include <library.h>
|
||||
|
||||
// ECHO, echo, echo, ....
|
206
libmultimc/src/fullversionfactory.cpp
Normal file
206
libmultimc/src/fullversionfactory.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
#include "fullversionfactory.h"
|
||||
#include "fullversion.h"
|
||||
#include <library.h>
|
||||
|
||||
class LibraryFinalizer
|
||||
{
|
||||
public:
|
||||
LibraryFinalizer(QSharedPointer<Library> library)
|
||||
{
|
||||
m_library = library;
|
||||
}
|
||||
|
||||
QSharedPointer<Library> m_library;
|
||||
};
|
||||
|
||||
// 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,40 +25,34 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "minecraftversionlist.h"
|
||||
#include "fullversionfactory.h"
|
||||
#include <fullversion.h>
|
||||
|
||||
#include "pathutils.h"
|
||||
#include "netutils.h"
|
||||
|
||||
|
||||
GameUpdateTask::GameUpdateTask(const LoginResponse &response, Instance *inst, QObject *parent) :
|
||||
Task(parent), m_response(response)
|
||||
{
|
||||
m_inst = inst;
|
||||
m_updateState = StateInit;
|
||||
m_currentDownload = 0;
|
||||
}
|
||||
|
||||
void GameUpdateTask::executeTask()
|
||||
{
|
||||
updateStatus();
|
||||
|
||||
QNetworkAccessManager networkMgr;
|
||||
netMgr = &networkMgr;
|
||||
|
||||
// Get a pointer to the version object that corresponds to the instance's version.
|
||||
MinecraftVersion *targetVersion = (MinecraftVersion *)MinecraftVersionList::getMainList().
|
||||
targetVersion = (MinecraftVersion *)MinecraftVersionList::getMainList().
|
||||
findVersion(m_inst->intendedVersion());
|
||||
Q_ASSERT_X(targetVersion != NULL, "game update", "instance's intended version is not an actual version");
|
||||
|
||||
// Make directories
|
||||
QDir binDir(m_inst->binDir());
|
||||
if (!binDir.exists() && !binDir.mkpath("."))
|
||||
if(targetVersion == NULL)
|
||||
{
|
||||
error("Failed to create bin folder.");
|
||||
//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 //
|
||||
/////////////////////////
|
||||
@ -66,90 +60,150 @@ void GameUpdateTask::executeTask()
|
||||
|
||||
setState(StateDetermineURLs);
|
||||
|
||||
|
||||
// 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";
|
||||
|
||||
// FIXME: this is NOT enough
|
||||
if (targetVersion->launcherVersion() == MinecraftVersion::Launcher16)
|
||||
jarFilename = targetVersion->descriptor();
|
||||
|
||||
QUrl mcJarURL = targetVersion->downloadURL() + jarFilename + ".jar";
|
||||
qDebug() << mcJarURL.toString();
|
||||
m_downloadList.append(FileToDownload::Create(mcJarURL, PathCombine(m_inst->minecraftDir(), "bin/minecraft.jar")));
|
||||
|
||||
|
||||
|
||||
////////////////////
|
||||
// DOWNLOAD FILES //
|
||||
////////////////////
|
||||
setState(StateDownloadFiles);
|
||||
for (int i = 0; i < m_downloadList.length(); i++)
|
||||
{
|
||||
m_currentDownload = i;
|
||||
if (!downloadFile(m_downloadList[i]))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////
|
||||
// INSTALL FILES //
|
||||
///////////////////
|
||||
setState(StateInstall);
|
||||
|
||||
// Nothing to do here yet
|
||||
|
||||
|
||||
|
||||
//////////////
|
||||
// FINISHED //
|
||||
//////////////
|
||||
setState(StateFinished);
|
||||
emit gameUpdateComplete(m_response);
|
||||
}
|
||||
|
||||
bool GameUpdateTask::downloadFile( const FileToDownloadPtr file )
|
||||
{
|
||||
setSubStatus("Downloading " + file->url().toString());
|
||||
QNetworkReply *reply = netMgr->get(QNetworkRequest(file->url()));
|
||||
|
||||
this->connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
|
||||
SLOT(updateDownloadProgress(qint64,qint64)));
|
||||
|
||||
NetUtils::waitForNetRequest(reply);
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError)
|
||||
{
|
||||
QString filePath = file->path();
|
||||
QFile outFile(filePath);
|
||||
if (outFile.exists() && !outFile.remove())
|
||||
{
|
||||
error("Can't delete old file " + file->path() + ": " + outFile.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!outFile.open(QIODevice::WriteOnly))
|
||||
{
|
||||
error("Can't write to " + file->path() + ": " + outFile.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
outFile.write(reply->readAll());
|
||||
outFile.close();
|
||||
determineNewVersion();
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Can't download " + file->url().toString() + ": " + reply->errorString());
|
||||
return false;
|
||||
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);
|
||||
}
|
||||
|
||||
// TODO: Check file integrity after downloading.
|
||||
if(version->isLegacy)
|
||||
{
|
||||
getLegacyJar();
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
// 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->launcherVersion() == 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
|
||||
@ -223,22 +277,7 @@ void GameUpdateTask::error(const QString &msg)
|
||||
void GameUpdateTask::updateDownloadProgress(qint64 current, qint64 total)
|
||||
{
|
||||
// The progress on the current file is current / total
|
||||
float currentDLProgress = (float) current / (float) total; // Cast ALL the values!
|
||||
|
||||
// The overall progress is (current progress + files downloaded) / total files to download
|
||||
float overallDLProgress = ((currentDLProgress + m_currentDownload) / (float) m_downloadList.length());
|
||||
|
||||
// Multiply by 100 to make it a percentage.
|
||||
setProgress((int)(overallDLProgress * 100));
|
||||
float currentDLProgress = (float) current / (float) total;
|
||||
setProgress((int)(currentDLProgress * 100)); // convert to percentage
|
||||
}
|
||||
|
||||
FileToDownloadPtr FileToDownload::Create(const QUrl &url, const QString &path, QObject *parent)
|
||||
{
|
||||
return FileToDownloadPtr(new FileToDownload (url, path, parent));
|
||||
}
|
||||
|
||||
FileToDownload::FileToDownload(const QUrl &url, const QString &path, QObject *parent) :
|
||||
QObject(parent), m_dlURL(url), m_dlPath(path)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -34,7 +34,8 @@ Instance::Instance(const QString &rootDir, QObject *parent) :
|
||||
settings().registerSetting(new Setting("iconKey", "default"));
|
||||
settings().registerSetting(new Setting("notes", ""));
|
||||
settings().registerSetting(new Setting("NeedsRebuild", true));
|
||||
settings().registerSetting(new Setting("ShouldForceUpdate", false));
|
||||
settings().registerSetting(new Setting("IsForNewLauncher", false));
|
||||
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", ""));
|
||||
@ -62,6 +63,18 @@ Instance::Instance(const QString &rootDir, QObject *parent) :
|
||||
|
||||
// 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 Instance::id() const
|
||||
|
37
libmultimc/src/library.cpp
Normal file
37
libmultimc/src/library.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/* 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 "include/library.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;
|
||||
}
|
||||
// default url for lib:
|
@ -47,6 +47,7 @@ public:
|
||||
|
||||
protected slots:
|
||||
virtual void changeSetting(const Setting &setting, QVariant value);
|
||||
virtual void resetSetting ( const Setting& setting );
|
||||
|
||||
protected:
|
||||
virtual QVariant retrieveValue(const Setting &setting);
|
||||
|
@ -84,6 +84,12 @@ signals:
|
||||
*/
|
||||
void settingChanged(const Setting &setting, QVariant value);
|
||||
|
||||
/*!
|
||||
* \brief Signal emitted when this Setting object's value resets to default.
|
||||
* \param setting A reference to the Setting that changed.
|
||||
*/
|
||||
void settingReset(const Setting &setting);
|
||||
|
||||
public slots:
|
||||
/*!
|
||||
* \brief Changes the setting's value.
|
||||
@ -93,6 +99,13 @@ public slots:
|
||||
*/
|
||||
virtual void set(QVariant value);
|
||||
|
||||
/*!
|
||||
* \brief Reset the setting to default
|
||||
* This is done by emitting the settingReset() signal which will then be
|
||||
* handled by the SettingsObject object and cause the setting to change.
|
||||
* \param value The new value.
|
||||
*/
|
||||
virtual void reset();
|
||||
protected:
|
||||
QString m_id;
|
||||
QVariant m_defVal;
|
||||
|
@ -100,6 +100,11 @@ public:
|
||||
*/
|
||||
virtual bool set(const QString &id, QVariant value);
|
||||
|
||||
/*!
|
||||
* \brief Reverts the setting with the given ID to default.
|
||||
* \param id The ID of the setting to reset.
|
||||
*/
|
||||
virtual void reset(const QString &id) const;
|
||||
|
||||
/*!
|
||||
* \brief Gets a QList with pointers to all of the registered settings.
|
||||
@ -125,6 +130,14 @@ signals:
|
||||
*/
|
||||
void settingChanged(const Setting &setting, QVariant value);
|
||||
|
||||
/*!
|
||||
* \brief Signal emitted when one of this SettingsObject object's settings resets.
|
||||
* This is usually just connected directly to each Setting object's
|
||||
* settingReset() signals.
|
||||
* \param setting A reference to the Setting object that changed.
|
||||
*/
|
||||
void settingReset(const Setting &setting);
|
||||
|
||||
protected slots:
|
||||
/*!
|
||||
* \brief Changes a setting.
|
||||
@ -136,6 +149,15 @@ protected slots:
|
||||
*/
|
||||
virtual void changeSetting(const Setting &setting, QVariant value) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Resets a setting.
|
||||
* This slot is usually connected to each Setting object's
|
||||
* settingReset() signal. The signal is emitted, causing this slot
|
||||
* to update the setting's value in the config file.
|
||||
* \param setting A reference to the Setting object that changed.
|
||||
*/
|
||||
virtual void resetSetting(const Setting &setting) = 0;
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* \brief Connects the necessary signals to the given Setting.
|
||||
|
@ -40,6 +40,15 @@ void INISettingsObject::changeSetting(const Setting &setting, QVariant value)
|
||||
}
|
||||
}
|
||||
|
||||
void INISettingsObject::resetSetting ( const Setting& setting )
|
||||
{
|
||||
if (contains(setting.id()))
|
||||
{
|
||||
m_ini.remove(setting.configKey());
|
||||
m_ini.saveFile(m_filePath);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant INISettingsObject::retrieveValue(const Setting &setting)
|
||||
{
|
||||
if (contains(setting.id()))
|
||||
|
@ -47,3 +47,8 @@ void Setting::set(QVariant value)
|
||||
{
|
||||
emit settingChanged(*this, value);
|
||||
}
|
||||
|
||||
void Setting::reset()
|
||||
{
|
||||
emit settingReset(*this);
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ bool SettingsObject::registerSetting(Setting *setting)
|
||||
// Connect signals.
|
||||
connectSignals(*setting);
|
||||
|
||||
qDebug(QString("Registered setting %1.").arg(setting->id()).toUtf8());
|
||||
// qDebug(QString("Registered setting %1.").arg(setting->id()).toUtf8());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -98,6 +98,14 @@ bool SettingsObject::set(const QString &id, QVariant value)
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsObject::reset(const QString &id) const
|
||||
{
|
||||
Setting *setting = getSetting(id);
|
||||
if(setting)
|
||||
setting->reset();
|
||||
}
|
||||
|
||||
|
||||
QList<Setting *> SettingsObject::getSettings()
|
||||
{
|
||||
return m_settings.values();
|
||||
@ -115,6 +123,11 @@ void SettingsObject::connectSignals(const Setting &setting)
|
||||
SLOT(changeSetting(const Setting &, QVariant)));
|
||||
connect(&setting, SIGNAL(settingChanged(const Setting &, QVariant)),
|
||||
SIGNAL(settingChanged(const Setting &, QVariant)));
|
||||
|
||||
connect(&setting, SIGNAL(settingReset(Setting)),
|
||||
SLOT(resetSetting(const Setting &)));
|
||||
connect(&setting, SIGNAL(settingReset(Setting)),
|
||||
SIGNAL(settingReset(const Setting &)));
|
||||
}
|
||||
|
||||
void SettingsObject::disconnectSignals(const Setting &setting)
|
||||
@ -123,4 +136,9 @@ void SettingsObject::disconnectSignals(const Setting &setting)
|
||||
this, SLOT(changeSetting(const Setting &, QVariant)));
|
||||
setting.disconnect(SIGNAL(settingChanged(const Setting &, QVariant)),
|
||||
this, SIGNAL(settingChanged(const Setting &, QVariant)));
|
||||
|
||||
setting.disconnect(SIGNAL(settingReset(const Setting &, QVariant)),
|
||||
this, SLOT(resetSetting(const Setting &, QVariant)));
|
||||
setting.disconnect(SIGNAL(settingReset(const Setting &, QVariant)),
|
||||
this, SIGNAL(settingReset(const Setting &, QVariant)));
|
||||
}
|
||||
|
@ -5,13 +5,16 @@
|
||||
/**
|
||||
* A single file for the downloader/cache to process.
|
||||
*/
|
||||
class DownloadJob : public Job
|
||||
class LIBUTIL_EXPORT DownloadJob : public Job
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DownloadJob(QUrl url, QString rel_target_path = QString(), QString expected_md5 = QString());
|
||||
static JobPtr create(QUrl url, QString rel_target_path = QString(), QString expected_md5 = QString());
|
||||
|
||||
|
||||
public:
|
||||
static bool ensurePathExists(QString filenamepath);
|
||||
public slots:
|
||||
virtual void start();
|
||||
|
||||
@ -37,8 +40,10 @@ public:
|
||||
|
||||
/// save to file?
|
||||
bool m_save_to_file;
|
||||
/// is the saving file already open?
|
||||
bool m_opened_for_saving;
|
||||
/// if saving to file, use the one specified in this string
|
||||
QString m_rel_target_path;
|
||||
QString m_target_path;
|
||||
/// this is the output file, if any
|
||||
QFile m_output_file;
|
||||
/// if not saving to file, downloaded data is placed here
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <QtCore>
|
||||
#include "libutil_config.h"
|
||||
|
||||
enum JobStatus
|
||||
{
|
||||
@ -11,7 +12,7 @@ enum JobStatus
|
||||
|
||||
class JobList;
|
||||
|
||||
class Job : public QObject
|
||||
class LIBUTIL_EXPORT Job : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
@ -30,7 +31,7 @@ typedef QSharedPointer<Job> JobPtr;
|
||||
/**
|
||||
* A list of jobs, to be processed one by one.
|
||||
*/
|
||||
class JobList : public QObject
|
||||
class LIBUTIL_EXPORT JobList : public QObject
|
||||
{
|
||||
friend class JobListQueue;
|
||||
Q_OBJECT
|
||||
@ -127,7 +128,7 @@ typedef QSharedPointer<JobList> JobListPtr;
|
||||
/**
|
||||
* A queue of job lists! The job lists fail or finish as units.
|
||||
*/
|
||||
class JobListQueue : public QObject
|
||||
class LIBUTIL_EXPORT JobListQueue : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -1,20 +1,28 @@
|
||||
#include "include/dlqueue.h"
|
||||
|
||||
DownloadJob::DownloadJob ( QUrl url, QString rel_target_path, QString expected_md5 )
|
||||
DownloadJob::DownloadJob ( QUrl url, QString target_path, QString expected_md5 )
|
||||
:Job()
|
||||
{
|
||||
m_url = url;
|
||||
m_rel_target_path = rel_target_path;
|
||||
m_target_path = target_path;
|
||||
m_expected_md5 = expected_md5;
|
||||
|
||||
m_check_md5 = m_expected_md5.size();
|
||||
m_save_to_file = m_rel_target_path.size();
|
||||
m_save_to_file = m_target_path.size();
|
||||
m_status = Job_NotStarted;
|
||||
m_opened_for_saving = false;
|
||||
}
|
||||
|
||||
JobPtr DownloadJob::create ( QUrl url, QString rel_target_path, QString expected_md5 )
|
||||
JobPtr DownloadJob::create ( QUrl url, QString target_path, QString expected_md5 )
|
||||
{
|
||||
return JobPtr ( new DownloadJob ( url, rel_target_path, expected_md5 ) );
|
||||
return JobPtr ( new DownloadJob ( url, target_path, expected_md5 ) );
|
||||
}
|
||||
|
||||
bool DownloadJob::ensurePathExists(QString filenamepath)
|
||||
{
|
||||
QFileInfo a ( filenamepath );
|
||||
QDir dir;
|
||||
return (dir.mkpath ( a.path() ));
|
||||
}
|
||||
|
||||
void DownloadJob::start()
|
||||
@ -22,47 +30,35 @@ void DownloadJob::start()
|
||||
m_manager.reset ( new QNetworkAccessManager() );
|
||||
if ( m_save_to_file )
|
||||
{
|
||||
QString filename = m_rel_target_path;
|
||||
QString filename = m_target_path;
|
||||
m_output_file.setFileName ( filename );
|
||||
// if there already is a file and md5 checking is in effect
|
||||
if ( m_output_file.exists() && m_check_md5 )
|
||||
// if there already is a file and md5 checking is in effect and it can be opened
|
||||
if ( m_output_file.exists() && m_output_file.open ( QIODevice::ReadOnly ) )
|
||||
{
|
||||
// and it can be opened
|
||||
if ( m_output_file.open ( QIODevice::ReadOnly ) )
|
||||
// check the md5 against the expected one
|
||||
QString hash = QCryptographicHash::hash ( m_output_file.readAll(), QCryptographicHash::Md5 ).toHex().constData();
|
||||
m_output_file.close();
|
||||
// skip this file if they match
|
||||
if ( m_check_md5 && hash == m_expected_md5 )
|
||||
{
|
||||
// check the md5 against the expected one
|
||||
QString hash = QCryptographicHash::hash ( m_output_file.readAll(), QCryptographicHash::Md5 ).toHex().constData();
|
||||
m_output_file.close();
|
||||
// skip this file if they match
|
||||
if ( hash == m_expected_md5 )
|
||||
{
|
||||
qDebug() << "Skipping " << m_url.toString() << ": md5 match.";
|
||||
emit finish();
|
||||
return;
|
||||
}
|
||||
qDebug() << "Skipping " << m_url.toString() << ": md5 match.";
|
||||
emit finish();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_expected_md5 = hash;
|
||||
}
|
||||
}
|
||||
QFileInfo a ( filename );
|
||||
QDir dir;
|
||||
if ( !dir.mkpath ( a.path() ) )
|
||||
if(!ensurePathExists(filename))
|
||||
{
|
||||
/*
|
||||
* error when making the folder structure
|
||||
*/
|
||||
emit fail();
|
||||
return;
|
||||
}
|
||||
if ( !m_output_file.open ( QIODevice::WriteOnly ) )
|
||||
{
|
||||
/*
|
||||
* Can't open the file... the job failed
|
||||
*/
|
||||
emit fail();
|
||||
return;
|
||||
}
|
||||
}
|
||||
qDebug() << "Downloading " << m_url.toString();
|
||||
QNetworkRequest request ( m_url );
|
||||
request.setRawHeader(QString("If-None-Match").toLatin1(), m_expected_md5.toLatin1());
|
||||
QNetworkReply * rep = m_manager->get ( request );
|
||||
m_reply = QSharedPointer<QNetworkReply> ( rep, &QObject::deleteLater );
|
||||
connect ( rep, SIGNAL ( downloadProgress ( qint64,qint64 ) ), SLOT ( downloadProgress ( qint64,qint64 ) ) );
|
||||
@ -121,8 +117,21 @@ void DownloadJob::downloadFinished()
|
||||
|
||||
void DownloadJob::downloadReadyRead()
|
||||
{
|
||||
if ( m_save_to_file )
|
||||
if( m_save_to_file )
|
||||
{
|
||||
if(!m_opened_for_saving)
|
||||
{
|
||||
if ( !m_output_file.open ( QIODevice::WriteOnly ) )
|
||||
{
|
||||
/*
|
||||
* Can't open the file... the job failed
|
||||
*/
|
||||
m_reply->abort();
|
||||
emit fail();
|
||||
return;
|
||||
}
|
||||
m_opened_for_saving = true;
|
||||
}
|
||||
m_output_file.write ( m_reply->readAll() );
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user