Merge branch 'develop' into feature_badges
Conflicts: logic/OneSixInstance.cpp
This commit is contained in:
commit
fcc5bc2ce0
2
.gitignore
vendored
2
.gitignore
vendored
@ -13,6 +13,8 @@ MultiMC5.kdev4
|
|||||||
MultiMC.pro.user
|
MultiMC.pro.user
|
||||||
CMakeLists.txt.user
|
CMakeLists.txt.user
|
||||||
CMakeLists.txt.user.*
|
CMakeLists.txt.user.*
|
||||||
|
/.project
|
||||||
|
/.settings
|
||||||
|
|
||||||
# Build dirs
|
# Build dirs
|
||||||
build
|
build
|
||||||
|
@ -257,6 +257,7 @@ SET(MULTIMC_SOURCES
|
|||||||
MultiMC.h
|
MultiMC.h
|
||||||
MultiMC.cpp
|
MultiMC.cpp
|
||||||
MultiMCVersion.h
|
MultiMCVersion.h
|
||||||
|
MMCError.h
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
logger/QsDebugOutput.cpp
|
logger/QsDebugOutput.cpp
|
||||||
@ -353,6 +354,10 @@ logic/ModList.cpp
|
|||||||
logic/InstanceLauncher.h
|
logic/InstanceLauncher.h
|
||||||
logic/InstanceLauncher.cpp
|
logic/InstanceLauncher.cpp
|
||||||
|
|
||||||
|
# JSON parsing helpers
|
||||||
|
logic/MMCJson.h
|
||||||
|
logic/MMCJson.cpp
|
||||||
|
|
||||||
# network stuffs
|
# network stuffs
|
||||||
logic/net/NetAction.h
|
logic/net/NetAction.h
|
||||||
logic/net/MD5EtagDownload.h
|
logic/net/MD5EtagDownload.h
|
||||||
@ -414,31 +419,38 @@ logic/LegacyInstance.cpp
|
|||||||
logic/LegacyInstance_p.h
|
logic/LegacyInstance_p.h
|
||||||
logic/LegacyUpdate.h
|
logic/LegacyUpdate.h
|
||||||
logic/LegacyUpdate.cpp
|
logic/LegacyUpdate.cpp
|
||||||
|
|
||||||
logic/LegacyForge.h
|
logic/LegacyForge.h
|
||||||
logic/LegacyForge.cpp
|
logic/LegacyForge.cpp
|
||||||
|
|
||||||
# OneSix instances
|
# OneSix instances
|
||||||
logic/OneSixUpdate.h
|
logic/OneSixUpdate.h
|
||||||
logic/OneSixUpdate.cpp
|
logic/OneSixUpdate.cpp
|
||||||
logic/OneSixVersion.h
|
logic/OneSixInstance.h
|
||||||
logic/OneSixVersion.cpp
|
logic/OneSixInstance.cpp
|
||||||
|
logic/OneSixInstance_p.h
|
||||||
|
|
||||||
|
# OneSix version json infrastructure
|
||||||
|
logic/OneSixVersionBuilder.h
|
||||||
|
logic/OneSixVersionBuilder.cpp
|
||||||
|
logic/VersionFile.h
|
||||||
|
logic/VersionFile.cpp
|
||||||
|
logic/VersionFinal.h
|
||||||
|
logic/VersionFinal.cpp
|
||||||
logic/OneSixLibrary.h
|
logic/OneSixLibrary.h
|
||||||
logic/OneSixLibrary.cpp
|
logic/OneSixLibrary.cpp
|
||||||
logic/OneSixRule.h
|
logic/OneSixRule.h
|
||||||
logic/OneSixRule.cpp
|
logic/OneSixRule.cpp
|
||||||
logic/OpSys.h
|
logic/OpSys.h
|
||||||
logic/OpSys.cpp
|
logic/OpSys.cpp
|
||||||
|
|
||||||
|
# Mod installers
|
||||||
logic/BaseInstaller.h
|
logic/BaseInstaller.h
|
||||||
logic/BaseInstaller.cpp
|
logic/BaseInstaller.cpp
|
||||||
logic/ForgeInstaller.h
|
logic/ForgeInstaller.h
|
||||||
logic/ForgeInstaller.cpp
|
logic/ForgeInstaller.cpp
|
||||||
logic/LiteLoaderInstaller.h
|
logic/LiteLoaderInstaller.h
|
||||||
logic/LiteLoaderInstaller.cpp
|
logic/LiteLoaderInstaller.cpp
|
||||||
logic/OneSixInstance.h
|
|
||||||
logic/OneSixInstance.cpp
|
|
||||||
logic/OneSixInstance_p.h
|
|
||||||
logic/OneSixVersionBuilder.h
|
|
||||||
logic/OneSixVersionBuilder.cpp
|
|
||||||
|
|
||||||
# Nostalgia
|
# Nostalgia
|
||||||
logic/NostalgiaInstance.h
|
logic/NostalgiaInstance.h
|
||||||
@ -758,24 +770,8 @@ INCLUDE(CPack)
|
|||||||
|
|
||||||
include_directories(${PROJECT_BINARY_DIR}/include)
|
include_directories(${PROJECT_BINARY_DIR}/include)
|
||||||
|
|
||||||
### translation stuff
|
# Translations
|
||||||
|
add_subdirectory(translations)
|
||||||
file (GLOB TRANSLATIONS_FILES translations/*.ts)
|
|
||||||
|
|
||||||
option (UPDATE_TRANSLATIONS "Update source translation translations/*.ts files (WARNING: make clean will delete the source .ts files! Danger!)")
|
|
||||||
IF(UPDATE_TRANSLATIONS)
|
|
||||||
qt5_create_translation(QM_FILES ${FILES_TO_TRANSLATE} ${TRANSLATIONS_FILES})
|
|
||||||
ELSE()
|
|
||||||
qt5_add_translation(QM_FILES ${TRANSLATIONS_FILES})
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
add_custom_target (translations DEPENDS ${QM_FILES})
|
|
||||||
IF(APPLE AND UNIX) ## OSX
|
|
||||||
install(FILES ${QM_FILES} DESTINATION MultiMC.app/Contents/MacOS/translations)
|
|
||||||
ELSE()
|
|
||||||
install(FILES ${QM_FILES} DESTINATION translations)
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
25
MMCError.h
Normal file
25
MMCError.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <exception>
|
||||||
|
#include <QString>
|
||||||
|
#include <logger/QsLog.h>
|
||||||
|
|
||||||
|
class MMCError : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MMCError(QString cause)
|
||||||
|
{
|
||||||
|
exceptionCause = cause;
|
||||||
|
QLOG_ERROR() << "Exception: " + cause;
|
||||||
|
};
|
||||||
|
virtual ~MMCError() noexcept {}
|
||||||
|
virtual const char *what() const noexcept
|
||||||
|
{
|
||||||
|
return exceptionCause.toLocal8Bit();
|
||||||
|
};
|
||||||
|
virtual QString cause() const
|
||||||
|
{
|
||||||
|
return exceptionCause;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
QString exceptionCause;
|
||||||
|
};
|
18
MultiMC.cpp
18
MultiMC.cpp
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
#include "MultiMC.h"
|
#include "MultiMC.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@ -43,6 +42,11 @@
|
|||||||
#include "logger/QsLog.h"
|
#include "logger/QsLog.h"
|
||||||
#include <logger/QsLogDest.h>
|
#include <logger/QsLogDest.h>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
static const int APPDATA_BUFFER_SIZE = 1024;
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace Util::Commandline;
|
using namespace Util::Commandline;
|
||||||
|
|
||||||
MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
||||||
@ -340,7 +344,16 @@ void MultiMC::initGlobalSettings()
|
|||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
QString ftbDefault = QDir::home().absoluteFilePath(".ftblauncher");
|
QString ftbDefault = QDir::home().absoluteFilePath(".ftblauncher");
|
||||||
#elif defined(Q_OS_WIN32)
|
#elif defined(Q_OS_WIN32)
|
||||||
QString ftbDefault = PathCombine(QStandardPaths::writableLocation(QStandardPaths::DataLocation), "/ftblauncher");
|
wchar_t buf[APPDATA_BUFFER_SIZE];
|
||||||
|
QString ftbDefault;
|
||||||
|
if(!GetEnvironmentVariableW(L"APPDATA", buf, APPDATA_BUFFER_SIZE))
|
||||||
|
{
|
||||||
|
QLOG_FATAL() << "Your APPDATA folder is missing! If you are on windows, this means your system is broken. If you aren't on windows, how the **** are you running the windows build????";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ftbDefault = PathCombine(QString::fromWCharArray(buf), "ftblauncher");
|
||||||
|
}
|
||||||
#elif defined(Q_OS_MAC)
|
#elif defined(Q_OS_MAC)
|
||||||
QString ftbDefault =
|
QString ftbDefault =
|
||||||
PathCombine(QDir::homePath(), "Library/Application Support/ftblauncher");
|
PathCombine(QDir::homePath(), "Library/Application Support/ftblauncher");
|
||||||
@ -457,6 +470,7 @@ void MultiMC::initHttpMetaCache()
|
|||||||
m_metacache->addBase("versions", QDir("versions").absolutePath());
|
m_metacache->addBase("versions", QDir("versions").absolutePath());
|
||||||
m_metacache->addBase("libraries", QDir("libraries").absolutePath());
|
m_metacache->addBase("libraries", QDir("libraries").absolutePath());
|
||||||
m_metacache->addBase("minecraftforge", QDir("mods/minecraftforge").absolutePath());
|
m_metacache->addBase("minecraftforge", QDir("mods/minecraftforge").absolutePath());
|
||||||
|
m_metacache->addBase("liteloader", QDir("mods/liteloader").absolutePath());
|
||||||
m_metacache->addBase("skins", QDir("accounts/skins").absolutePath());
|
m_metacache->addBase("skins", QDir("accounts/skins").absolutePath());
|
||||||
m_metacache->addBase("root", QDir(root()).absolutePath());
|
m_metacache->addBase("root", QDir(root()).absolutePath());
|
||||||
m_metacache->Load();
|
m_metacache->Load();
|
||||||
|
@ -28,6 +28,11 @@ void INISettingsObject::setFilePath(const QString &filePath)
|
|||||||
m_filePath = filePath;
|
m_filePath = filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool INISettingsObject::reload()
|
||||||
|
{
|
||||||
|
return m_ini.loadFile(m_filePath) && SettingsObject::reload();
|
||||||
|
}
|
||||||
|
|
||||||
void INISettingsObject::changeSetting(const Setting &setting, QVariant value)
|
void INISettingsObject::changeSetting(const Setting &setting, QVariant value)
|
||||||
{
|
{
|
||||||
if (contains(setting.id()))
|
if (contains(setting.id()))
|
||||||
|
@ -47,6 +47,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void setFilePath(const QString &filePath);
|
virtual void setFilePath(const QString &filePath);
|
||||||
|
|
||||||
|
bool reload() override;
|
||||||
|
|
||||||
protected
|
protected
|
||||||
slots:
|
slots:
|
||||||
virtual void changeSetting(const Setting &setting, QVariant value);
|
virtual void changeSetting(const Setting &setting, QVariant value);
|
||||||
|
@ -126,6 +126,15 @@ bool SettingsObject::contains(const QString &id)
|
|||||||
return m_settings.contains(id);
|
return m_settings.contains(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SettingsObject::reload()
|
||||||
|
{
|
||||||
|
for (auto setting : m_settings.values())
|
||||||
|
{
|
||||||
|
setting->set(setting->get());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsObject::connectSignals(const Setting &setting)
|
void SettingsObject::connectSignals(const Setting &setting)
|
||||||
{
|
{
|
||||||
connect(&setting, SIGNAL(settingChanged(const Setting &, QVariant)),
|
connect(&setting, SIGNAL(settingChanged(const Setting &, QVariant)),
|
||||||
|
@ -113,6 +113,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool contains(const QString &id);
|
bool contains(const QString &id);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Reloads the settings and emit signals for changed settings
|
||||||
|
* \return True if reloading was successful
|
||||||
|
*/
|
||||||
|
virtual bool reload();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/*!
|
/*!
|
||||||
* \brief Signal emitted when one of this SettingsObject object's settings changes.
|
* \brief Signal emitted when one of this SettingsObject object's settings changes.
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
#include "gui/dialogs/ProgressDialog.h"
|
#include "gui/dialogs/ProgressDialog.h"
|
||||||
|
|
||||||
#include "logic/ModList.h"
|
#include "logic/ModList.h"
|
||||||
#include "logic/OneSixVersion.h"
|
#include "logic/VersionFinal.h"
|
||||||
#include "logic/EnabledItemFilter.h"
|
#include "logic/EnabledItemFilter.h"
|
||||||
#include "logic/lists/ForgeVersionList.h"
|
#include "logic/lists/ForgeVersionList.h"
|
||||||
#include "logic/lists/LiteLoaderVersionList.h"
|
#include "logic/lists/LiteLoaderVersionList.h"
|
||||||
@ -42,8 +42,7 @@
|
|||||||
#include "logic/LiteLoaderInstaller.h"
|
#include "logic/LiteLoaderInstaller.h"
|
||||||
#include "logic/OneSixVersionBuilder.h"
|
#include "logic/OneSixVersionBuilder.h"
|
||||||
|
|
||||||
template<typename A, typename B>
|
template <typename A, typename B> QMap<A, B> invert(const QMap<B, A> &in)
|
||||||
QMap<A, B> invert(const QMap<B, A> &in)
|
|
||||||
{
|
{
|
||||||
QMap<A, B> out;
|
QMap<A, B> out;
|
||||||
for (auto it = in.begin(); it != in.end(); ++it)
|
for (auto it = in.begin(); it != in.end(); ++it)
|
||||||
@ -96,7 +95,8 @@ OneSixModEditDialog::OneSixModEditDialog(OneSixInstance *inst, QWidget *parent)
|
|||||||
m_resourcepacks->startWatching();
|
m_resourcepacks->startWatching();
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(m_inst, &OneSixInstance::versionReloaded, this, &OneSixModEditDialog::updateVersionControls);
|
connect(m_inst, &OneSixInstance::versionReloaded, this,
|
||||||
|
&OneSixModEditDialog::updateVersionControls);
|
||||||
}
|
}
|
||||||
|
|
||||||
OneSixModEditDialog::~OneSixModEditDialog()
|
OneSixModEditDialog::~OneSixModEditDialog()
|
||||||
@ -110,7 +110,6 @@ void OneSixModEditDialog::updateVersionControls()
|
|||||||
{
|
{
|
||||||
ui->forgeBtn->setEnabled(true);
|
ui->forgeBtn->setEnabled(true);
|
||||||
ui->liteloaderBtn->setEnabled(true);
|
ui->liteloaderBtn->setEnabled(true);
|
||||||
ui->mainClassEdit->setText(m_version->mainClass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixModEditDialog::disableVersionControls()
|
void OneSixModEditDialog::disableVersionControls()
|
||||||
@ -119,120 +118,81 @@ void OneSixModEditDialog::disableVersionControls()
|
|||||||
ui->liteloaderBtn->setEnabled(false);
|
ui->liteloaderBtn->setEnabled(false);
|
||||||
ui->reloadLibrariesBtn->setEnabled(false);
|
ui->reloadLibrariesBtn->setEnabled(false);
|
||||||
ui->removeLibraryBtn->setEnabled(false);
|
ui->removeLibraryBtn->setEnabled(false);
|
||||||
ui->mainClassEdit->setText("");
|
}
|
||||||
|
|
||||||
|
bool OneSixModEditDialog::reloadInstanceVersion()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_inst->reloadVersion();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (MMCError &e)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(
|
||||||
|
this, tr("Error"),
|
||||||
|
tr("Failed to load the version description file for reasons unknown."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixModEditDialog::on_reloadLibrariesBtn_clicked()
|
void OneSixModEditDialog::on_reloadLibrariesBtn_clicked()
|
||||||
{
|
{
|
||||||
m_inst->reloadVersion(this);
|
reloadInstanceVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixModEditDialog::on_removeLibraryBtn_clicked()
|
void OneSixModEditDialog::on_removeLibraryBtn_clicked()
|
||||||
{
|
{
|
||||||
if (ui->libraryTreeView->currentIndex().isValid())
|
if (ui->libraryTreeView->currentIndex().isValid())
|
||||||
{
|
{
|
||||||
|
// FIXME: use actual model, not reloading.
|
||||||
if (!m_version->remove(ui->libraryTreeView->currentIndex().row()))
|
if (!m_version->remove(ui->libraryTreeView->currentIndex().row()))
|
||||||
{
|
{
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
|
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_inst->reloadVersion(this);
|
reloadInstanceVersion();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixModEditDialog::on_resetLibraryOrderBtn_clicked()
|
void OneSixModEditDialog::on_resetLibraryOrderBtn_clicked()
|
||||||
{
|
{
|
||||||
QDir(m_inst->instanceRoot()).remove("order.json");
|
// FIXME: IMPLEMENT LOGIC IN MODEL. SEE LEGACY DIALOG FOR EXAMPLE(S).
|
||||||
m_inst->reloadVersion(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixModEditDialog::on_moveLibraryUpBtn_clicked()
|
void OneSixModEditDialog::on_moveLibraryUpBtn_clicked()
|
||||||
{
|
{
|
||||||
|
// FIXME: IMPLEMENT LOGIC IN MODEL. SEE LEGACY DIALOG FOR EXAMPLE(S).
|
||||||
QMap<QString, int> order = getExistingOrder();
|
|
||||||
if (order.size() < 2 || ui->libraryTreeView->selectionModel()->selectedIndexes().isEmpty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const int ourRow = ui->libraryTreeView->selectionModel()->selectedIndexes().first().row();
|
|
||||||
const QString ourId = m_version->versionFileId(ourRow);
|
|
||||||
const int ourOrder = order[ourId];
|
|
||||||
if (ourId.isNull() || ourId.startsWith("org.multimc."))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMap<int, QString> sortedOrder = invert(order);
|
|
||||||
|
|
||||||
QList<int> sortedOrders = sortedOrder.keys();
|
|
||||||
const int ourIndex = sortedOrders.indexOf(ourOrder);
|
|
||||||
if (ourIndex <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const int ourNewOrder = sortedOrders.at(ourIndex - 1);
|
|
||||||
order[ourId] = ourNewOrder;
|
|
||||||
order[sortedOrder[sortedOrders[ourIndex - 1]]] = ourOrder;
|
|
||||||
|
|
||||||
if (!OneSixVersionBuilder::writeOverrideOrders(order, m_inst))
|
|
||||||
{
|
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't save the new order"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_inst->reloadVersion(this);
|
|
||||||
ui->libraryTreeView->selectionModel()->select(m_version->index(ourRow - 1), QItemSelectionModel::SelectCurrent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixModEditDialog::on_moveLibraryDownBtn_clicked()
|
void OneSixModEditDialog::on_moveLibraryDownBtn_clicked()
|
||||||
{
|
{
|
||||||
QMap<QString, int> order = getExistingOrder();
|
// FIXME: IMPLEMENT LOGIC IN MODEL. SEE LEGACY DIALOG FOR EXAMPLE(S).
|
||||||
if (order.size() < 2 || ui->libraryTreeView->selectionModel()->selectedIndexes().isEmpty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const int ourRow = ui->libraryTreeView->selectionModel()->selectedIndexes().first().row();
|
|
||||||
const QString ourId = m_version->versionFileId(ourRow);
|
|
||||||
const int ourOrder = order[ourId];
|
|
||||||
if (ourId.isNull() || ourId.startsWith("org.multimc."))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMap<int, QString> sortedOrder = invert(order);
|
|
||||||
|
|
||||||
QList<int> sortedOrders = sortedOrder.keys();
|
|
||||||
const int ourIndex = sortedOrders.indexOf(ourOrder);
|
|
||||||
if ((ourIndex + 1) >= sortedOrders.size())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const int ourNewOrder = sortedOrders.at(ourIndex + 1);
|
|
||||||
order[ourId] = ourNewOrder;
|
|
||||||
order[sortedOrder[sortedOrders[ourIndex + 1]]] = ourOrder;
|
|
||||||
|
|
||||||
if (!OneSixVersionBuilder::writeOverrideOrders(order, m_inst))
|
|
||||||
{
|
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't save the new order"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_inst->reloadVersion(this);
|
|
||||||
ui->libraryTreeView->selectionModel()->select(m_version->index(ourRow + 1), QItemSelectionModel::SelectCurrent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixModEditDialog::on_forgeBtn_clicked()
|
void OneSixModEditDialog::on_forgeBtn_clicked()
|
||||||
{
|
{
|
||||||
|
// FIXME: use actual model, not reloading. Move logic to model.
|
||||||
|
|
||||||
|
// FIXME: model::isCustom();
|
||||||
if (QDir(m_inst->instanceRoot()).exists("custom.json"))
|
if (QDir(m_inst->instanceRoot()).exists("custom.json"))
|
||||||
{
|
{
|
||||||
if (QMessageBox::question(this, tr("Revert?"), tr("This action will remove your custom.json. Continue?")) != QMessageBox::Yes)
|
if (QMessageBox::question(this, tr("Revert?"),
|
||||||
|
tr("This action will remove your custom.json. Continue?")) !=
|
||||||
|
QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// FIXME: model::revertToBase();
|
||||||
QDir(m_inst->instanceRoot()).remove("custom.json");
|
QDir(m_inst->instanceRoot()).remove("custom.json");
|
||||||
m_inst->reloadVersion(this);
|
reloadInstanceVersion();
|
||||||
}
|
}
|
||||||
VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this);
|
VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this);
|
||||||
vselect.setFilter(1, m_inst->currentVersionId());
|
vselect.setFilter(1, m_inst->currentVersionId());
|
||||||
@ -277,21 +237,25 @@ void OneSixModEditDialog::on_forgeBtn_clicked()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_inst->reloadVersion(this);
|
reloadInstanceVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixModEditDialog::on_liteloaderBtn_clicked()
|
void OneSixModEditDialog::on_liteloaderBtn_clicked()
|
||||||
{
|
{
|
||||||
|
// FIXME: model...
|
||||||
if (QDir(m_inst->instanceRoot()).exists("custom.json"))
|
if (QDir(m_inst->instanceRoot()).exists("custom.json"))
|
||||||
{
|
{
|
||||||
if (QMessageBox::question(this, tr("Revert?"), tr("This action will remove your custom.json. Continue?")) != QMessageBox::Yes)
|
if (QMessageBox::question(this, tr("Revert?"),
|
||||||
|
tr("This action will remove your custom.json. Continue?")) !=
|
||||||
|
QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QDir(m_inst->instanceRoot()).remove("custom.json");
|
QDir(m_inst->instanceRoot()).remove("custom.json");
|
||||||
m_inst->reloadVersion(this);
|
reloadInstanceVersion();
|
||||||
}
|
}
|
||||||
VersionSelectDialog vselect(MMC->liteloaderlist().get(), tr("Select LiteLoader version"), this);
|
VersionSelectDialog vselect(MMC->liteloaderlist().get(), tr("Select LiteLoader version"),
|
||||||
|
this);
|
||||||
vselect.setFilter(1, m_inst->currentVersionId());
|
vselect.setFilter(1, m_inst->currentVersionId());
|
||||||
vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") +
|
vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") +
|
||||||
m_inst->currentVersionId());
|
m_inst->currentVersionId());
|
||||||
@ -310,7 +274,7 @@ void OneSixModEditDialog::on_liteloaderBtn_clicked()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_inst->reloadVersion(this);
|
reloadInstanceVersion();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -347,35 +311,6 @@ bool OneSixModEditDialog::resourcePackListFilter(QKeyEvent *keyEvent)
|
|||||||
return QDialog::eventFilter(ui->resPackTreeView, keyEvent);
|
return QDialog::eventFilter(ui->resPackTreeView, keyEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, int> OneSixModEditDialog::getExistingOrder() const
|
|
||||||
{
|
|
||||||
|
|
||||||
QMap<QString, int> order;
|
|
||||||
// default
|
|
||||||
{
|
|
||||||
for (OneSixVersion::VersionFile file : m_version->versionFiles)
|
|
||||||
{
|
|
||||||
if (file.id.startsWith("org.multimc."))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
order.insert(file.id, file.order);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// overriden
|
|
||||||
{
|
|
||||||
QMap<QString, int> overridenOrder = OneSixVersionBuilder::readOverrideOrders(m_inst);
|
|
||||||
for (auto id : order.keys())
|
|
||||||
{
|
|
||||||
if (overridenOrder.contains(id))
|
|
||||||
{
|
|
||||||
order[id] = overridenOrder[id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return order;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OneSixModEditDialog::eventFilter(QObject *obj, QEvent *ev)
|
bool OneSixModEditDialog::eventFilter(QObject *obj, QEvent *ev)
|
||||||
{
|
{
|
||||||
if (ev->type() != QEvent::KeyPress)
|
if (ev->type() != QEvent::KeyPress)
|
||||||
@ -461,7 +396,8 @@ void OneSixModEditDialog::loaderCurrent(QModelIndex current, QModelIndex previou
|
|||||||
ui->frame->updateWithMod(m);
|
ui->frame->updateWithMod(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixModEditDialog::versionCurrent(const QModelIndex ¤t, const QModelIndex &previous)
|
void OneSixModEditDialog::versionCurrent(const QModelIndex ¤t,
|
||||||
|
const QModelIndex &previous)
|
||||||
{
|
{
|
||||||
if (!current.isValid())
|
if (!current.isValid())
|
||||||
{
|
{
|
||||||
|
@ -57,17 +57,17 @@ protected:
|
|||||||
bool eventFilter(QObject *obj, QEvent *ev);
|
bool eventFilter(QObject *obj, QEvent *ev);
|
||||||
bool loaderListFilter(QKeyEvent *ev);
|
bool loaderListFilter(QKeyEvent *ev);
|
||||||
bool resourcePackListFilter(QKeyEvent *ev);
|
bool resourcePackListFilter(QKeyEvent *ev);
|
||||||
|
/// FIXME: this shouldn't be necessary!
|
||||||
|
bool reloadInstanceVersion();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::OneSixModEditDialog *ui;
|
Ui::OneSixModEditDialog *ui;
|
||||||
std::shared_ptr<OneSixVersion> m_version;
|
std::shared_ptr<VersionFinal> m_version;
|
||||||
std::shared_ptr<ModList> m_mods;
|
std::shared_ptr<ModList> m_mods;
|
||||||
std::shared_ptr<ModList> m_resourcepacks;
|
std::shared_ptr<ModList> m_resourcepacks;
|
||||||
EnabledItemFilter *main_model;
|
EnabledItemFilter *main_model;
|
||||||
OneSixInstance *m_inst;
|
OneSixInstance *m_inst;
|
||||||
|
|
||||||
QMap<QString, int> getExistingOrder() const;
|
|
||||||
|
|
||||||
public
|
public
|
||||||
slots:
|
slots:
|
||||||
void loaderCurrent(QModelIndex current, QModelIndex previous);
|
void loaderCurrent(QModelIndex current, QModelIndex previous);
|
||||||
|
@ -48,24 +48,6 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Main Class:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="mainClassEdit">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -108,13 +90,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="resetLibraryOrderBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Reset order</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line_2">
|
<widget class="Line" name="line_2">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@ -124,6 +99,12 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="moveLibraryUpBtn">
|
<widget class="QPushButton" name="moveLibraryUpBtn">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>This isn't implemented yet.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Move up</string>
|
<string>Move up</string>
|
||||||
</property>
|
</property>
|
||||||
@ -131,11 +112,30 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="moveLibraryDownBtn">
|
<widget class="QPushButton" name="moveLibraryDownBtn">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>This isn't implemented yet.</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Move down</string>
|
<string>Move down</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="resetLibraryOrderBtn">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>This isn't implemented yet.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reset order</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verticalSpacer_7">
|
<spacer name="verticalSpacer_7">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
||||||
#include "OneSixVersion.h"
|
#include "VersionFinal.h"
|
||||||
#include "OneSixLibrary.h"
|
#include "OneSixLibrary.h"
|
||||||
#include "OneSixInstance.h"
|
#include "OneSixInstance.h"
|
||||||
|
|
||||||
|
@ -168,6 +168,11 @@ bool BaseInstance::canLaunch() const
|
|||||||
return !flags().contains(VersionBrokenFlag);
|
return !flags().contains(VersionBrokenFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BaseInstance::reload()
|
||||||
|
{
|
||||||
|
return settings().reload();
|
||||||
|
}
|
||||||
|
|
||||||
QString BaseInstance::baseJar() const
|
QString BaseInstance::baseJar() const
|
||||||
{
|
{
|
||||||
I_D(BaseInstance);
|
I_D(BaseInstance);
|
||||||
|
@ -190,6 +190,8 @@ public:
|
|||||||
|
|
||||||
bool canLaunch() const;
|
bool canLaunch() const;
|
||||||
|
|
||||||
|
virtual bool reload();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/*!
|
/*!
|
||||||
* \brief Signal emitted when properties relevant to the instance view change
|
* \brief Signal emitted when properties relevant to the instance view change
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ForgeInstaller.h"
|
#include "ForgeInstaller.h"
|
||||||
#include "OneSixVersion.h"
|
#include "VersionFinal.h"
|
||||||
#include "OneSixLibrary.h"
|
#include "OneSixLibrary.h"
|
||||||
#include "net/HttpMetaCache.h"
|
#include "net/HttpMetaCache.h"
|
||||||
#include <quazip.h>
|
#include <quazip.h>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
|
ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
|
||||||
{
|
{
|
||||||
std::shared_ptr<OneSixVersion> newVersion;
|
std::shared_ptr<VersionFinal> newVersion;
|
||||||
m_universal_url = universal_url;
|
m_universal_url = universal_url;
|
||||||
|
|
||||||
QuaZip zip(filename);
|
QuaZip zip(filename);
|
||||||
@ -66,7 +66,7 @@ ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
|
|||||||
|
|
||||||
// read the forge version info
|
// read the forge version info
|
||||||
{
|
{
|
||||||
newVersion = OneSixVersion::fromJson(versionInfoVal.toObject());
|
newVersion = VersionFinal::fromJson(versionInfoVal.toObject());
|
||||||
if (!newVersion)
|
if (!newVersion)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class OneSixVersion;
|
class VersionFinal;
|
||||||
|
|
||||||
class ForgeInstaller : public BaseInstaller
|
class ForgeInstaller : public BaseInstaller
|
||||||
{
|
{
|
||||||
@ -33,7 +33,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// the version, read from the installer
|
// the version, read from the installer
|
||||||
std::shared_ptr<OneSixVersion> m_forge_version;
|
std::shared_ptr<VersionFinal> m_forge_version;
|
||||||
QString internalPath;
|
QString internalPath;
|
||||||
QString finalPath;
|
QString finalPath;
|
||||||
QString realVersionId;
|
QString realVersionId;
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#include "logger/QsLog.h"
|
#include "logger/QsLog.h"
|
||||||
|
|
||||||
#include "OneSixVersion.h"
|
#include "VersionFinal.h"
|
||||||
#include "OneSixLibrary.h"
|
#include "OneSixLibrary.h"
|
||||||
#include "OneSixInstance.h"
|
#include "OneSixInstance.h"
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ bool LiteLoaderInstaller::add(OneSixInstance *to)
|
|||||||
obj.insert("+libraries", libraries);
|
obj.insert("+libraries", libraries);
|
||||||
obj.insert("name", QString("LiteLoader"));
|
obj.insert("name", QString("LiteLoader"));
|
||||||
obj.insert("fileId", id());
|
obj.insert("fileId", id());
|
||||||
obj.insert("version", to->intendedVersionId());
|
obj.insert("version", m_version->version);
|
||||||
obj.insert("mcVersion", to->intendedVersionId());
|
obj.insert("mcVersion", to->intendedVersionId());
|
||||||
|
|
||||||
QFile file(filename(to->instanceRoot()));
|
QFile file(filename(to->instanceRoot()));
|
||||||
|
61
logic/MMCJson.cpp
Normal file
61
logic/MMCJson.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "MMCJson.h"
|
||||||
|
#include <QString>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
bool MMCJson::ensureBoolean(const QJsonValue val, const QString what)
|
||||||
|
{
|
||||||
|
if (!val.isBool())
|
||||||
|
throw JSONValidationError(what + " is not boolean");
|
||||||
|
return val.isBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonValue MMCJson::ensureExists(QJsonValue val, const QString what)
|
||||||
|
{
|
||||||
|
if(val.isNull())
|
||||||
|
throw JSONValidationError(what + " does not exist");
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray MMCJson::ensureArray(const QJsonValue val, const QString what)
|
||||||
|
{
|
||||||
|
if (!val.isArray())
|
||||||
|
throw JSONValidationError(what + " is not an array");
|
||||||
|
return val.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
double MMCJson::ensureDouble(const QJsonValue val, const QString what)
|
||||||
|
{
|
||||||
|
if (!val.isDouble())
|
||||||
|
throw JSONValidationError(what + " is not a number");
|
||||||
|
double ret = val.toDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
int MMCJson::ensureInteger(const QJsonValue val, const QString what)
|
||||||
|
{
|
||||||
|
double ret = ensureDouble(val, what);
|
||||||
|
if (fmod(ret, 1) != 0)
|
||||||
|
throw JSONValidationError(what + " is not an integer");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject MMCJson::ensureObject(const QJsonValue val, const QString what)
|
||||||
|
{
|
||||||
|
if (!val.isObject())
|
||||||
|
throw JSONValidationError(what + " is not an object");
|
||||||
|
return val.toObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject MMCJson::ensureObject(const QJsonDocument val, const QString what)
|
||||||
|
{
|
||||||
|
if (!val.isObject())
|
||||||
|
throw JSONValidationError(what + " is not an object");
|
||||||
|
return val.object();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MMCJson::ensureString(const QJsonValue val, const QString what)
|
||||||
|
{
|
||||||
|
if (!val.isString())
|
||||||
|
throw JSONValidationError(what + " is not a string");
|
||||||
|
return val.toString();
|
||||||
|
}
|
||||||
|
|
46
logic/MMCJson.h
Normal file
46
logic/MMCJson.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Some de-bullshitting for Qt JSON failures.
|
||||||
|
*
|
||||||
|
* Simple exception-throwing
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <QJsonValue>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include "MMCError.h"
|
||||||
|
|
||||||
|
class JSONValidationError : public MMCError
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JSONValidationError(QString cause) : MMCError(cause) {};
|
||||||
|
virtual ~JSONValidationError() noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace MMCJson
|
||||||
|
{
|
||||||
|
/// make sure the value exists. throw otherwise.
|
||||||
|
QJsonValue ensureExists(QJsonValue val, const QString what = "value");
|
||||||
|
|
||||||
|
/// make sure the value is converted into an object. throw otherwise.
|
||||||
|
QJsonObject ensureObject(const QJsonValue val, const QString what = "value");
|
||||||
|
|
||||||
|
/// make sure the document is converted into an object. throw otherwise.
|
||||||
|
QJsonObject ensureObject(const QJsonDocument val, const QString what = "value");
|
||||||
|
|
||||||
|
/// make sure the value is converted into an array. throw otherwise.
|
||||||
|
QJsonArray ensureArray(const QJsonValue val, QString what = "value");
|
||||||
|
|
||||||
|
/// make sure the value is converted into a string. throw otherwise.
|
||||||
|
QString ensureString(const QJsonValue val, QString what = "value");
|
||||||
|
|
||||||
|
/// make sure the value is converted into a boolean. throw otherwise.
|
||||||
|
bool ensureBoolean(const QJsonValue val, QString what = "value");
|
||||||
|
|
||||||
|
/// make sure the value is converted into an integer. throw otherwise.
|
||||||
|
int ensureInteger(const QJsonValue val, QString what = "value");
|
||||||
|
|
||||||
|
/// make sure the value is converted into a double precision floating number. throw otherwise.
|
||||||
|
double ensureDouble(const QJsonValue val, QString what = "value");
|
||||||
|
}
|
@ -49,9 +49,11 @@ MinecraftProcess::MinecraftProcess(BaseInstance *inst) : m_instance(inst)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// export some infos
|
// export some infos
|
||||||
env.insert("INST_NAME", inst->name());
|
auto variables = getVariables();
|
||||||
env.insert("INST_ID", inst->id());
|
for (auto it = variables.begin(); it != variables.end(); ++it)
|
||||||
env.insert("INST_DIR", QDir(inst->instanceRoot()).absolutePath());
|
{
|
||||||
|
env.insert(it.key(), it.value());
|
||||||
|
}
|
||||||
|
|
||||||
this->setProcessEnvironment(env);
|
this->setProcessEnvironment(env);
|
||||||
m_prepostlaunchprocess.setProcessEnvironment(env);
|
m_prepostlaunchprocess.setProcessEnvironment(env);
|
||||||
@ -63,10 +65,10 @@ MinecraftProcess::MinecraftProcess(BaseInstance *inst) : m_instance(inst)
|
|||||||
// Log prepost launch command output (can be disabled.)
|
// Log prepost launch command output (can be disabled.)
|
||||||
if (m_instance->settings().get("LogPrePostOutput").toBool())
|
if (m_instance->settings().get("LogPrePostOutput").toBool())
|
||||||
{
|
{
|
||||||
connect(&m_prepostlaunchprocess, &QProcess::readyReadStandardError,
|
connect(&m_prepostlaunchprocess, &QProcess::readyReadStandardError, this,
|
||||||
this, &MinecraftProcess::on_prepost_stdErr);
|
&MinecraftProcess::on_prepost_stdErr);
|
||||||
connect(&m_prepostlaunchprocess, &QProcess::readyReadStandardOutput,
|
connect(&m_prepostlaunchprocess, &QProcess::readyReadStandardOutput, this,
|
||||||
this, &MinecraftProcess::on_prepost_stdOut);
|
&MinecraftProcess::on_prepost_stdOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,10 +81,10 @@ void MinecraftProcess::setWorkdir(QString path)
|
|||||||
|
|
||||||
QString MinecraftProcess::censorPrivateInfo(QString in)
|
QString MinecraftProcess::censorPrivateInfo(QString in)
|
||||||
{
|
{
|
||||||
if(!m_session)
|
if (!m_session)
|
||||||
return in;
|
return in;
|
||||||
|
|
||||||
if(m_session->session != "-")
|
if (m_session->session != "-")
|
||||||
in.replace(m_session->session, "<SESSION ID>");
|
in.replace(m_session->session, "<SESSION ID>");
|
||||||
in.replace(m_session->access_token, "<ACCESS TOKEN>");
|
in.replace(m_session->access_token, "<ACCESS TOKEN>");
|
||||||
in.replace(m_session->client_token, "<CLIENT TOKEN>");
|
in.replace(m_session->client_token, "<CLIENT TOKEN>");
|
||||||
@ -113,7 +115,7 @@ MessageLevel::Enum MinecraftProcess::guessLevel(const QString &line, MessageLeve
|
|||||||
level = MessageLevel::Fatal;
|
level = MessageLevel::Fatal;
|
||||||
if (line.contains("[DEBUG]"))
|
if (line.contains("[DEBUG]"))
|
||||||
level = MessageLevel::Debug;
|
level = MessageLevel::Debug;
|
||||||
if(line.contains("overwriting existing"))
|
if (line.contains("overwriting existing"))
|
||||||
level = MessageLevel::Fatal;
|
level = MessageLevel::Fatal;
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
@ -139,17 +141,15 @@ MessageLevel::Enum MinecraftProcess::getLevel(const QString &levelName)
|
|||||||
return MessageLevel::Message;
|
return MessageLevel::Message;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MinecraftProcess::logOutput(const QStringList &lines,
|
void MinecraftProcess::logOutput(const QStringList &lines, MessageLevel::Enum defaultLevel,
|
||||||
MessageLevel::Enum defaultLevel,
|
|
||||||
bool guessLevel, bool censor)
|
bool guessLevel, bool censor)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < lines.size(); ++i)
|
for (int i = 0; i < lines.size(); ++i)
|
||||||
logOutput(lines[i], defaultLevel, guessLevel, censor);
|
logOutput(lines[i], defaultLevel, guessLevel, censor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MinecraftProcess::logOutput(QString line,
|
void MinecraftProcess::logOutput(QString line, MessageLevel::Enum defaultLevel, bool guessLevel,
|
||||||
MessageLevel::Enum defaultLevel,
|
bool censor)
|
||||||
bool guessLevel, bool censor)
|
|
||||||
{
|
{
|
||||||
MessageLevel::Enum level = defaultLevel;
|
MessageLevel::Enum level = defaultLevel;
|
||||||
|
|
||||||
@ -251,33 +251,7 @@ void MinecraftProcess::finish(int code, ExitStatus status)
|
|||||||
m_prepostlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(code));
|
m_prepostlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(code));
|
||||||
|
|
||||||
// run post-exit
|
// run post-exit
|
||||||
QString postlaunch_cmd = m_instance->settings().get("PostExitCommand").toString();
|
postLaunch();
|
||||||
if (!postlaunch_cmd.isEmpty())
|
|
||||||
{
|
|
||||||
emit log(tr("Running Post-Launch command: %1").arg(postlaunch_cmd));
|
|
||||||
m_prepostlaunchprocess.start(postlaunch_cmd);
|
|
||||||
m_prepostlaunchprocess.waitForFinished();
|
|
||||||
// Flush console window
|
|
||||||
if (!m_err_leftover.isEmpty())
|
|
||||||
{
|
|
||||||
logOutput(m_err_leftover, MessageLevel::PrePost);
|
|
||||||
m_err_leftover.clear();
|
|
||||||
}
|
|
||||||
if (!m_out_leftover.isEmpty())
|
|
||||||
{
|
|
||||||
logOutput(m_out_leftover, MessageLevel::PrePost);
|
|
||||||
m_out_leftover.clear();
|
|
||||||
}
|
|
||||||
if (m_prepostlaunchprocess.exitStatus() != NormalExit)
|
|
||||||
{
|
|
||||||
emit log(tr("Post-Launch command failed with code %1.\n\n").arg(m_prepostlaunchprocess.exitCode()),
|
|
||||||
MessageLevel::Error);
|
|
||||||
emit postlaunch_failed(m_instance, m_prepostlaunchprocess.exitCode(),
|
|
||||||
m_prepostlaunchprocess.exitStatus());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
emit log(tr("Post-Launch command ran successfully.\n\n"));
|
|
||||||
}
|
|
||||||
m_instance->cleanupAfterRun();
|
m_instance->cleanupAfterRun();
|
||||||
emit ended(m_instance, code, status);
|
emit ended(m_instance, code, status);
|
||||||
}
|
}
|
||||||
@ -288,14 +262,12 @@ void MinecraftProcess::killMinecraft()
|
|||||||
kill();
|
kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MinecraftProcess::arm()
|
bool MinecraftProcess::preLaunch()
|
||||||
{
|
{
|
||||||
emit log("MultiMC version: " + MMC->version().toString() + "\n\n");
|
|
||||||
emit log("Minecraft folder is:\n" + workingDirectory() + "\n\n");
|
|
||||||
|
|
||||||
QString prelaunch_cmd = m_instance->settings().get("PreLaunchCommand").toString();
|
QString prelaunch_cmd = m_instance->settings().get("PreLaunchCommand").toString();
|
||||||
if (!prelaunch_cmd.isEmpty())
|
if (!prelaunch_cmd.isEmpty())
|
||||||
{
|
{
|
||||||
|
prelaunch_cmd = substituteVariables(prelaunch_cmd);
|
||||||
// Launch
|
// Launch
|
||||||
emit log(tr("Running Pre-Launch command: %1").arg(prelaunch_cmd));
|
emit log(tr("Running Pre-Launch command: %1").arg(prelaunch_cmd));
|
||||||
m_prepostlaunchprocess.start(prelaunch_cmd);
|
m_prepostlaunchprocess.start(prelaunch_cmd);
|
||||||
@ -315,45 +287,128 @@ void MinecraftProcess::arm()
|
|||||||
// Process return values
|
// Process return values
|
||||||
if (m_prepostlaunchprocess.exitStatus() != NormalExit)
|
if (m_prepostlaunchprocess.exitStatus() != NormalExit)
|
||||||
{
|
{
|
||||||
emit log(tr("Pre-Launch command failed with code %1.\n\n").arg(m_prepostlaunchprocess.exitCode()),
|
emit log(tr("Pre-Launch command failed with code %1.\n\n")
|
||||||
|
.arg(m_prepostlaunchprocess.exitCode()),
|
||||||
MessageLevel::Fatal);
|
MessageLevel::Fatal);
|
||||||
m_instance->cleanupAfterRun();
|
m_instance->cleanupAfterRun();
|
||||||
emit prelaunch_failed(m_instance, m_prepostlaunchprocess.exitCode(),
|
emit prelaunch_failed(m_instance, m_prepostlaunchprocess.exitCode(),
|
||||||
m_prepostlaunchprocess.exitStatus());
|
m_prepostlaunchprocess.exitStatus());
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
emit log(tr("Pre-Launch command ran successfully.\n\n"));
|
emit log(tr("Pre-Launch command ran successfully.\n\n"));
|
||||||
|
|
||||||
|
return m_instance->reload();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool MinecraftProcess::postLaunch()
|
||||||
|
{
|
||||||
|
QString postlaunch_cmd = m_instance->settings().get("PostExitCommand").toString();
|
||||||
|
if (!postlaunch_cmd.isEmpty())
|
||||||
|
{
|
||||||
|
postlaunch_cmd = substituteVariables(postlaunch_cmd);
|
||||||
|
emit log(tr("Running Post-Launch command: %1").arg(postlaunch_cmd));
|
||||||
|
m_prepostlaunchprocess.start(postlaunch_cmd);
|
||||||
|
m_prepostlaunchprocess.waitForFinished();
|
||||||
|
// Flush console window
|
||||||
|
if (!m_err_leftover.isEmpty())
|
||||||
|
{
|
||||||
|
logOutput(m_err_leftover, MessageLevel::PrePost);
|
||||||
|
m_err_leftover.clear();
|
||||||
|
}
|
||||||
|
if (!m_out_leftover.isEmpty())
|
||||||
|
{
|
||||||
|
logOutput(m_out_leftover, MessageLevel::PrePost);
|
||||||
|
m_out_leftover.clear();
|
||||||
|
}
|
||||||
|
if (m_prepostlaunchprocess.exitStatus() != NormalExit)
|
||||||
|
{
|
||||||
|
emit log(tr("Post-Launch command failed with code %1.\n\n")
|
||||||
|
.arg(m_prepostlaunchprocess.exitCode()),
|
||||||
|
MessageLevel::Error);
|
||||||
|
emit postlaunch_failed(m_instance, m_prepostlaunchprocess.exitCode(),
|
||||||
|
m_prepostlaunchprocess.exitStatus());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
emit log(tr("Post-Launch command ran successfully.\n\n"));
|
||||||
|
|
||||||
|
return m_instance->reload();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QString> MinecraftProcess::getVariables() const
|
||||||
|
{
|
||||||
|
QMap<QString, QString> out;
|
||||||
|
out.insert("INST_NAME", m_instance->name());
|
||||||
|
out.insert("INST_ID", m_instance->id());
|
||||||
|
out.insert("INST_DIR", QDir(m_instance->instanceRoot()).absolutePath());
|
||||||
|
out.insert("INST_MC_DIR", QDir(m_instance->minecraftRoot()).absolutePath());
|
||||||
|
out.insert("INST_JAVA", m_instance->settings().get("JavaPath").toString());
|
||||||
|
out.insert("INST_JAVA_ARGS", javaArguments().join(' '));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
QString MinecraftProcess::substituteVariables(const QString &cmd) const
|
||||||
|
{
|
||||||
|
QString out = cmd;
|
||||||
|
auto variables = getVariables();
|
||||||
|
for (auto it = variables.begin(); it != variables.end(); ++it)
|
||||||
|
{
|
||||||
|
out.replace("$" + it.key(), it.value());
|
||||||
|
}
|
||||||
|
auto env = QProcessEnvironment::systemEnvironment();
|
||||||
|
for (auto var : env.keys())
|
||||||
|
{
|
||||||
|
out.replace("$" + var, env.value(var));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList MinecraftProcess::javaArguments() const
|
||||||
|
{
|
||||||
|
QStringList args;
|
||||||
|
|
||||||
|
// custom args go first. we want to override them if we have our own here.
|
||||||
|
args.append(m_instance->extraArguments());
|
||||||
|
|
||||||
|
// OSX dock icon and name
|
||||||
|
#ifdef OSX
|
||||||
|
args << "-Xdock:icon=icon.png";
|
||||||
|
args << QString("-Xdock:name=\"%1\"").arg(m_instance->windowTitle());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// HACK: Stupid hack for Intel drivers. See: https://mojang.atlassian.net/browse/MCL-767
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
args << QString("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_"
|
||||||
|
"minecraft.exe.heapdump");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
args << QString("-Xms%1m").arg(m_instance->settings().get("MinMemAlloc").toInt());
|
||||||
|
args << QString("-Xmx%1m").arg(m_instance->settings().get("MaxMemAlloc").toInt());
|
||||||
|
args << QString("-XX:PermSize=%1m").arg(m_instance->settings().get("PermGen").toInt());
|
||||||
|
args << "-Duser.language=en";
|
||||||
|
if (!m_nativeFolder.isEmpty())
|
||||||
|
args << QString("-Djava.library.path=%1").arg(m_nativeFolder);
|
||||||
|
args << "-jar" << PathCombine(MMC->bin(), "jars", "NewLaunch.jar");
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MinecraftProcess::arm()
|
||||||
|
{
|
||||||
|
emit log("MultiMC version: " + MMC->version().toString() + "\n\n");
|
||||||
|
emit log("Minecraft folder is:\n" + workingDirectory() + "\n\n");
|
||||||
|
|
||||||
|
if (!preLaunch())
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_instance->setLastLaunch();
|
m_instance->setLastLaunch();
|
||||||
auto &settings = m_instance->settings();
|
auto &settings = m_instance->settings();
|
||||||
|
|
||||||
//////////// java arguments ////////////
|
QStringList args = javaArguments();
|
||||||
QStringList args;
|
|
||||||
{
|
|
||||||
// custom args go first. we want to override them if we have our own here.
|
|
||||||
args.append(m_instance->extraArguments());
|
|
||||||
|
|
||||||
// OSX dock icon and name
|
|
||||||
#ifdef OSX
|
|
||||||
args << "-Xdock:icon=icon.png";
|
|
||||||
args << QString("-Xdock:name=\"%1\"").arg(m_instance->windowTitle());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// HACK: Stupid hack for Intel drivers. See: https://mojang.atlassian.net/browse/MCL-767
|
|
||||||
#ifdef Q_OS_WIN32
|
|
||||||
args << QString("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_"
|
|
||||||
"minecraft.exe.heapdump");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
args << QString("-Xms%1m").arg(settings.get("MinMemAlloc").toInt());
|
|
||||||
args << QString("-Xmx%1m").arg(settings.get("MaxMemAlloc").toInt());
|
|
||||||
args << QString("-XX:PermSize=%1m").arg(settings.get("PermGen").toInt());
|
|
||||||
if(!m_nativeFolder.isEmpty())
|
|
||||||
args << QString("-Djava.library.path=%1").arg(m_nativeFolder);
|
|
||||||
args << "-jar" << PathCombine(MMC->bin(), "jars", "NewLaunch.jar");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString JavaPath = m_instance->settings().get("JavaPath").toString();
|
QString JavaPath = m_instance->settings().get("JavaPath").toString();
|
||||||
emit log("Java path is:\n" + JavaPath + "\n\n");
|
emit log("Java path is:\n" + JavaPath + "\n\n");
|
||||||
|
@ -131,6 +131,13 @@ protected:
|
|||||||
QString launchScript;
|
QString launchScript;
|
||||||
QString m_nativeFolder;
|
QString m_nativeFolder;
|
||||||
|
|
||||||
|
bool preLaunch();
|
||||||
|
bool postLaunch();
|
||||||
|
QMap<QString, QString> getVariables() const;
|
||||||
|
QString substituteVariables(const QString &cmd) const;
|
||||||
|
|
||||||
|
QStringList javaArguments() const;
|
||||||
|
|
||||||
protected
|
protected
|
||||||
slots:
|
slots:
|
||||||
void finish(int, QProcess::ExitStatus status);
|
void finish(int, QProcess::ExitStatus status);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "OneSixFTBInstance.h"
|
#include "OneSixFTBInstance.h"
|
||||||
|
|
||||||
#include "OneSixVersion.h"
|
#include "VersionFinal.h"
|
||||||
#include "OneSixLibrary.h"
|
#include "OneSixLibrary.h"
|
||||||
#include "tasks/SequentialTask.h"
|
#include "tasks/SequentialTask.h"
|
||||||
#include "ForgeInstaller.h"
|
#include "ForgeInstaller.h"
|
||||||
@ -10,76 +10,6 @@
|
|||||||
#include "MultiMC.h"
|
#include "MultiMC.h"
|
||||||
#include "pathutils.h"
|
#include "pathutils.h"
|
||||||
|
|
||||||
class OneSixFTBInstanceForge : public Task
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit OneSixFTBInstanceForge(const QString &version, OneSixFTBInstance *inst, QObject *parent = 0) :
|
|
||||||
Task(parent), instance(inst), version("Forge " + version)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void executeTask()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < MMC->forgelist()->count(); ++i)
|
|
||||||
{
|
|
||||||
if (MMC->forgelist()->at(i)->name() == version)
|
|
||||||
{
|
|
||||||
forgeVersion = std::dynamic_pointer_cast<ForgeVersion>(MMC->forgelist()->at(i));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!forgeVersion)
|
|
||||||
{
|
|
||||||
emitFailed(QString("Couldn't find forge version ") + version );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
entry = MMC->metacache()->resolveEntry("minecraftforge", forgeVersion->filename);
|
|
||||||
if (entry->stale)
|
|
||||||
{
|
|
||||||
setStatus(tr("Downloading Forge..."));
|
|
||||||
fjob = new NetJob("Forge download");
|
|
||||||
fjob->addNetAction(CacheDownload::make(forgeVersion->installer_url, entry));
|
|
||||||
connect(fjob, &NetJob::failed, [this](){emitFailed(m_failReason);});
|
|
||||||
connect(fjob, &NetJob::succeeded, this, &OneSixFTBInstanceForge::installForge);
|
|
||||||
connect(fjob, &NetJob::progress, [this](qint64 c, qint64 total){ setProgress(100 * c / total); });
|
|
||||||
fjob->start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
installForge();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
slots:
|
|
||||||
void installForge()
|
|
||||||
{
|
|
||||||
setStatus(tr("Installing Forge..."));
|
|
||||||
QString forgePath = entry->getFullPath();
|
|
||||||
ForgeInstaller forge(forgePath, forgeVersion->universal_url);
|
|
||||||
if (!instance->reloadVersion())
|
|
||||||
{
|
|
||||||
emitFailed(tr("Couldn't load the version config"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto version = instance->getFullVersion();
|
|
||||||
if (!forge.add(instance))
|
|
||||||
{
|
|
||||||
emitFailed(tr("Couldn't install Forge"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
OneSixFTBInstance *instance;
|
|
||||||
QString version;
|
|
||||||
ForgeVersionPtr forgeVersion;
|
|
||||||
MetaEntryPtr entry;
|
|
||||||
NetJob *fjob;
|
|
||||||
};
|
|
||||||
|
|
||||||
OneSixFTBInstance::OneSixFTBInstance(const QString &rootDir, SettingsObject *settings, QObject *parent) :
|
OneSixFTBInstance::OneSixFTBInstance(const QString &rootDir, SettingsObject *settings, QObject *parent) :
|
||||||
OneSixInstance(rootDir, settings, parent)
|
OneSixInstance(rootDir, settings, parent)
|
||||||
{
|
{
|
||||||
@ -87,7 +17,14 @@ OneSixFTBInstance::OneSixFTBInstance(const QString &rootDir, SettingsObject *set
|
|||||||
|
|
||||||
void OneSixFTBInstance::init()
|
void OneSixFTBInstance::init()
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
reloadVersion();
|
reloadVersion();
|
||||||
|
}
|
||||||
|
catch(MMCError & e)
|
||||||
|
{
|
||||||
|
// QLOG_ERROR() << "Caught exception on instance init: " << e.cause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixFTBInstance::copy(const QDir &newDir)
|
void OneSixFTBInstance::copy(const QDir &newDir)
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "OneSixInstance_p.h"
|
#include "OneSixInstance_p.h"
|
||||||
#include "OneSixUpdate.h"
|
#include "OneSixUpdate.h"
|
||||||
#include "OneSixVersion.h"
|
#include "VersionFinal.h"
|
||||||
#include "pathutils.h"
|
#include "pathutils.h"
|
||||||
#include "logger/QsLog.h"
|
#include "logger/QsLog.h"
|
||||||
#include "assets/AssetsUtils.h"
|
#include "assets/AssetsUtils.h"
|
||||||
@ -27,6 +27,7 @@
|
|||||||
#include "icons/IconList.h"
|
#include "icons/IconList.h"
|
||||||
#include "MinecraftProcess.h"
|
#include "MinecraftProcess.h"
|
||||||
#include "gui/dialogs/OneSixModEditDialog.h"
|
#include "gui/dialogs/OneSixModEditDialog.h"
|
||||||
|
#include <MMCError.h>
|
||||||
|
|
||||||
OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *settings, QObject *parent)
|
OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *settings, QObject *parent)
|
||||||
: BaseInstance(new OneSixInstancePrivate(), rootDir, settings, parent)
|
: BaseInstance(new OneSixInstancePrivate(), rootDir, settings, parent)
|
||||||
@ -34,16 +35,24 @@ OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *settings,
|
|||||||
I_D(OneSixInstance);
|
I_D(OneSixInstance);
|
||||||
d->m_settings->registerSetting("IntendedVersion", "");
|
d->m_settings->registerSetting("IntendedVersion", "");
|
||||||
d->m_settings->registerSetting("ShouldUpdate", false);
|
d->m_settings->registerSetting("ShouldUpdate", false);
|
||||||
d->version.reset(new OneSixVersion(this, this));
|
d->version.reset(new VersionFinal(this, this));
|
||||||
d->vanillaVersion.reset(new OneSixVersion(this, this));
|
d->vanillaVersion.reset(new VersionFinal(this, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixInstance::init()
|
void OneSixInstance::init()
|
||||||
{
|
{
|
||||||
|
// FIXME: why is this decided here? what does this even mean?
|
||||||
if (QDir(instanceRoot()).exists("version.json"))
|
if (QDir(instanceRoot()).exists("version.json"))
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
reloadVersion();
|
reloadVersion();
|
||||||
}
|
}
|
||||||
|
catch(MMCError & e)
|
||||||
|
{
|
||||||
|
// QLOG_ERROR() << "Caught exception on instance init: " << e.cause();
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
clearVersion();
|
clearVersion();
|
||||||
@ -79,7 +88,7 @@ QString replaceTokensIn(QString text, QMap<QString, QString> with)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDir OneSixInstance::reconstructAssets(std::shared_ptr<OneSixVersion> version)
|
QDir OneSixInstance::reconstructAssets(std::shared_ptr<VersionFinal> version)
|
||||||
{
|
{
|
||||||
QDir assetsDir = QDir("assets/");
|
QDir assetsDir = QDir("assets/");
|
||||||
QDir indexDir = QDir(PathCombine(assetsDir.path(), "indexes"));
|
QDir indexDir = QDir(PathCombine(assetsDir.path(), "indexes"));
|
||||||
@ -316,25 +325,26 @@ QString OneSixInstance::currentVersionId() const
|
|||||||
return intendedVersionId();
|
return intendedVersionId();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OneSixInstance::reloadVersion(QWidget *widgetParent)
|
void OneSixInstance::reloadVersion()
|
||||||
{
|
{
|
||||||
I_D(OneSixInstance);
|
I_D(OneSixInstance);
|
||||||
|
|
||||||
bool ret = d->version->reload(widgetParent, false, externalPatches());
|
try
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
ret = d->vanillaVersion->reload(widgetParent, true, externalPatches());
|
|
||||||
}
|
|
||||||
if (ret)
|
|
||||||
{
|
{
|
||||||
|
d->version->reload(false, externalPatches());
|
||||||
|
d->vanillaVersion->reload(true, externalPatches());
|
||||||
d->m_flags.remove(VersionBrokenFlag);
|
d->m_flags.remove(VersionBrokenFlag);
|
||||||
emit versionReloaded();
|
emit versionReloaded();
|
||||||
}
|
}
|
||||||
else
|
catch(MMCError & error)
|
||||||
{
|
{
|
||||||
|
d->version->clear();
|
||||||
|
d->vanillaVersion->clear();
|
||||||
d->m_flags.insert(VersionBrokenFlag);
|
d->m_flags.insert(VersionBrokenFlag);
|
||||||
|
//TODO: rethrow to show some error message(s)?
|
||||||
|
emit versionReloaded();
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixInstance::clearVersion()
|
void OneSixInstance::clearVersion()
|
||||||
@ -345,13 +355,13 @@ void OneSixInstance::clearVersion()
|
|||||||
emit versionReloaded();
|
emit versionReloaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<OneSixVersion> OneSixInstance::getFullVersion() const
|
std::shared_ptr<VersionFinal> OneSixInstance::getFullVersion() const
|
||||||
{
|
{
|
||||||
I_D(const OneSixInstance);
|
I_D(const OneSixInstance);
|
||||||
return d->version;
|
return d->version;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<OneSixVersion> OneSixInstance::getVanillaVersion() const
|
std::shared_ptr<VersionFinal> OneSixInstance::getVanillaVersion() const
|
||||||
{
|
{
|
||||||
I_D(const OneSixInstance);
|
I_D(const OneSixInstance);
|
||||||
return d->vanillaVersion;
|
return d->vanillaVersion;
|
||||||
@ -413,6 +423,23 @@ bool OneSixInstance::providesVersionFile() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OneSixInstance::reload()
|
||||||
|
{
|
||||||
|
if(BaseInstance::reload())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
reloadVersion();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QString OneSixInstance::loaderModsDir() const
|
QString OneSixInstance::loaderModsDir() const
|
||||||
{
|
{
|
||||||
return PathCombine(minecraftRoot(), "mods");
|
return PathCombine(minecraftRoot(), "mods");
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
|
|
||||||
#include "OneSixVersion.h"
|
#include "VersionFinal.h"
|
||||||
#include "ModList.h"
|
#include "ModList.h"
|
||||||
|
|
||||||
class OneSixInstance : public BaseInstance
|
class OneSixInstance : public BaseInstance
|
||||||
@ -53,14 +53,18 @@ public:
|
|||||||
|
|
||||||
virtual QDialog *createModEditDialog(QWidget *parent) override;
|
virtual QDialog *createModEditDialog(QWidget *parent) override;
|
||||||
|
|
||||||
/// reload the full version json files. return true on success!
|
/**
|
||||||
bool reloadVersion(QWidget *widgetParent = 0);
|
* reload the full version json files. return true on success!
|
||||||
|
*
|
||||||
|
* throws various exceptions :3
|
||||||
|
*/
|
||||||
|
void reloadVersion();
|
||||||
/// clears all version information in preparation for an update
|
/// clears all version information in preparation for an update
|
||||||
void clearVersion();
|
void clearVersion();
|
||||||
/// get the current full version info
|
/// get the current full version info
|
||||||
std::shared_ptr<OneSixVersion> getFullVersion() const;
|
std::shared_ptr<VersionFinal> getFullVersion() const;
|
||||||
/// gets the current version info, but only for version.json
|
/// gets the current version info, but only for version.json
|
||||||
std::shared_ptr<OneSixVersion> getVanillaVersion() const;
|
std::shared_ptr<VersionFinal> getVanillaVersion() const;
|
||||||
/// is the current version original, or custom?
|
/// is the current version original, or custom?
|
||||||
virtual bool versionIsCustom() override;
|
virtual bool versionIsCustom() override;
|
||||||
|
|
||||||
@ -75,10 +79,12 @@ public:
|
|||||||
virtual QStringList externalPatches() const;
|
virtual QStringList externalPatches() const;
|
||||||
virtual bool providesVersionFile() const;
|
virtual bool providesVersionFile() const;
|
||||||
|
|
||||||
|
bool reload() override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void versionReloaded();
|
void versionReloaded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList processMinecraftArgs(AuthSessionPtr account);
|
QStringList processMinecraftArgs(AuthSessionPtr account);
|
||||||
QDir reconstructAssets(std::shared_ptr<OneSixVersion> version);
|
QDir reconstructAssets(std::shared_ptr<VersionFinal> version);
|
||||||
};
|
};
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "BaseInstance_p.h"
|
#include "BaseInstance_p.h"
|
||||||
#include "OneSixVersion.h"
|
#include "VersionFinal.h"
|
||||||
#include "ModList.h"
|
#include "ModList.h"
|
||||||
|
|
||||||
struct OneSixInstancePrivate : public BaseInstancePrivate
|
struct OneSixInstancePrivate : public BaseInstancePrivate
|
||||||
{
|
{
|
||||||
std::shared_ptr<OneSixVersion> version;
|
std::shared_ptr<VersionFinal> version;
|
||||||
std::shared_ptr<OneSixVersion> vanillaVersion;
|
std::shared_ptr<VersionFinal> vanillaVersion;
|
||||||
std::shared_ptr<ModList> loader_mod_list;
|
std::shared_ptr<ModList> loader_mod_list;
|
||||||
std::shared_ptr<ModList> resource_pack_list;
|
std::shared_ptr<ModList> resource_pack_list;
|
||||||
};
|
};
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
|
|
||||||
class Rule;
|
class Rule;
|
||||||
|
|
||||||
|
class OneSixLibrary;
|
||||||
|
typedef std::shared_ptr<OneSixLibrary> OneSixLibraryPtr;
|
||||||
|
|
||||||
class OneSixLibrary
|
class OneSixLibrary
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "lists/MinecraftVersionList.h"
|
#include "lists/MinecraftVersionList.h"
|
||||||
#include "OneSixVersion.h"
|
#include "VersionFinal.h"
|
||||||
#include "OneSixLibrary.h"
|
#include "OneSixLibrary.h"
|
||||||
#include "OneSixInstance.h"
|
#include "OneSixInstance.h"
|
||||||
#include "net/ForgeMirrors.h"
|
#include "net/ForgeMirrors.h"
|
||||||
@ -48,7 +48,7 @@ void OneSixUpdate::executeTask()
|
|||||||
QDir mcDir(m_inst->minecraftRoot());
|
QDir mcDir(m_inst->minecraftRoot());
|
||||||
if (!mcDir.exists() && !mcDir.mkpath("."))
|
if (!mcDir.exists() && !mcDir.mkpath("."))
|
||||||
{
|
{
|
||||||
emitFailed("Failed to create bin folder.");
|
emitFailed(tr("Failed to create folder for minecraft binaries."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ void OneSixUpdate::executeTask()
|
|||||||
if (targetVersion == nullptr)
|
if (targetVersion == nullptr)
|
||||||
{
|
{
|
||||||
// don't do anything if it was invalid
|
// don't do anything if it was invalid
|
||||||
emitFailed("The specified Minecraft version is invalid. Choose a different one.");
|
emitFailed(tr("The specified Minecraft version is invalid. Choose a different one."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
versionFileStart();
|
versionFileStart();
|
||||||
@ -108,20 +108,19 @@ void OneSixUpdate::versionFileFinished()
|
|||||||
QSaveFile vfile1(version1);
|
QSaveFile vfile1(version1);
|
||||||
if (!vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly))
|
if (!vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly))
|
||||||
{
|
{
|
||||||
emitFailed("Can't open " + version1 + " for writing.");
|
emitFailed(tr("Can't open %1 for writing.").arg(version1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto data = std::dynamic_pointer_cast<ByteArrayDownload>(DlJob)->m_data;
|
auto data = std::dynamic_pointer_cast<ByteArrayDownload>(DlJob)->m_data;
|
||||||
qint64 actual = 0;
|
qint64 actual = 0;
|
||||||
if ((actual = vfile1.write(data)) != data.size())
|
if ((actual = vfile1.write(data)) != data.size())
|
||||||
{
|
{
|
||||||
emitFailed("Failed to write into " + version1 + ". Written " + actual + " out of " +
|
emitFailed(tr("Failed to write into %1. Written %2 out of %3.").arg(version1).arg(actual).arg(data.size()));
|
||||||
data.size() + '.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!vfile1.commit())
|
if (!vfile1.commit())
|
||||||
{
|
{
|
||||||
emitFailed("Can't commit changes to " + version1);
|
emitFailed(tr("Can't commit changes to %1").arg(version1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,21 +135,20 @@ void OneSixUpdate::versionFileFinished()
|
|||||||
{
|
{
|
||||||
finfo.remove();
|
finfo.remove();
|
||||||
}
|
}
|
||||||
inst->reloadVersion();
|
// NOTE: Version is reloaded in jarlibStart
|
||||||
|
|
||||||
jarlibStart();
|
jarlibStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixUpdate::versionFileFailed()
|
void OneSixUpdate::versionFileFailed()
|
||||||
{
|
{
|
||||||
emitFailed("Failed to download the version description. Try again.");
|
emitFailed(tr("Failed to download the version description. Try again."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixUpdate::assetIndexStart()
|
void OneSixUpdate::assetIndexStart()
|
||||||
{
|
{
|
||||||
setStatus(tr("Updating assets index..."));
|
setStatus(tr("Updating assets index..."));
|
||||||
OneSixInstance *inst = (OneSixInstance *)m_inst;
|
OneSixInstance *inst = (OneSixInstance *)m_inst;
|
||||||
std::shared_ptr<OneSixVersion> version = inst->getFullVersion();
|
std::shared_ptr<VersionFinal> version = inst->getFullVersion();
|
||||||
QString assetName = version->assets;
|
QString assetName = version->assets;
|
||||||
QUrl indexUrl = "http://" + URLConstants::AWS_DOWNLOAD_INDEXES + assetName + ".json";
|
QUrl indexUrl = "http://" + URLConstants::AWS_DOWNLOAD_INDEXES + assetName + ".json";
|
||||||
QString localPath = assetName + ".json";
|
QString localPath = assetName + ".json";
|
||||||
@ -174,13 +172,13 @@ void OneSixUpdate::assetIndexFinished()
|
|||||||
AssetsIndex index;
|
AssetsIndex index;
|
||||||
|
|
||||||
OneSixInstance *inst = (OneSixInstance *)m_inst;
|
OneSixInstance *inst = (OneSixInstance *)m_inst;
|
||||||
std::shared_ptr<OneSixVersion> version = inst->getFullVersion();
|
std::shared_ptr<VersionFinal> version = inst->getFullVersion();
|
||||||
QString assetName = version->assets;
|
QString assetName = version->assets;
|
||||||
|
|
||||||
QString asset_fname = "assets/indexes/" + assetName + ".json";
|
QString asset_fname = "assets/indexes/" + assetName + ".json";
|
||||||
if (!AssetsUtils::loadAssetsIndexJson(asset_fname, &index))
|
if (!AssetsUtils::loadAssetsIndexJson(asset_fname, &index))
|
||||||
{
|
{
|
||||||
emitFailed("Failed to read the assets index!");
|
emitFailed(tr("Failed to read the assets index!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Md5EtagDownloadPtr> dls;
|
QList<Md5EtagDownloadPtr> dls;
|
||||||
@ -216,7 +214,7 @@ void OneSixUpdate::assetIndexFinished()
|
|||||||
|
|
||||||
void OneSixUpdate::assetIndexFailed()
|
void OneSixUpdate::assetIndexFailed()
|
||||||
{
|
{
|
||||||
emitFailed("Failed to download the assets index!");
|
emitFailed(tr("Failed to download the assets index!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixUpdate::assetsFinished()
|
void OneSixUpdate::assetsFinished()
|
||||||
@ -226,7 +224,7 @@ void OneSixUpdate::assetsFinished()
|
|||||||
|
|
||||||
void OneSixUpdate::assetsFailed()
|
void OneSixUpdate::assetsFailed()
|
||||||
{
|
{
|
||||||
emitFailed("Failed to download assets!");
|
emitFailed(tr("Failed to download assets!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixUpdate::jarlibStart()
|
void OneSixUpdate::jarlibStart()
|
||||||
@ -234,16 +232,23 @@ void OneSixUpdate::jarlibStart()
|
|||||||
setStatus(tr("Getting the library files from Mojang..."));
|
setStatus(tr("Getting the library files from Mojang..."));
|
||||||
QLOG_INFO() << m_inst->name() << ": downloading libraries";
|
QLOG_INFO() << m_inst->name() << ": downloading libraries";
|
||||||
OneSixInstance *inst = (OneSixInstance *)m_inst;
|
OneSixInstance *inst = (OneSixInstance *)m_inst;
|
||||||
bool successful = inst->reloadVersion();
|
try
|
||||||
if (!successful)
|
|
||||||
{
|
{
|
||||||
emitFailed("Failed to load the version description file. It might be "
|
inst->reloadVersion();
|
||||||
"corrupted, missing or simply too new.");
|
}
|
||||||
|
catch(MMCError & e)
|
||||||
|
{
|
||||||
|
emitFailed(e.cause());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
emitFailed(tr("Failed to load the version description file for reasons unknown."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a list of URLs that will need to be downloaded.
|
// Build a list of URLs that will need to be downloaded.
|
||||||
std::shared_ptr<OneSixVersion> version = inst->getFullVersion();
|
std::shared_ptr<VersionFinal> version = inst->getFullVersion();
|
||||||
// minecraft.jar for this version
|
// minecraft.jar for this version
|
||||||
{
|
{
|
||||||
QString version_id = version->id;
|
QString version_id = version->id;
|
||||||
@ -326,6 +331,5 @@ void OneSixUpdate::jarlibFailed()
|
|||||||
{
|
{
|
||||||
QStringList failed = jarlibDownloadJob->getFailedFiles();
|
QStringList failed = jarlibDownloadJob->getFailedFiles();
|
||||||
QString failed_all = failed.join("\n");
|
QString failed_all = failed.join("\n");
|
||||||
emitFailed("Failed to download the following files:\n" + failed_all +
|
emitFailed(tr("Failed to download the following files:\n%1\n\nPlease try again.").arg(failed_all));
|
||||||
"\n\nPlease try again.");
|
|
||||||
}
|
}
|
||||||
|
@ -1,221 +0,0 @@
|
|||||||
/* 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 "OneSixVersion.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
#include "OneSixVersionBuilder.h"
|
|
||||||
|
|
||||||
OneSixVersion::OneSixVersion(OneSixInstance *instance, QObject *parent)
|
|
||||||
: QAbstractListModel(parent), m_instance(instance)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OneSixVersion::reload(QWidget *widgetParent, const bool onlyVanilla, const QStringList &external)
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
bool ret = OneSixVersionBuilder::build(this, m_instance, widgetParent, onlyVanilla, external);
|
|
||||||
endResetModel();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OneSixVersion::clear()
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
id.clear();
|
|
||||||
time.clear();
|
|
||||||
releaseTime.clear();
|
|
||||||
type.clear();
|
|
||||||
assets.clear();
|
|
||||||
processArguments.clear();
|
|
||||||
minecraftArguments.clear();
|
|
||||||
minimumLauncherVersion = 0xDEADBEAF;
|
|
||||||
mainClass.clear();
|
|
||||||
libraries.clear();
|
|
||||||
tweakers.clear();
|
|
||||||
versionFiles.clear();
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OneSixVersion::dump() const
|
|
||||||
{
|
|
||||||
qDebug().nospace() << "OneSixVersion("
|
|
||||||
<< "\n\tid=" << id
|
|
||||||
<< "\n\ttime=" << time
|
|
||||||
<< "\n\treleaseTime=" << releaseTime
|
|
||||||
<< "\n\ttype=" << type
|
|
||||||
<< "\n\tassets=" << assets
|
|
||||||
<< "\n\tprocessArguments=" << processArguments
|
|
||||||
<< "\n\tminecraftArguments=" << minecraftArguments
|
|
||||||
<< "\n\tminimumLauncherVersion=" << minimumLauncherVersion
|
|
||||||
<< "\n\tmainClass=" << mainClass
|
|
||||||
<< "\n\tlibraries=";
|
|
||||||
for (auto lib : libraries)
|
|
||||||
{
|
|
||||||
qDebug().nospace() << "\n\t\t" << lib.get();
|
|
||||||
}
|
|
||||||
qDebug().nospace() << "\n)";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OneSixVersion::canRemove(const int index) const
|
|
||||||
{
|
|
||||||
if (index < versionFiles.size())
|
|
||||||
{
|
|
||||||
return versionFiles.at(index).id != "org.multimc.version.json";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OneSixVersion::versionFileId(const int index) const
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= versionFiles.size())
|
|
||||||
{
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
return versionFiles.at(index).id;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OneSixVersion::remove(const int index)
|
|
||||||
{
|
|
||||||
if (canRemove(index))
|
|
||||||
{
|
|
||||||
return QFile::remove(versionFiles.at(index).filename);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<std::shared_ptr<OneSixLibrary> > OneSixVersion::getActiveNormalLibs()
|
|
||||||
{
|
|
||||||
QList<std::shared_ptr<OneSixLibrary> > output;
|
|
||||||
for (auto lib : libraries)
|
|
||||||
{
|
|
||||||
if (lib->isActive() && !lib->isNative())
|
|
||||||
{
|
|
||||||
output.append(lib);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<std::shared_ptr<OneSixLibrary> > OneSixVersion::getActiveNativeLibs()
|
|
||||||
{
|
|
||||||
QList<std::shared_ptr<OneSixLibrary> > output;
|
|
||||||
for (auto lib : libraries)
|
|
||||||
{
|
|
||||||
if (lib->isActive() && lib->isNative())
|
|
||||||
{
|
|
||||||
output.append(lib);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<OneSixVersion> OneSixVersion::fromJson(const QJsonObject &obj)
|
|
||||||
{
|
|
||||||
std::shared_ptr<OneSixVersion> version(new OneSixVersion(0));
|
|
||||||
if (OneSixVersionBuilder::read(version.get(), obj))
|
|
||||||
{
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant OneSixVersion::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
int row = index.row();
|
|
||||||
int column = index.column();
|
|
||||||
|
|
||||||
if (row < 0 || row >= versionFiles.size())
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
if (role == Qt::DisplayRole)
|
|
||||||
{
|
|
||||||
switch (column)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return versionFiles.at(row).name;
|
|
||||||
case 1:
|
|
||||||
return versionFiles.at(row).version;
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant OneSixVersion::headerData(int section, Qt::Orientation orientation, int role) const
|
|
||||||
{
|
|
||||||
if (orientation == Qt::Horizontal)
|
|
||||||
{
|
|
||||||
if (role == Qt::DisplayRole)
|
|
||||||
{
|
|
||||||
switch (section)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return tr("Name");
|
|
||||||
case 1:
|
|
||||||
return tr("Version");
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
Qt::ItemFlags OneSixVersion::flags(const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return Qt::NoItemFlags;
|
|
||||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
int OneSixVersion::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
return versionFiles.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
int OneSixVersion::columnCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDebug operator<<(QDebug &dbg, const OneSixVersion *version)
|
|
||||||
{
|
|
||||||
version->dump();
|
|
||||||
return dbg.maybeSpace();
|
|
||||||
}
|
|
||||||
QDebug operator<<(QDebug &dbg, const OneSixLibrary *library)
|
|
||||||
{
|
|
||||||
dbg.nospace() << "OneSixLibrary("
|
|
||||||
<< "\n\t\t\trawName=" << library->rawName()
|
|
||||||
<< "\n\t\t\tname=" << library->name()
|
|
||||||
<< "\n\t\t\tversion=" << library->version()
|
|
||||||
<< "\n\t\t\ttype=" << library->type()
|
|
||||||
<< "\n\t\t\tisActive=" << library->isActive()
|
|
||||||
<< "\n\t\t\tisNative=" << library->isNative()
|
|
||||||
<< "\n\t\t\tdownloadUrl=" << library->downloadUrl()
|
|
||||||
<< "\n\t\t\tstoragePath=" << library->storagePath()
|
|
||||||
<< "\n\t\t\tabsolutePath=" << library->absoluteUrl()
|
|
||||||
<< "\n\t\t\thint=" << library->hint();
|
|
||||||
dbg.nospace() << "\n\t\t)";
|
|
||||||
return dbg.maybeSpace();
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -17,39 +17,32 @@
|
|||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include "VersionFile.h"
|
||||||
|
|
||||||
class OneSixVersion;
|
class VersionFinal;
|
||||||
class OneSixInstance;
|
class OneSixInstance;
|
||||||
class QWidget;
|
|
||||||
class QJsonObject;
|
class QJsonObject;
|
||||||
class QFileInfo;
|
class QFileInfo;
|
||||||
class VersionFile;
|
|
||||||
|
|
||||||
class OneSixVersionBuilder
|
class OneSixVersionBuilder
|
||||||
{
|
{
|
||||||
OneSixVersionBuilder();
|
OneSixVersionBuilder();
|
||||||
public:
|
public:
|
||||||
static bool build(OneSixVersion *version, OneSixInstance *instance, QWidget *widgetParent, const bool onlyVanilla, const QStringList &external);
|
static void build(VersionFinal *version, OneSixInstance *instance, const bool onlyVanilla,
|
||||||
static bool read(OneSixVersion *version, const QJsonObject &obj);
|
const QStringList &external);
|
||||||
|
static void readJsonAndApplyToVersion(VersionFinal *version, const QJsonObject &obj);
|
||||||
|
|
||||||
static QMap<QString, int> readOverrideOrders(OneSixInstance *instance);
|
static QMap<QString, int> readOverrideOrders(OneSixInstance *instance);
|
||||||
static bool writeOverrideOrders(const QMap<QString, int> &order, OneSixInstance *instance);
|
static bool writeOverrideOrders(const QMap<QString, int> &order, OneSixInstance *instance);
|
||||||
|
|
||||||
enum ParseFlag
|
|
||||||
{
|
|
||||||
NoFlags = 0x0,
|
|
||||||
IsFTBPackJson = 0x1
|
|
||||||
};
|
|
||||||
Q_DECLARE_FLAGS(ParseFlags, ParseFlag)
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OneSixVersion *m_version;
|
VersionFinal *m_version;
|
||||||
OneSixInstance *m_instance;
|
OneSixInstance *m_instance;
|
||||||
QWidget *m_widgetParent;
|
|
||||||
|
|
||||||
bool build(const bool onlyVanilla, const QStringList &external);
|
void buildInternal(const bool onlyVanilla, const QStringList &external);
|
||||||
bool read(const QJsonObject &obj);
|
void readJsonAndApply(const QJsonObject &obj);
|
||||||
|
void finalizeVersion();
|
||||||
|
|
||||||
bool read(const QFileInfo &fileInfo, const bool requireOrder, VersionFile *out, const ParseFlags flags = NoFlags);
|
VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder,
|
||||||
|
bool isFTB = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(OneSixVersionBuilder::ParseFlags)
|
|
||||||
|
535
logic/VersionFile.cpp
Normal file
535
logic/VersionFile.cpp
Normal file
@ -0,0 +1,535 @@
|
|||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
|
#include <modutils.h>
|
||||||
|
|
||||||
|
#include "logger/QsLog.h"
|
||||||
|
#include "logic/VersionFile.h"
|
||||||
|
#include "logic/OneSixLibrary.h"
|
||||||
|
#include "logic/VersionFinal.h"
|
||||||
|
#include "MMCJson.h"
|
||||||
|
|
||||||
|
using namespace MMCJson;
|
||||||
|
|
||||||
|
#define CURRENT_MINIMUM_LAUNCHER_VERSION 14
|
||||||
|
|
||||||
|
RawLibraryPtr RawLibrary::fromJson(const QJsonObject &libObj, const QString &filename)
|
||||||
|
{
|
||||||
|
RawLibraryPtr out(new RawLibrary());
|
||||||
|
if (!libObj.contains("name"))
|
||||||
|
{
|
||||||
|
throw JSONValidationError(filename +
|
||||||
|
"contains a library that doesn't have a 'name' field");
|
||||||
|
}
|
||||||
|
out->name = libObj.value("name").toString();
|
||||||
|
|
||||||
|
auto readString = [libObj, filename](const QString & key, QString & variable)
|
||||||
|
{
|
||||||
|
if (libObj.contains(key))
|
||||||
|
{
|
||||||
|
QJsonValue val = libObj.value(key);
|
||||||
|
if (!val.isString())
|
||||||
|
{
|
||||||
|
QLOG_WARN() << key << "is not a string in" << filename << "(skipping)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
variable = val.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
readString("url", out->url);
|
||||||
|
readString("MMC-hint", out->hint);
|
||||||
|
readString("MMC-absulute_url", out->absoluteUrl);
|
||||||
|
readString("MMC-absoluteUrl", out->absoluteUrl);
|
||||||
|
if (libObj.contains("extract"))
|
||||||
|
{
|
||||||
|
out->applyExcludes = true;
|
||||||
|
auto extractObj = ensureObject(libObj.value("extract"));
|
||||||
|
for (auto excludeVal : ensureArray(extractObj.value("exclude")))
|
||||||
|
{
|
||||||
|
out->excludes.append(ensureString(excludeVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (libObj.contains("natives"))
|
||||||
|
{
|
||||||
|
out->applyNatives = true;
|
||||||
|
QJsonObject nativesObj = ensureObject(libObj.value("natives"));
|
||||||
|
for (auto it = nativesObj.begin(); it != nativesObj.end(); ++it)
|
||||||
|
{
|
||||||
|
if (!it.value().isString())
|
||||||
|
{
|
||||||
|
QLOG_WARN() << filename << "contains an invalid native (skipping)";
|
||||||
|
}
|
||||||
|
OpSys opSys = OpSys_fromString(it.key());
|
||||||
|
if (opSys != Os_Other)
|
||||||
|
{
|
||||||
|
out->natives.append(qMakePair(opSys, it.value().toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (libObj.contains("rules"))
|
||||||
|
{
|
||||||
|
out->applyRules = true;
|
||||||
|
out->rules = rulesFromJsonV4(libObj);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &filename,
|
||||||
|
const bool requireOrder, const bool isFTB)
|
||||||
|
{
|
||||||
|
VersionFilePtr out(new VersionFile());
|
||||||
|
if (doc.isEmpty() || doc.isNull())
|
||||||
|
{
|
||||||
|
throw JSONValidationError(filename + " is empty or null");
|
||||||
|
}
|
||||||
|
if (!doc.isObject())
|
||||||
|
{
|
||||||
|
throw JSONValidationError("The root of " + filename + " is not an object");
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject root = doc.object();
|
||||||
|
|
||||||
|
if (requireOrder)
|
||||||
|
{
|
||||||
|
if (root.contains("order"))
|
||||||
|
{
|
||||||
|
out->order = ensureInteger(root.value("order"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FIXME: evaluate if we don't want to throw exceptions here instead
|
||||||
|
QLOG_ERROR() << filename << "doesn't contain an order field";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out->name = root.value("name").toString();
|
||||||
|
out->fileId = root.value("fileId").toString();
|
||||||
|
out->version = root.value("version").toString();
|
||||||
|
out->mcVersion = root.value("mcVersion").toString();
|
||||||
|
out->filename = filename;
|
||||||
|
|
||||||
|
auto readString = [root, filename](const QString & key, QString & variable)
|
||||||
|
{
|
||||||
|
if (root.contains(key))
|
||||||
|
{
|
||||||
|
variable = ensureString(root.value(key));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: This should be ignored when applying.
|
||||||
|
if (!isFTB)
|
||||||
|
{
|
||||||
|
readString("id", out->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
readString("mainClass", out->mainClass);
|
||||||
|
readString("processArguments", out->processArguments);
|
||||||
|
readString("minecraftArguments", out->overwriteMinecraftArguments);
|
||||||
|
readString("+minecraftArguments", out->addMinecraftArguments);
|
||||||
|
readString("-minecraftArguments", out->removeMinecraftArguments);
|
||||||
|
readString("type", out->type);
|
||||||
|
readString("releaseTime", out->releaseTime);
|
||||||
|
readString("time", out->time);
|
||||||
|
readString("assets", out->assets);
|
||||||
|
|
||||||
|
if (root.contains("minimumLauncherVersion"))
|
||||||
|
{
|
||||||
|
out->minimumLauncherVersion = ensureInteger(root.value("minimumLauncherVersion"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.contains("tweakers"))
|
||||||
|
{
|
||||||
|
out->shouldOverwriteTweakers = true;
|
||||||
|
for (auto tweakerVal : ensureArray(root.value("tweakers")))
|
||||||
|
{
|
||||||
|
out->overwriteTweakers.append(ensureString(tweakerVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.contains("+tweakers"))
|
||||||
|
{
|
||||||
|
for (auto tweakerVal : ensureArray(root.value("+tweakers")))
|
||||||
|
{
|
||||||
|
out->addTweakers.append(ensureString(tweakerVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.contains("-tweakers"))
|
||||||
|
{
|
||||||
|
for (auto tweakerVal : ensureArray(root.value("-tweakers")))
|
||||||
|
{
|
||||||
|
out->removeTweakers.append(ensureString(tweakerVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.contains("libraries"))
|
||||||
|
{
|
||||||
|
// FIXME: This should be done when applying.
|
||||||
|
out->shouldOverwriteLibs = !isFTB;
|
||||||
|
for (auto libVal : ensureArray(root.value("libraries")))
|
||||||
|
{
|
||||||
|
auto libObj = ensureObject(libVal);
|
||||||
|
|
||||||
|
auto lib = RawLibrary::fromJson(libObj, filename);
|
||||||
|
// FIXME: This should be done when applying.
|
||||||
|
if (isFTB)
|
||||||
|
{
|
||||||
|
lib->hint = "local";
|
||||||
|
lib->insertType = RawLibrary::Prepend;
|
||||||
|
out->addLibs.prepend(lib);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->overwriteLibs.append(lib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.contains("+libraries"))
|
||||||
|
{
|
||||||
|
for (auto libVal : ensureArray(root.value("+libraries")))
|
||||||
|
{
|
||||||
|
QJsonObject libObj = ensureObject(libVal);
|
||||||
|
QJsonValue insertVal = ensureExists(libObj.value("insert"));
|
||||||
|
|
||||||
|
// parse the library
|
||||||
|
auto lib = RawLibrary::fromJson(libObj, filename);
|
||||||
|
|
||||||
|
// TODO: utility functions for handling this case. templates?
|
||||||
|
QString insertString;
|
||||||
|
{
|
||||||
|
if (insertVal.isString())
|
||||||
|
{
|
||||||
|
insertString = insertVal.toString();
|
||||||
|
}
|
||||||
|
else if (insertVal.isObject())
|
||||||
|
{
|
||||||
|
QJsonObject insertObj = insertVal.toObject();
|
||||||
|
if (insertObj.isEmpty())
|
||||||
|
{
|
||||||
|
throw JSONValidationError("One library has an empty insert object in " +
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
insertString = insertObj.keys().first();
|
||||||
|
lib->insertData = insertObj.value(insertString).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (insertString == "apply")
|
||||||
|
{
|
||||||
|
lib->insertType = RawLibrary::Apply;
|
||||||
|
}
|
||||||
|
else if (insertString == "prepend")
|
||||||
|
{
|
||||||
|
lib->insertType = RawLibrary::Prepend;
|
||||||
|
}
|
||||||
|
else if (insertString == "append")
|
||||||
|
{
|
||||||
|
lib->insertType = RawLibrary::Prepend;
|
||||||
|
}
|
||||||
|
else if (insertString == "replace")
|
||||||
|
{
|
||||||
|
lib->insertType = RawLibrary::Replace;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw JSONValidationError("A '+' library in " + filename +
|
||||||
|
" contains an invalid insert type");
|
||||||
|
}
|
||||||
|
if (libObj.contains("MMC-depend"))
|
||||||
|
{
|
||||||
|
const QString dependString = ensureString(libObj.value("MMC-depend"));
|
||||||
|
if (dependString == "hard")
|
||||||
|
{
|
||||||
|
lib->dependType = RawLibrary::Hard;
|
||||||
|
}
|
||||||
|
else if (dependString == "soft")
|
||||||
|
{
|
||||||
|
lib->dependType = RawLibrary::Soft;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw JSONValidationError("A '+' library in " + filename +
|
||||||
|
" contains an invalid depend type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out->addLibs.append(lib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (root.contains("-libraries"))
|
||||||
|
{
|
||||||
|
for (auto libVal : ensureArray(root.value("-libraries")))
|
||||||
|
{
|
||||||
|
auto libObj = ensureObject(libVal);
|
||||||
|
out->removeLibs.append(ensureString(libObj.value("name")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
OneSixLibraryPtr VersionFile::createLibrary(RawLibraryPtr lib)
|
||||||
|
{
|
||||||
|
std::shared_ptr<OneSixLibrary> out(new OneSixLibrary(lib->name));
|
||||||
|
if (!lib->url.isEmpty())
|
||||||
|
{
|
||||||
|
out->setBaseUrl(lib->url);
|
||||||
|
}
|
||||||
|
out->setHint(lib->hint);
|
||||||
|
if (!lib->absoluteUrl.isEmpty())
|
||||||
|
{
|
||||||
|
out->setAbsoluteUrl(lib->absoluteUrl);
|
||||||
|
}
|
||||||
|
out->setAbsoluteUrl(lib->absoluteUrl);
|
||||||
|
out->extract_excludes = lib->excludes;
|
||||||
|
for (auto native : lib->natives)
|
||||||
|
{
|
||||||
|
out->addNative(native.first, native.second);
|
||||||
|
}
|
||||||
|
out->setRules(lib->rules);
|
||||||
|
out->finalize();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VersionFile::findLibrary(QList<OneSixLibraryPtr> haystack, const QString &needle)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < haystack.size(); ++i)
|
||||||
|
{
|
||||||
|
if (QRegExp(needle, Qt::CaseSensitive, QRegExp::WildcardUnix)
|
||||||
|
.indexIn(haystack.at(i)->rawName()) != -1)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionFile::applyTo(VersionFinal *version)
|
||||||
|
{
|
||||||
|
if (minimumLauncherVersion != -1)
|
||||||
|
{
|
||||||
|
if (minimumLauncherVersion > CURRENT_MINIMUM_LAUNCHER_VERSION)
|
||||||
|
{
|
||||||
|
throw LauncherVersionError(minimumLauncherVersion, CURRENT_MINIMUM_LAUNCHER_VERSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!version->id.isNull() && !mcVersion.isNull())
|
||||||
|
{
|
||||||
|
if (QRegExp(mcVersion, Qt::CaseInsensitive, QRegExp::Wildcard).indexIn(version->id) ==
|
||||||
|
-1)
|
||||||
|
{
|
||||||
|
throw MinecraftVersionMismatch(fileId, mcVersion, version->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!id.isNull())
|
||||||
|
{
|
||||||
|
version->id = id;
|
||||||
|
}
|
||||||
|
if (!mainClass.isNull())
|
||||||
|
{
|
||||||
|
version->mainClass = mainClass;
|
||||||
|
}
|
||||||
|
if (!processArguments.isNull())
|
||||||
|
{
|
||||||
|
version->processArguments = processArguments;
|
||||||
|
}
|
||||||
|
if (!type.isNull())
|
||||||
|
{
|
||||||
|
version->type = type;
|
||||||
|
}
|
||||||
|
if (!releaseTime.isNull())
|
||||||
|
{
|
||||||
|
version->releaseTime = releaseTime;
|
||||||
|
}
|
||||||
|
if (!time.isNull())
|
||||||
|
{
|
||||||
|
version->time = time;
|
||||||
|
}
|
||||||
|
if (!assets.isNull())
|
||||||
|
{
|
||||||
|
version->assets = assets;
|
||||||
|
}
|
||||||
|
if (minimumLauncherVersion >= 0)
|
||||||
|
{
|
||||||
|
version->minimumLauncherVersion = minimumLauncherVersion;
|
||||||
|
}
|
||||||
|
if (!overwriteMinecraftArguments.isNull())
|
||||||
|
{
|
||||||
|
version->minecraftArguments = overwriteMinecraftArguments;
|
||||||
|
}
|
||||||
|
if (!addMinecraftArguments.isNull())
|
||||||
|
{
|
||||||
|
version->minecraftArguments += addMinecraftArguments;
|
||||||
|
}
|
||||||
|
if (!removeMinecraftArguments.isNull())
|
||||||
|
{
|
||||||
|
version->minecraftArguments.remove(removeMinecraftArguments);
|
||||||
|
}
|
||||||
|
if (shouldOverwriteTweakers)
|
||||||
|
{
|
||||||
|
version->tweakers = overwriteTweakers;
|
||||||
|
}
|
||||||
|
for (auto tweaker : addTweakers)
|
||||||
|
{
|
||||||
|
version->tweakers += tweaker;
|
||||||
|
}
|
||||||
|
for (auto tweaker : removeTweakers)
|
||||||
|
{
|
||||||
|
version->tweakers.removeAll(tweaker);
|
||||||
|
}
|
||||||
|
if (shouldOverwriteLibs)
|
||||||
|
{
|
||||||
|
version->libraries.clear();
|
||||||
|
for (auto lib : overwriteLibs)
|
||||||
|
{
|
||||||
|
version->libraries.append(createLibrary(lib));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto lib : addLibs)
|
||||||
|
{
|
||||||
|
switch (lib->insertType)
|
||||||
|
{
|
||||||
|
case RawLibrary::Apply:
|
||||||
|
{
|
||||||
|
|
||||||
|
int index = findLibrary(version->libraries, lib->name);
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
auto library = version->libraries[index];
|
||||||
|
if (!lib->url.isNull())
|
||||||
|
{
|
||||||
|
library->setBaseUrl(lib->url);
|
||||||
|
}
|
||||||
|
if (!lib->hint.isNull())
|
||||||
|
{
|
||||||
|
library->setHint(lib->hint);
|
||||||
|
}
|
||||||
|
if (!lib->absoluteUrl.isNull())
|
||||||
|
{
|
||||||
|
library->setAbsoluteUrl(lib->absoluteUrl);
|
||||||
|
}
|
||||||
|
if (lib->applyExcludes)
|
||||||
|
{
|
||||||
|
library->extract_excludes = lib->excludes;
|
||||||
|
}
|
||||||
|
if (lib->applyNatives)
|
||||||
|
{
|
||||||
|
library->clearSuffixes();
|
||||||
|
for (auto native : lib->natives)
|
||||||
|
{
|
||||||
|
library->addNative(native.first, native.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lib->applyRules)
|
||||||
|
{
|
||||||
|
library->setRules(lib->rules);
|
||||||
|
}
|
||||||
|
library->finalize();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QLOG_WARN() << "Couldn't find" << lib->name << "(skipping)";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RawLibrary::Append:
|
||||||
|
case RawLibrary::Prepend:
|
||||||
|
{
|
||||||
|
|
||||||
|
const int startOfVersion = lib->name.lastIndexOf(':') + 1;
|
||||||
|
const int index = findLibrary(
|
||||||
|
version->libraries, QString(lib->name).replace(startOfVersion, INT_MAX, '*'));
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
if (lib->insertType == RawLibrary::Append)
|
||||||
|
{
|
||||||
|
version->libraries.append(createLibrary(lib));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
version->libraries.prepend(createLibrary(lib));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto otherLib = version->libraries.at(index);
|
||||||
|
const Util::Version ourVersion = lib->name.mid(startOfVersion, INT_MAX);
|
||||||
|
const Util::Version otherVersion = otherLib->version();
|
||||||
|
// if the existing version is a hard dependency we can either use it or
|
||||||
|
// fail, but we can't change it
|
||||||
|
if (otherLib->dependType == OneSixLibrary::Hard)
|
||||||
|
{
|
||||||
|
// we need a higher version, or we're hard to and the versions aren't
|
||||||
|
// equal
|
||||||
|
if (ourVersion > otherVersion ||
|
||||||
|
(lib->dependType == RawLibrary::Hard && ourVersion != otherVersion))
|
||||||
|
{
|
||||||
|
throw VersionBuildError(
|
||||||
|
QObject::tr(
|
||||||
|
"Error resolving library dependencies between %1 and %2 in %3.")
|
||||||
|
.arg(otherLib->rawName(), lib->name, filename));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the library is already existing, so we don't have to do anything
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (otherLib->dependType == OneSixLibrary::Soft)
|
||||||
|
{
|
||||||
|
// if we are higher it means we should update
|
||||||
|
if (ourVersion > otherVersion)
|
||||||
|
{
|
||||||
|
auto library = createLibrary(lib);
|
||||||
|
if (Util::Version(otherLib->minVersion) < ourVersion)
|
||||||
|
{
|
||||||
|
library->minVersion = ourVersion.toString();
|
||||||
|
}
|
||||||
|
version->libraries.replace(index, library);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// our version is smaller than the existing version, but we require
|
||||||
|
// it: fail
|
||||||
|
if (lib->dependType == RawLibrary::Hard)
|
||||||
|
{
|
||||||
|
throw VersionBuildError(QObject::tr(
|
||||||
|
"Error resolving library dependencies between %1 and %2 in %3.")
|
||||||
|
.arg(otherLib->rawName(), lib->name,
|
||||||
|
filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RawLibrary::Replace:
|
||||||
|
{
|
||||||
|
int index = findLibrary(version->libraries, lib->insertData);
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
version->libraries.replace(index, createLibrary(lib));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QLOG_WARN() << "Couldn't find" << lib->insertData << "(skipping)";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto lib : removeLibs)
|
||||||
|
{
|
||||||
|
int index = findLibrary(version->libraries, lib);
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
version->libraries.removeAt(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QLOG_WARN() << "Couldn't find" << lib << "(skipping)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
127
logic/VersionFile.h
Normal file
127
logic/VersionFile.h
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <memory>
|
||||||
|
#include "logic/OpSys.h"
|
||||||
|
#include "logic/OneSixRule.h"
|
||||||
|
#include "MMCError.h"
|
||||||
|
|
||||||
|
class VersionFinal;
|
||||||
|
|
||||||
|
class VersionBuildError : public MMCError
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VersionBuildError(QString cause) : MMCError(cause) {};
|
||||||
|
virtual ~VersionBuildError() noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the base version file was meant for a newer version of the vanilla launcher than we support
|
||||||
|
*/
|
||||||
|
class LauncherVersionError : public VersionBuildError
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LauncherVersionError(int actual, int supported)
|
||||||
|
: VersionBuildError(QObject::tr(
|
||||||
|
"The base version file of this instance was meant for a newer (%1) "
|
||||||
|
"version of the vanilla launcher than this version of MultiMC supports (%2).")
|
||||||
|
.arg(actual)
|
||||||
|
.arg(supported)) {};
|
||||||
|
virtual ~LauncherVersionError() noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* some patch was intended for a different version of minecraft
|
||||||
|
*/
|
||||||
|
class MinecraftVersionMismatch : public VersionBuildError
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MinecraftVersionMismatch(QString fileId, QString mcVersion, QString parentMcVersion)
|
||||||
|
: VersionBuildError(QObject::tr("The patch %1 is for a different version of Minecraft "
|
||||||
|
"(%2) than that of the instance (%3).")
|
||||||
|
.arg(fileId)
|
||||||
|
.arg(mcVersion)
|
||||||
|
.arg(parentMcVersion)) {};
|
||||||
|
virtual ~MinecraftVersionMismatch() noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RawLibrary;
|
||||||
|
typedef std::shared_ptr<RawLibrary> RawLibraryPtr;
|
||||||
|
struct RawLibrary
|
||||||
|
{
|
||||||
|
QString name;
|
||||||
|
QString url;
|
||||||
|
QString hint;
|
||||||
|
QString absoluteUrl;
|
||||||
|
bool applyExcludes = false;
|
||||||
|
QStringList excludes;
|
||||||
|
bool applyNatives = false;
|
||||||
|
QList<QPair<OpSys, QString>> natives;
|
||||||
|
bool applyRules = false;
|
||||||
|
QList<std::shared_ptr<Rule>> rules;
|
||||||
|
|
||||||
|
// user for '+' libraries
|
||||||
|
enum InsertType
|
||||||
|
{
|
||||||
|
Apply,
|
||||||
|
Append,
|
||||||
|
Prepend,
|
||||||
|
Replace
|
||||||
|
};
|
||||||
|
InsertType insertType = Append;
|
||||||
|
QString insertData;
|
||||||
|
enum DependType
|
||||||
|
{
|
||||||
|
Soft,
|
||||||
|
Hard
|
||||||
|
};
|
||||||
|
DependType dependType = Soft;
|
||||||
|
|
||||||
|
static RawLibraryPtr fromJson(const QJsonObject &libObj, const QString &filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VersionFile;
|
||||||
|
typedef std::shared_ptr<VersionFile> VersionFilePtr;
|
||||||
|
struct VersionFile
|
||||||
|
{
|
||||||
|
public: /* methods */
|
||||||
|
static VersionFilePtr fromJson(const QJsonDocument &doc, const QString &filename,
|
||||||
|
const bool requireOrder, const bool isFTB = false);
|
||||||
|
|
||||||
|
static OneSixLibraryPtr createLibrary(RawLibraryPtr lib);
|
||||||
|
int findLibrary(QList<OneSixLibraryPtr> haystack, const QString &needle);
|
||||||
|
void applyTo(VersionFinal *version);
|
||||||
|
|
||||||
|
public: /* data */
|
||||||
|
int order = 0;
|
||||||
|
QString name;
|
||||||
|
QString fileId;
|
||||||
|
QString version;
|
||||||
|
// TODO use the mcVersion to determine if a version file should be removed on update
|
||||||
|
QString mcVersion;
|
||||||
|
QString filename;
|
||||||
|
// TODO requirements
|
||||||
|
// QMap<QString, QString> requirements;
|
||||||
|
QString id;
|
||||||
|
QString mainClass;
|
||||||
|
QString overwriteMinecraftArguments;
|
||||||
|
QString addMinecraftArguments;
|
||||||
|
QString removeMinecraftArguments;
|
||||||
|
QString processArguments;
|
||||||
|
QString type;
|
||||||
|
QString releaseTime;
|
||||||
|
QString time;
|
||||||
|
QString assets;
|
||||||
|
int minimumLauncherVersion = -1;
|
||||||
|
|
||||||
|
bool shouldOverwriteTweakers = false;
|
||||||
|
QStringList overwriteTweakers;
|
||||||
|
QStringList addTweakers;
|
||||||
|
QStringList removeTweakers;
|
||||||
|
|
||||||
|
bool shouldOverwriteLibs = false;
|
||||||
|
QList<RawLibraryPtr> overwriteLibs;
|
||||||
|
QList<RawLibraryPtr> addLibs;
|
||||||
|
QList<QString> removeLibs;
|
||||||
|
};
|
183
logic/VersionFinal.cpp
Normal file
183
logic/VersionFinal.cpp
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/* 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 "VersionFinal.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
#include "OneSixVersionBuilder.h"
|
||||||
|
|
||||||
|
VersionFinal::VersionFinal(OneSixInstance *instance, QObject *parent)
|
||||||
|
: QAbstractListModel(parent), m_instance(instance)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VersionFinal::reload(const bool onlyVanilla, const QStringList &external)
|
||||||
|
{
|
||||||
|
//FIXME: source of epic failure.
|
||||||
|
beginResetModel();
|
||||||
|
OneSixVersionBuilder::build(this, m_instance, onlyVanilla, external);
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionFinal::clear()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
id.clear();
|
||||||
|
time.clear();
|
||||||
|
releaseTime.clear();
|
||||||
|
type.clear();
|
||||||
|
assets.clear();
|
||||||
|
processArguments.clear();
|
||||||
|
minecraftArguments.clear();
|
||||||
|
minimumLauncherVersion = 0xDEADBEAF;
|
||||||
|
mainClass.clear();
|
||||||
|
libraries.clear();
|
||||||
|
tweakers.clear();
|
||||||
|
versionFiles.clear();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VersionFinal::canRemove(const int index) const
|
||||||
|
{
|
||||||
|
if (index < versionFiles.size())
|
||||||
|
{
|
||||||
|
return versionFiles.at(index)->fileId != "org.multimc.version.json";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VersionFinal::versionFileId(const int index) const
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= versionFiles.size())
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return versionFiles.at(index)->fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VersionFinal::remove(const int index)
|
||||||
|
{
|
||||||
|
if (canRemove(index))
|
||||||
|
{
|
||||||
|
return QFile::remove(versionFiles.at(index)->filename);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<std::shared_ptr<OneSixLibrary> > VersionFinal::getActiveNormalLibs()
|
||||||
|
{
|
||||||
|
QList<std::shared_ptr<OneSixLibrary> > output;
|
||||||
|
for (auto lib : libraries)
|
||||||
|
{
|
||||||
|
if (lib->isActive() && !lib->isNative())
|
||||||
|
{
|
||||||
|
output.append(lib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<std::shared_ptr<OneSixLibrary> > VersionFinal::getActiveNativeLibs()
|
||||||
|
{
|
||||||
|
QList<std::shared_ptr<OneSixLibrary> > output;
|
||||||
|
for (auto lib : libraries)
|
||||||
|
{
|
||||||
|
if (lib->isActive() && lib->isNative())
|
||||||
|
{
|
||||||
|
output.append(lib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<VersionFinal> VersionFinal::fromJson(const QJsonObject &obj)
|
||||||
|
{
|
||||||
|
std::shared_ptr<VersionFinal> version(new VersionFinal(0));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OneSixVersionBuilder::readJsonAndApplyToVersion(version.get(), obj);
|
||||||
|
}
|
||||||
|
catch(MMCError & err)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant VersionFinal::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
int row = index.row();
|
||||||
|
int column = index.column();
|
||||||
|
|
||||||
|
if (row < 0 || row >= versionFiles.size())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole)
|
||||||
|
{
|
||||||
|
switch (column)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return versionFiles.at(row)->name;
|
||||||
|
case 1:
|
||||||
|
return versionFiles.at(row)->version;
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant VersionFinal::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (orientation == Qt::Horizontal)
|
||||||
|
{
|
||||||
|
if (role == Qt::DisplayRole)
|
||||||
|
{
|
||||||
|
switch (section)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return tr("Name");
|
||||||
|
case 1:
|
||||||
|
return tr("Version");
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags VersionFinal::flags(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VersionFinal::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return versionFiles.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int VersionFinal::columnCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
@ -22,14 +22,15 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "OneSixLibrary.h"
|
#include "OneSixLibrary.h"
|
||||||
|
#include "VersionFile.h"
|
||||||
|
|
||||||
class OneSixInstance;
|
class OneSixInstance;
|
||||||
|
|
||||||
class OneSixVersion : public QAbstractListModel
|
class VersionFinal : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit OneSixVersion(OneSixInstance *instance, QObject *parent = 0);
|
explicit VersionFinal(OneSixInstance *instance, QObject *parent = 0);
|
||||||
|
|
||||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||||
@ -37,7 +38,7 @@ public:
|
|||||||
virtual int columnCount(const QModelIndex &parent) const;
|
virtual int columnCount(const QModelIndex &parent) const;
|
||||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||||
|
|
||||||
bool reload(QWidget *widgetParent, const bool onlyVanilla = false, const QStringList &external = QStringList());
|
bool reload(const bool onlyVanilla = false, const QStringList &external = QStringList());
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
void dump() const;
|
void dump() const;
|
||||||
@ -54,7 +55,7 @@ public:
|
|||||||
QList<std::shared_ptr<OneSixLibrary>> getActiveNormalLibs();
|
QList<std::shared_ptr<OneSixLibrary>> getActiveNormalLibs();
|
||||||
QList<std::shared_ptr<OneSixLibrary>> getActiveNativeLibs();
|
QList<std::shared_ptr<OneSixLibrary>> getActiveNativeLibs();
|
||||||
|
|
||||||
static std::shared_ptr<OneSixVersion> fromJson(const QJsonObject &obj);
|
static std::shared_ptr<VersionFinal> fromJson(const QJsonObject &obj);
|
||||||
|
|
||||||
// data members
|
// data members
|
||||||
public:
|
public:
|
||||||
@ -118,20 +119,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
// QList<Rule> rules;
|
// QList<Rule> rules;
|
||||||
|
|
||||||
struct VersionFile
|
QList<VersionFilePtr> versionFiles;
|
||||||
{
|
|
||||||
QString name;
|
|
||||||
QString id;
|
|
||||||
QString version;
|
|
||||||
QString mcVersion;
|
|
||||||
QString filename;
|
|
||||||
int order;
|
|
||||||
};
|
|
||||||
QList<VersionFile> versionFiles;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OneSixInstance *m_instance;
|
OneSixInstance *m_instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
QDebug operator<<(QDebug &dbg, const OneSixVersion *version);
|
|
||||||
QDebug operator<<(QDebug &dbg, const OneSixLibrary *library);
|
|
@ -92,7 +92,6 @@ void LiteLoaderVersionList::updateListData(QList<BaseVersionPtr> versions)
|
|||||||
LLListLoadTask::LLListLoadTask(LiteLoaderVersionList *vlist)
|
LLListLoadTask::LLListLoadTask(LiteLoaderVersionList *vlist)
|
||||||
{
|
{
|
||||||
m_list = vlist;
|
m_list = vlist;
|
||||||
vlistReply = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLListLoadTask::~LLListLoadTask()
|
LLListLoadTask::~LLListLoadTask()
|
||||||
@ -102,23 +101,49 @@ LLListLoadTask::~LLListLoadTask()
|
|||||||
void LLListLoadTask::executeTask()
|
void LLListLoadTask::executeTask()
|
||||||
{
|
{
|
||||||
setStatus(tr("Loading LiteLoader version list..."));
|
setStatus(tr("Loading LiteLoader version list..."));
|
||||||
auto worker = MMC->qnam();
|
auto job = new NetJob("Version index");
|
||||||
vlistReply = worker->get(QNetworkRequest(QUrl(URLConstants::LITELOADER_URL)));
|
// we do not care if the version is stale or not.
|
||||||
connect(vlistReply, SIGNAL(finished()), this, SLOT(listDownloaded()));
|
auto liteloaderEntry = MMC->metacache()->resolveEntry("liteloader", "versions.json");
|
||||||
|
|
||||||
|
// verify by poking the server.
|
||||||
|
liteloaderEntry->stale = true;
|
||||||
|
|
||||||
|
job->addNetAction(listDownload = CacheDownload::make(QUrl(URLConstants::LITELOADER_URL),
|
||||||
|
liteloaderEntry));
|
||||||
|
|
||||||
|
connect(listDownload.get(), SIGNAL(failed(int)), SLOT(listFailed()));
|
||||||
|
|
||||||
|
listJob.reset(job);
|
||||||
|
connect(listJob.get(), SIGNAL(succeeded()), SLOT(listDownloaded()));
|
||||||
|
connect(listJob.get(), SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64)));
|
||||||
|
listJob->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLListLoadTask::listFailed()
|
||||||
|
{
|
||||||
|
emitFailed("Failed to load LiteLoader version list.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLListLoadTask::listDownloaded()
|
void LLListLoadTask::listDownloaded()
|
||||||
{
|
{
|
||||||
if (vlistReply->error() != QNetworkReply::NoError)
|
QByteArray data;
|
||||||
{
|
{
|
||||||
vlistReply->deleteLater();
|
auto dlJob = listDownload;
|
||||||
emitFailed("Failed to load LiteLoader version list" + vlistReply->errorString());
|
auto filename = std::dynamic_pointer_cast<CacheDownload>(dlJob)->getTargetFilepath();
|
||||||
|
QFile listFile(filename);
|
||||||
|
if (!listFile.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
emitFailed("Failed to open the LiteLoader version list.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
data = listFile.readAll();
|
||||||
|
listFile.close();
|
||||||
|
dlJob.reset();
|
||||||
|
}
|
||||||
|
|
||||||
QJsonParseError jsonError;
|
QJsonParseError jsonError;
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(vlistReply->readAll(), &jsonError);
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
||||||
vlistReply->deleteLater();
|
|
||||||
|
|
||||||
if (jsonError.error != QJsonParseError::NoError)
|
if (jsonError.error != QJsonParseError::NoError)
|
||||||
{
|
{
|
||||||
@ -140,7 +165,12 @@ void LLListLoadTask::listDownloaded()
|
|||||||
emitFailed("Error parsing version list JSON: missing 'versions' object");
|
emitFailed("Error parsing version list JSON: missing 'versions' object");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const QJsonObject versions = root.value("versions").toObject();
|
|
||||||
|
auto meta = root.value("meta").toObject();
|
||||||
|
QString description = meta.value("description").toString(tr("This is a lightweight loader for mods that don't change game mechanics."));
|
||||||
|
QString defaultUrl = meta.value("url").toString("http://dl.liteloader.com");
|
||||||
|
QString authors = meta.value("authors").toString("Mumfrey");
|
||||||
|
auto versions = root.value("versions").toObject();
|
||||||
|
|
||||||
QList<BaseVersionPtr> tempList;
|
QList<BaseVersionPtr> tempList;
|
||||||
for (auto vIt = versions.begin(); vIt != versions.end(); ++vIt)
|
for (auto vIt = versions.begin(); vIt != versions.end(); ++vIt)
|
||||||
@ -170,6 +200,9 @@ void LLListLoadTask::listDownloaded()
|
|||||||
version->md5 = artefact.value("md5").toString();
|
version->md5 = artefact.value("md5").toString();
|
||||||
version->timestamp = artefact.value("timestamp").toDouble();
|
version->timestamp = artefact.value("timestamp").toDouble();
|
||||||
version->tweakClass = artefact.value("tweakClass").toString();
|
version->tweakClass = artefact.value("tweakClass").toString();
|
||||||
|
version->authors = authors;
|
||||||
|
version->description = description;
|
||||||
|
version->defaultUrl = defaultUrl;
|
||||||
const QJsonArray libs = artefact.value("libraries").toArray();
|
const QJsonArray libs = artefact.value("libraries").toArray();
|
||||||
for (auto lIt = libs.begin(); lIt != libs.end(); ++lIt)
|
for (auto lIt = libs.begin(); lIt != libs.end(); ++lIt)
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "BaseVersionList.h"
|
#include "BaseVersionList.h"
|
||||||
#include "logic/tasks/Task.h"
|
#include "logic/tasks/Task.h"
|
||||||
#include "logic/BaseVersion.h"
|
#include "logic/BaseVersion.h"
|
||||||
|
#include <logic/net/NetJob.h>
|
||||||
|
|
||||||
class LLListLoadTask;
|
class LLListLoadTask;
|
||||||
class QNetworkReply;
|
class QNetworkReply;
|
||||||
@ -46,6 +47,7 @@ public:
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// important info
|
||||||
QString version;
|
QString version;
|
||||||
QString file;
|
QString file;
|
||||||
QString mcVersion;
|
QString mcVersion;
|
||||||
@ -54,6 +56,11 @@ public:
|
|||||||
bool isLatest;
|
bool isLatest;
|
||||||
QString tweakClass;
|
QString tweakClass;
|
||||||
QStringList libraries;
|
QStringList libraries;
|
||||||
|
|
||||||
|
// meta
|
||||||
|
QString defaultUrl;
|
||||||
|
QString description;
|
||||||
|
QString authors;
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr<LiteLoaderVersion> LiteLoaderVersionPtr;
|
typedef std::shared_ptr<LiteLoaderVersion> LiteLoaderVersionPtr;
|
||||||
|
|
||||||
@ -96,8 +103,10 @@ public:
|
|||||||
protected
|
protected
|
||||||
slots:
|
slots:
|
||||||
void listDownloaded();
|
void listDownloaded();
|
||||||
|
void listFailed();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QNetworkReply *vlistReply;
|
NetJobPtr listJob;
|
||||||
|
CacheDownloadPtr listDownload;
|
||||||
LiteLoaderVersionList *m_list;
|
LiteLoaderVersionList *m_list;
|
||||||
};
|
};
|
||||||
|
@ -25,7 +25,7 @@ void PasteUpload::executeTask()
|
|||||||
|
|
||||||
m_reply = std::shared_ptr<QNetworkReply>(rep);
|
m_reply = std::shared_ptr<QNetworkReply>(rep);
|
||||||
connect(rep, &QNetworkReply::downloadProgress, [&](qint64 value, qint64 max)
|
connect(rep, &QNetworkReply::downloadProgress, [&](qint64 value, qint64 max)
|
||||||
{ setProgress(value / max * 100); });
|
{ setProgress(value / qMax((qint64)1, max) * 100); });
|
||||||
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this,
|
connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this,
|
||||||
SLOT(downloadError(QNetworkReply::NetworkError)));
|
SLOT(downloadError(QNetworkReply::NetworkError)));
|
||||||
connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished()));
|
connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished()));
|
||||||
@ -52,10 +52,9 @@ void PasteUpload::downloadFinished()
|
|||||||
emitFailed(jsonError.errorString());
|
emitFailed(jsonError.errorString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QString error;
|
if (!parseResult(doc))
|
||||||
if (!parseResult(doc, &error))
|
|
||||||
{
|
{
|
||||||
emitFailed(error);
|
emitFailed(tr("paste.ee returned an error. Please consult the logs for more information"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,13 +68,13 @@ void PasteUpload::downloadFinished()
|
|||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PasteUpload::parseResult(QJsonDocument doc, QString *parseError)
|
bool PasteUpload::parseResult(QJsonDocument doc)
|
||||||
{
|
{
|
||||||
auto object = doc.object();
|
auto object = doc.object();
|
||||||
auto status = object.value("status").toString("error");
|
auto status = object.value("status").toString("error");
|
||||||
if (status == "error")
|
if (status == "error")
|
||||||
{
|
{
|
||||||
parseError = new QString(object.value("error").toString());
|
QLOG_ERROR() << "paste.ee reported error:" << QString(object.value("error").toString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// FIXME: not the place for GUI things.
|
// FIXME: not the place for GUI things.
|
||||||
|
@ -14,7 +14,7 @@ protected:
|
|||||||
virtual void executeTask();
|
virtual void executeTask();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool parseResult(QJsonDocument doc, QString *parseError);
|
bool parseResult(QJsonDocument doc);
|
||||||
QString m_text;
|
QString m_text;
|
||||||
QString m_error;
|
QString m_error;
|
||||||
QWidget *m_window;
|
QWidget *m_window;
|
||||||
|
20
translations/CMakeLists.txt
Normal file
20
translations/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM 1)
|
||||||
|
|
||||||
|
### translation stuff
|
||||||
|
|
||||||
|
file(GLOB TRANSLATION_FILES ${CMAKE_CURRENT_LIST_DIR}/*.ts)
|
||||||
|
set(FILES_TO_TRANSLATE_ABSOLUTE)
|
||||||
|
foreach(file ${FILES_TO_TRANSLATE})
|
||||||
|
list(APPEND FILES_TO_TRANSLATE_ABSOLUTE "${CMAKE_SOURCE_DIR}/${file}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
qt5_create_translation(TRANSLATION_MESSAGES ${FILES_TO_TRANSLATE_ABSOLUTE} ${TRANSLATION_FILES})
|
||||||
|
qt5_add_translation(TRANSLATION_QM ${TRANSLATION_FILES})
|
||||||
|
add_custom_target(translations_update DEPENDS ${TRANSLATION_MESSAGES})
|
||||||
|
add_custom_target(translations DEPENDS ${TRANSLATION_QM})
|
||||||
|
|
||||||
|
IF(APPLE AND UNIX) ## OSX
|
||||||
|
install(FILES ${TRANSLATION_QM} DESTINATION MultiMC.app/Contents/MacOS/translations)
|
||||||
|
ELSE()
|
||||||
|
install(FILES ${TRANSLATION_QM} DESTINATION translations)
|
||||||
|
ENDIF()
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user