Merge branch 'feature_derpstances' of https://github.com/02JanDal/MultiMC5 into feature_derpstances
Conflicts: gui/dialogs/OneSixModEditDialog.cpp logic/OneSixUpdate.cpp
This commit is contained in:
commit
1936bd181f
@ -411,10 +411,7 @@ logic/LegacyUpdate.cpp
|
||||
logic/LegacyForge.h
|
||||
logic/LegacyForge.cpp
|
||||
|
||||
# 1.6 instances
|
||||
logic/OneSixInstance.h
|
||||
logic/OneSixInstance.cpp
|
||||
logic/OneSixInstance_p.h
|
||||
# OneSix instances
|
||||
logic/OneSixUpdate.h
|
||||
logic/OneSixUpdate.cpp
|
||||
logic/OneSixVersion.h
|
||||
@ -425,10 +422,17 @@ logic/OneSixRule.h
|
||||
logic/OneSixRule.cpp
|
||||
logic/OpSys.h
|
||||
logic/OpSys.cpp
|
||||
logic/BaseInstaller.h
|
||||
logic/BaseInstaller.cpp
|
||||
logic/ForgeInstaller.h
|
||||
logic/ForgeInstaller.cpp
|
||||
logic/LiteLoaderInstaller.h
|
||||
logic/LiteLoaderInstaller.cpp
|
||||
logic/OneSixInstance.h
|
||||
logic/OneSixInstance.cpp
|
||||
logic/OneSixInstance_p.h
|
||||
logic/OneSixVersionBuilder.h
|
||||
logic/OneSixVersionBuilder.cpp
|
||||
|
||||
# Nostalgia
|
||||
logic/NostalgiaInstance.h
|
||||
|
@ -55,7 +55,8 @@ OneSixModEditDialog::OneSixModEditDialog(OneSixInstance *inst, QWidget *parent)
|
||||
main_model->setSourceModel(m_version.get());
|
||||
ui->libraryTreeView->setModel(main_model);
|
||||
ui->libraryTreeView->installEventFilter(this);
|
||||
ui->mainClassEdit->setText(m_version->mainClass);
|
||||
connect(ui->libraryTreeView->selectionModel(), &QItemSelectionModel::currentChanged,
|
||||
this, &OneSixModEditDialog::versionCurrent);
|
||||
updateVersionControls();
|
||||
}
|
||||
else
|
||||
@ -81,6 +82,8 @@ OneSixModEditDialog::OneSixModEditDialog(OneSixInstance *inst, QWidget *parent)
|
||||
ui->resPackTreeView->installEventFilter(this);
|
||||
m_resourcepacks->startWatching();
|
||||
}
|
||||
|
||||
connect(m_inst, &OneSixInstance::versionReloaded, this, &OneSixModEditDialog::updateVersionControls);
|
||||
}
|
||||
|
||||
OneSixModEditDialog::~OneSixModEditDialog()
|
||||
@ -92,98 +95,76 @@ OneSixModEditDialog::~OneSixModEditDialog()
|
||||
|
||||
void OneSixModEditDialog::updateVersionControls()
|
||||
{
|
||||
bool customVersion = m_inst->versionIsCustom();
|
||||
ui->customizeBtn->setEnabled(!customVersion);
|
||||
ui->revertBtn->setEnabled(customVersion);
|
||||
ui->forgeBtn->setEnabled(true);
|
||||
ui->liteloaderBtn->setEnabled(LiteLoaderInstaller(m_inst->intendedVersionId()).canApply());
|
||||
ui->customEditorBtn->setEnabled(customVersion);
|
||||
ui->liteloaderBtn->setEnabled(LiteLoaderInstaller().canApply(m_inst));
|
||||
ui->mainClassEdit->setText(m_version->mainClass);
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::disableVersionControls()
|
||||
{
|
||||
ui->customizeBtn->setEnabled(false);
|
||||
ui->revertBtn->setEnabled(false);
|
||||
ui->forgeBtn->setEnabled(false);
|
||||
ui->liteloaderBtn->setEnabled(false);
|
||||
ui->customEditorBtn->setEnabled(false);
|
||||
ui->reloadLibrariesBtn->setEnabled(false);
|
||||
ui->removeLibraryBtn->setEnabled(false);
|
||||
ui->mainClassEdit->setText("");
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_customizeBtn_clicked()
|
||||
void OneSixModEditDialog::on_userEditorBtn_clicked()
|
||||
{
|
||||
if (m_inst->customizeVersion())
|
||||
QDir root(m_inst->instanceRoot());
|
||||
if (!root.exists("user.json"))
|
||||
{
|
||||
m_version = m_inst->getFullVersion();
|
||||
main_model->setSourceModel(m_version.get());
|
||||
updateVersionControls();
|
||||
QFile file(root.absoluteFilePath("user.json"));
|
||||
if (!file.open(QFile::WriteOnly))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't write a skeletion user.json file: %1").arg(file.errorString()));
|
||||
return;
|
||||
}
|
||||
file.write("{\n}");
|
||||
file.close();
|
||||
}
|
||||
if (!MMC->openJsonEditor(root.absoluteFilePath("user.json")))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error"), tr("Unable to open user.json, check the settings"));
|
||||
}
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_revertBtn_clicked()
|
||||
void OneSixModEditDialog::on_reloadLibrariesBtn_clicked()
|
||||
{
|
||||
auto response = CustomMessageBox::selectable(
|
||||
this, tr("Revert?"), tr("Do you want to revert the "
|
||||
"version of this instance to its original configuration?"),
|
||||
QMessageBox::Question, QMessageBox::Yes | QMessageBox::No)->exec();
|
||||
if (response == QMessageBox::Yes)
|
||||
{
|
||||
if (m_inst->revertCustomVersion())
|
||||
{
|
||||
m_version = m_inst->getFullVersion();
|
||||
main_model->setSourceModel(m_version.get());
|
||||
updateVersionControls();
|
||||
}
|
||||
}
|
||||
m_inst->reloadVersion(this);
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_customEditorBtn_clicked()
|
||||
void OneSixModEditDialog::on_removeLibraryBtn_clicked()
|
||||
{
|
||||
if (m_inst->versionIsCustom())
|
||||
if (ui->libraryTreeView->currentIndex().isValid())
|
||||
{
|
||||
if (!MMC->openJsonEditor(m_inst->instanceRoot() + "/custom.json"))
|
||||
if (!m_version->remove(ui->libraryTreeView->currentIndex().row()))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Error"),
|
||||
tr("Unable to open custom.json, check the settings"));
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_inst->reloadVersion(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_forgeBtn_clicked()
|
||||
{
|
||||
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)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QDir(m_inst->instanceRoot()).remove("custom.json");
|
||||
}
|
||||
VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this);
|
||||
vselect.setFilter(1, m_inst->currentVersionId());
|
||||
vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") +
|
||||
m_inst->currentVersionId());
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
if (m_inst->versionIsCustom())
|
||||
{
|
||||
auto reply = QMessageBox::question(
|
||||
this, tr("Revert?"),
|
||||
tr("This will revert any "
|
||||
"changes you did to the version up to this point. Is that "
|
||||
"OK?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (reply == QMessageBox::Yes)
|
||||
{
|
||||
m_inst->revertCustomVersion();
|
||||
m_inst->customizeVersion();
|
||||
{
|
||||
m_version = m_inst->getFullVersion();
|
||||
main_model->setSourceModel(m_version.get());
|
||||
updateVersionControls();
|
||||
}
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_inst->customizeVersion();
|
||||
m_version = m_inst->getFullVersion();
|
||||
main_model->setSourceModel(m_version.get());
|
||||
updateVersionControls();
|
||||
}
|
||||
ForgeVersionPtr forgeVersion =
|
||||
std::dynamic_pointer_cast<ForgeVersion>(vselect.selectedVersion());
|
||||
if (!forgeVersion)
|
||||
@ -200,9 +181,9 @@ void OneSixModEditDialog::on_forgeBtn_clicked()
|
||||
// install
|
||||
QString forgePath = entry->getFullPath();
|
||||
ForgeInstaller forge(forgePath, forgeVersion->universal_url);
|
||||
if (!forge.apply(m_version))
|
||||
if (!forge.add(m_inst))
|
||||
{
|
||||
// failure notice
|
||||
QLOG_ERROR() << "Failure installing forge";
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -215,18 +196,27 @@ void OneSixModEditDialog::on_forgeBtn_clicked()
|
||||
// install
|
||||
QString forgePath = entry->getFullPath();
|
||||
ForgeInstaller forge(forgePath, forgeVersion->universal_url);
|
||||
if (!forge.apply(m_version))
|
||||
if (!forge.add(m_inst))
|
||||
{
|
||||
// failure notice
|
||||
QLOG_ERROR() << "Failure installing forge";
|
||||
}
|
||||
}
|
||||
}
|
||||
m_inst->reloadVersion(this);
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_liteloaderBtn_clicked()
|
||||
{
|
||||
LiteLoaderInstaller liteloader(m_inst->intendedVersionId());
|
||||
if (!liteloader.canApply())
|
||||
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)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QDir(m_inst->instanceRoot()).remove("custom.json");
|
||||
}
|
||||
LiteLoaderInstaller liteloader;
|
||||
if (!liteloader.canApply(m_inst))
|
||||
{
|
||||
QMessageBox::critical(
|
||||
this, tr("LiteLoader"),
|
||||
@ -234,19 +224,16 @@ void OneSixModEditDialog::on_liteloaderBtn_clicked()
|
||||
"into this version of Minecraft"));
|
||||
return;
|
||||
}
|
||||
if (!m_inst->versionIsCustom())
|
||||
{
|
||||
m_inst->customizeVersion();
|
||||
m_version = m_inst->getFullVersion();
|
||||
main_model->setSourceModel(m_version.get());
|
||||
updateVersionControls();
|
||||
}
|
||||
if (!liteloader.apply(m_version))
|
||||
if (!liteloader.add(m_inst))
|
||||
{
|
||||
QMessageBox::critical(this, tr("LiteLoader"),
|
||||
tr("For reasons unknown, the LiteLoader installation failed. "
|
||||
"Check your MultiMC log files for details."));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_inst->reloadVersion(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool OneSixModEditDialog::loaderListFilter(QKeyEvent *keyEvent)
|
||||
@ -365,3 +352,15 @@ void OneSixModEditDialog::loaderCurrent(QModelIndex current, QModelIndex previou
|
||||
Mod &m = m_mods->operator[](row);
|
||||
ui->frame->updateWithMod(m);
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::versionCurrent(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->removeLibraryBtn->setDisabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->removeLibraryBtn->setEnabled(m_version->canRemove(current.row()));
|
||||
}
|
||||
}
|
||||
|
@ -45,9 +45,9 @@ slots:
|
||||
void on_buttonBox_rejected();
|
||||
void on_forgeBtn_clicked();
|
||||
void on_liteloaderBtn_clicked();
|
||||
void on_customizeBtn_clicked();
|
||||
void on_revertBtn_clicked();
|
||||
void on_customEditorBtn_clicked();
|
||||
void on_userEditorBtn_clicked();
|
||||
void on_reloadLibrariesBtn_clicked();
|
||||
void on_removeLibraryBtn_clicked();
|
||||
void updateVersionControls();
|
||||
void disableVersionControls();
|
||||
|
||||
@ -66,4 +66,5 @@ private:
|
||||
public
|
||||
slots:
|
||||
void loaderCurrent(QModelIndex current, QModelIndex previous);
|
||||
void versionCurrent(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
};
|
||||
|
@ -26,7 +26,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="libTab">
|
||||
<attribute name="title">
|
||||
@ -43,6 +43,9 @@
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@ -84,62 +87,24 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="customizeBtn">
|
||||
<property name="toolTip">
|
||||
<string>Create an customized copy of the base version</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Customize</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="revertBtn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Revert to original base version</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Revert</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addLibraryBtn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Add new libraries</string>
|
||||
</property>
|
||||
<widget class="QPushButton" name="reloadLibrariesBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
<string>Reload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeLibraryBtn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Remove selected libraries</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -151,9 +116,9 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="customEditorBtn">
|
||||
<widget class="QPushButton" name="userEditorBtn">
|
||||
<property name="text">
|
||||
<string>Open custom.json</string>
|
||||
<string>Open user.json</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
66
logic/BaseInstaller.cpp
Normal file
66
logic/BaseInstaller.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/* 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 "BaseInstaller.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#include "OneSixVersion.h"
|
||||
#include "OneSixLibrary.h"
|
||||
#include "OneSixInstance.h"
|
||||
|
||||
#include "cmdutils.h"
|
||||
|
||||
BaseInstaller::BaseInstaller()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool BaseInstaller::isApplied(OneSixInstance *on)
|
||||
{
|
||||
return QFile::exists(filename(on->instanceRoot()));
|
||||
}
|
||||
|
||||
bool BaseInstaller::add(OneSixInstance *to)
|
||||
{
|
||||
if (!patchesDir(to->instanceRoot()).exists())
|
||||
{
|
||||
QDir(to->instanceRoot()).mkdir("patches");
|
||||
}
|
||||
|
||||
if (isApplied(to))
|
||||
{
|
||||
if (!remove(to))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseInstaller::remove(OneSixInstance *from)
|
||||
{
|
||||
return QFile::remove(filename(from->instanceRoot()));
|
||||
}
|
||||
|
||||
QString BaseInstaller::filename(const QString &root) const
|
||||
{
|
||||
return patchesDir(root).absoluteFilePath(id() + ".json");
|
||||
}
|
||||
QDir BaseInstaller::patchesDir(const QString &root) const
|
||||
{
|
||||
return QDir(root + "/patches/");
|
||||
}
|
39
logic/BaseInstaller.h
Normal file
39
logic/BaseInstaller.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
class OneSixInstance;
|
||||
class QDir;
|
||||
class QString;
|
||||
|
||||
class BaseInstaller
|
||||
{
|
||||
public:
|
||||
BaseInstaller();
|
||||
|
||||
virtual bool canApply(OneSixInstance *instance) const { return true; }
|
||||
bool isApplied(OneSixInstance *on);
|
||||
|
||||
virtual bool add(OneSixInstance *to);
|
||||
virtual bool remove(OneSixInstance *from);
|
||||
|
||||
protected:
|
||||
virtual QString id() const = 0;
|
||||
QString filename(const QString &root) const;
|
||||
QDir patchesDir(const QString &root) const;
|
||||
};
|
@ -21,7 +21,15 @@
|
||||
#include <quazipfile.h>
|
||||
#include <pathutils.h>
|
||||
#include <QStringList>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
#include "MultiMC.h"
|
||||
#include "OneSixInstance.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QSaveFile>
|
||||
#include <QCryptographicHash>
|
||||
|
||||
ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
|
||||
{
|
||||
@ -66,6 +74,7 @@ ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
|
||||
QJsonObject installObj = installVal.toObject();
|
||||
QString libraryName = installObj.value("path").toString();
|
||||
internalPath = installObj.value("filePath").toString();
|
||||
m_forgeVersionString = installObj.value("version").toString().remove("Forge").trimmed();
|
||||
|
||||
// where do we put the library? decode the mojang path
|
||||
OneSixLibrary lib(libraryName);
|
||||
@ -103,13 +112,22 @@ ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
|
||||
realVersionId = m_forge_version->id = installObj.value("minecraft").toString();
|
||||
}
|
||||
|
||||
bool ForgeInstaller::apply(std::shared_ptr<OneSixVersion> to)
|
||||
bool ForgeInstaller::add(OneSixInstance *to)
|
||||
{
|
||||
if (!BaseInstaller::add(to))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject obj;
|
||||
obj.insert("order", 5);
|
||||
|
||||
if (!m_forge_version)
|
||||
return false;
|
||||
to->externalUpdateStart();
|
||||
int sliding_insert_window = 0;
|
||||
{
|
||||
QJsonArray librariesPlus;
|
||||
|
||||
// for each library in the version we are adding (except for the blacklisted)
|
||||
QSet<QString> blacklist{"lwjgl", "lwjgl_util", "lwjgl-platform"};
|
||||
for (auto lib : m_forge_version->libraries)
|
||||
@ -128,28 +146,79 @@ bool ForgeInstaller::apply(std::shared_ptr<OneSixVersion> to)
|
||||
if (blacklist.contains(libName))
|
||||
continue;
|
||||
|
||||
// find an entry that matches this one
|
||||
QJsonObject libObj = lib->toJson();
|
||||
|
||||
bool found = false;
|
||||
for (auto tolib : to->libraries)
|
||||
bool equals = false;
|
||||
// find an entry that matches this one
|
||||
for (auto tolib : to->getNonCustomVersion()->libraries)
|
||||
{
|
||||
if (tolib->name() != libName)
|
||||
continue;
|
||||
found = true;
|
||||
if (tolib->toJson() == libObj)
|
||||
{
|
||||
equals = true;
|
||||
}
|
||||
// replace lib
|
||||
tolib = lib;
|
||||
libObj.insert("insert", QString("replace"));
|
||||
break;
|
||||
}
|
||||
if (equals)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
// add lib
|
||||
to->libraries.insert(sliding_insert_window, lib);
|
||||
libObj.insert("insert", QString("prepend-if-not-exists"));
|
||||
sliding_insert_window++;
|
||||
}
|
||||
librariesPlus.prepend(libObj);
|
||||
}
|
||||
to->mainClass = m_forge_version->mainClass;
|
||||
to->minecraftArguments = m_forge_version->minecraftArguments;
|
||||
to->processArguments = m_forge_version->processArguments;
|
||||
obj.insert("+libraries", librariesPlus);
|
||||
obj.insert("mainClass", m_forge_version->mainClass);
|
||||
QString args = m_forge_version->minecraftArguments;
|
||||
QStringList tweakers;
|
||||
{
|
||||
QRegularExpression expression("--tweakClass ([a-zA-Z0-9\\.]*)");
|
||||
QRegularExpressionMatch match = expression.match(args);
|
||||
while (match.hasMatch())
|
||||
{
|
||||
tweakers.append(match.captured(1));
|
||||
args.remove(match.capturedStart(), match.capturedLength());
|
||||
match = expression.match(args);
|
||||
}
|
||||
to->externalUpdateFinish();
|
||||
return to->toOriginalFile();
|
||||
}
|
||||
if (!args.isEmpty() && args != to->getNonCustomVersion()->minecraftArguments)
|
||||
{
|
||||
obj.insert("minecraftArguments", args);
|
||||
}
|
||||
if (!tweakers.isEmpty())
|
||||
{
|
||||
obj.insert("+tweakers", QJsonArray::fromStringList(tweakers));
|
||||
}
|
||||
if (!m_forge_version->processArguments.isEmpty() &&
|
||||
m_forge_version->processArguments != to->getNonCustomVersion()->processArguments)
|
||||
{
|
||||
obj.insert("processArguments", m_forge_version->processArguments);
|
||||
}
|
||||
}
|
||||
|
||||
obj.insert("name", QString("Forge"));
|
||||
obj.insert("fileId", id());
|
||||
obj.insert("version", m_forgeVersionString);
|
||||
obj.insert("mcVersion", to->intendedVersionId());
|
||||
|
||||
QFile file(filename(to->instanceRoot()));
|
||||
if (!file.open(QFile::WriteOnly))
|
||||
{
|
||||
QLOG_ERROR() << "Error opening" << file.fileName()
|
||||
<< "for reading:" << file.errorString();
|
||||
return false;
|
||||
}
|
||||
file.write(QJsonDocument(obj).toJson());
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -14,17 +14,22 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BaseInstaller.h"
|
||||
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
|
||||
class OneSixVersion;
|
||||
|
||||
class ForgeInstaller
|
||||
class ForgeInstaller : public BaseInstaller
|
||||
{
|
||||
public:
|
||||
ForgeInstaller(QString filename, QString universal_url);
|
||||
|
||||
bool apply(std::shared_ptr<OneSixVersion> to);
|
||||
bool add(OneSixInstance *to) override;
|
||||
|
||||
QString id() const override { return "net.minecraftforge"; }
|
||||
|
||||
private:
|
||||
// the version, read from the installer
|
||||
@ -32,5 +37,6 @@ private:
|
||||
QString internalPath;
|
||||
QString finalPath;
|
||||
QString realVersionId;
|
||||
QString m_forgeVersionString;
|
||||
QString m_universal_url;
|
||||
};
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "OneSixInstance.h"
|
||||
#include "OneSixFTBInstance.h"
|
||||
#include "NostalgiaInstance.h"
|
||||
#include "OneSixInstance.h"
|
||||
#include "BaseVersion.h"
|
||||
#include "MinecraftVersion.h"
|
||||
|
||||
@ -50,14 +51,14 @@ InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst
|
||||
QString inst_type = m_settings->get("InstanceType").toString();
|
||||
|
||||
// FIXME: replace with a map lookup, where instance classes register their types
|
||||
if (inst_type == "Legacy")
|
||||
{
|
||||
inst = new LegacyInstance(instDir, m_settings, this);
|
||||
}
|
||||
else if (inst_type == "OneSix")
|
||||
if (inst_type == "OneSix")
|
||||
{
|
||||
inst = new OneSixInstance(instDir, m_settings, this);
|
||||
}
|
||||
else if (inst_type == "Legacy")
|
||||
{
|
||||
inst = new LegacyInstance(instDir, m_settings, this);
|
||||
}
|
||||
else if (inst_type == "Nostalgia")
|
||||
{
|
||||
inst = new NostalgiaInstance(instDir, m_settings, this);
|
||||
@ -101,6 +102,7 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(BaseInstance *&
|
||||
switch (mcVer->type)
|
||||
{
|
||||
case MinecraftVersion::Legacy:
|
||||
// TODO new instance type
|
||||
m_settings->set("InstanceType", "Legacy");
|
||||
inst = new LegacyInstance(instDir, m_settings, this);
|
||||
inst->setIntendedVersionId(version->descriptor());
|
||||
|
@ -15,12 +15,19 @@
|
||||
|
||||
#include "LiteLoaderInstaller.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "logger/QsLog.h"
|
||||
|
||||
#include "OneSixVersion.h"
|
||||
#include "OneSixLibrary.h"
|
||||
#include "OneSixInstance.h"
|
||||
|
||||
QMap<QString, QString> LiteLoaderInstaller::m_launcherWrapperVersionMapping;
|
||||
|
||||
LiteLoaderInstaller::LiteLoaderInstaller(const QString &mcVersion) : m_mcVersion(mcVersion)
|
||||
LiteLoaderInstaller::LiteLoaderInstaller()
|
||||
: BaseInstaller()
|
||||
{
|
||||
if (m_launcherWrapperVersionMapping.isEmpty())
|
||||
{
|
||||
@ -31,72 +38,59 @@ LiteLoaderInstaller::LiteLoaderInstaller(const QString &mcVersion) : m_mcVersion
|
||||
}
|
||||
}
|
||||
|
||||
bool LiteLoaderInstaller::canApply() const
|
||||
bool LiteLoaderInstaller::canApply(OneSixInstance *instance) const
|
||||
{
|
||||
return m_launcherWrapperVersionMapping.contains(m_mcVersion);
|
||||
return m_launcherWrapperVersionMapping.contains(instance->intendedVersionId());
|
||||
}
|
||||
|
||||
bool LiteLoaderInstaller::apply(std::shared_ptr<OneSixVersion> to)
|
||||
bool LiteLoaderInstaller::add(OneSixInstance *to)
|
||||
{
|
||||
to->externalUpdateStart();
|
||||
|
||||
applyLaunchwrapper(to);
|
||||
applyLiteLoader(to);
|
||||
|
||||
to->mainClass = "net.minecraft.launchwrapper.Launch";
|
||||
if (!to->minecraftArguments.contains(
|
||||
" --tweakClass com.mumfrey.liteloader.launch.LiteLoaderTweaker"))
|
||||
if (!BaseInstaller::add(to))
|
||||
{
|
||||
to->minecraftArguments.append(
|
||||
" --tweakClass com.mumfrey.liteloader.launch.LiteLoaderTweaker");
|
||||
return false;
|
||||
}
|
||||
|
||||
to->externalUpdateFinish();
|
||||
return to->toOriginalFile();
|
||||
}
|
||||
|
||||
void LiteLoaderInstaller::applyLaunchwrapper(std::shared_ptr<OneSixVersion> to)
|
||||
{
|
||||
const QString intendedVersion = m_launcherWrapperVersionMapping[m_mcVersion];
|
||||
|
||||
QMutableListIterator<std::shared_ptr<OneSixLibrary>> it(to->libraries);
|
||||
while (it.hasNext())
|
||||
{
|
||||
it.next();
|
||||
if (it.value()->rawName().startsWith("net.minecraft:launchwrapper:"))
|
||||
{
|
||||
if (it.value()->version() >= intendedVersion)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<OneSixLibrary> lib(new OneSixLibrary(
|
||||
"net.minecraft:launchwrapper:" + m_launcherWrapperVersionMapping[m_mcVersion]));
|
||||
lib->finalize();
|
||||
to->libraries.prepend(lib);
|
||||
}
|
||||
|
||||
void LiteLoaderInstaller::applyLiteLoader(std::shared_ptr<OneSixVersion> to)
|
||||
{
|
||||
QMutableListIterator<std::shared_ptr<OneSixLibrary>> it(to->libraries);
|
||||
while (it.hasNext())
|
||||
{
|
||||
it.next();
|
||||
if (it.value()->rawName().startsWith("com.mumfrey:liteloader:"))
|
||||
{
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<OneSixLibrary> lib(
|
||||
new OneSixLibrary("com.mumfrey:liteloader:" + m_mcVersion));
|
||||
lib->setBaseUrl("http://dl.liteloader.com/versions/");
|
||||
lib->finalize();
|
||||
to->libraries.prepend(lib);
|
||||
QJsonObject obj;
|
||||
|
||||
obj.insert("mainClass", QString("net.minecraft.launchwrapper.Launch"));
|
||||
obj.insert("+tweakers", QJsonArray::fromStringList(QStringList() << "com.mumfrey.liteloader.launch.LiteLoaderTweaker"));
|
||||
obj.insert("order", 10);
|
||||
|
||||
QJsonArray libraries;
|
||||
|
||||
// launchwrapper
|
||||
{
|
||||
OneSixLibrary launchwrapperLib("net.minecraft:launchwrapper:" + m_launcherWrapperVersionMapping[to->intendedVersionId()]);
|
||||
launchwrapperLib.finalize();
|
||||
QJsonObject lwLibObj = launchwrapperLib.toJson();
|
||||
lwLibObj.insert("insert", QString("prepend-if-not-exists"));
|
||||
libraries.append(lwLibObj);
|
||||
}
|
||||
|
||||
// liteloader
|
||||
{
|
||||
OneSixLibrary liteloaderLib("com.mumfrey:liteloader:" + to->intendedVersionId());
|
||||
liteloaderLib.setBaseUrl("http://dl.liteloader.com/versions/");
|
||||
liteloaderLib.finalize();
|
||||
QJsonObject llLibObj = liteloaderLib.toJson();
|
||||
llLibObj.insert("insert", QString("prepend"));
|
||||
libraries.append(llLibObj);
|
||||
}
|
||||
|
||||
obj.insert("+libraries", libraries);
|
||||
obj.insert("name", QString("LiteLoader"));
|
||||
obj.insert("fileId", id());
|
||||
obj.insert("version", to->intendedVersionId());
|
||||
obj.insert("mcVersion", to->intendedVersionId());
|
||||
|
||||
QFile file(filename(to->instanceRoot()));
|
||||
if (!file.open(QFile::WriteOnly))
|
||||
{
|
||||
QLOG_ERROR() << "Error opening" << file.fileName() << "for reading:" << file.errorString();
|
||||
return false;
|
||||
}
|
||||
file.write(QJsonDocument(obj).toJson());
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -14,26 +14,22 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BaseInstaller.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
#include <memory>
|
||||
|
||||
class OneSixVersion;
|
||||
|
||||
class LiteLoaderInstaller
|
||||
class LiteLoaderInstaller : public BaseInstaller
|
||||
{
|
||||
public:
|
||||
LiteLoaderInstaller(const QString &mcVersion);
|
||||
LiteLoaderInstaller();
|
||||
|
||||
bool canApply() const;
|
||||
|
||||
bool apply(std::shared_ptr<OneSixVersion> to);
|
||||
bool canApply(OneSixInstance *instance) const override;
|
||||
bool add(OneSixInstance *to) override;
|
||||
|
||||
private:
|
||||
QString m_mcVersion;
|
||||
|
||||
void applyLaunchwrapper(std::shared_ptr<OneSixVersion> to);
|
||||
void applyLiteLoader(std::shared_ptr<OneSixVersion> to);
|
||||
virtual QString id() const override { return "com.mumfrey.liteloader"; }
|
||||
|
||||
static QMap<QString, QString> m_launcherWrapperVersionMapping;
|
||||
};
|
||||
|
@ -55,15 +55,13 @@ slots:
|
||||
setStatus(tr("Installing Forge..."));
|
||||
QString forgePath = entry->getFullPath();
|
||||
ForgeInstaller forge(forgePath, forgeVersion->universal_url);
|
||||
if (!instance->reloadFullVersion())
|
||||
if (!instance->reloadVersion())
|
||||
{
|
||||
emitFailed(tr("Couldn't load the version config"));
|
||||
return;
|
||||
}
|
||||
instance->revertCustomVersion();
|
||||
instance->customizeVersion();
|
||||
auto version = instance->getFullVersion();
|
||||
if (!forge.apply(version))
|
||||
if (!forge.add(instance))
|
||||
{
|
||||
emitFailed(tr("Couldn't install Forge"));
|
||||
return;
|
||||
|
@ -13,32 +13,37 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MultiMC.h"
|
||||
#include "OneSixInstance.h"
|
||||
#include "OneSixInstance_p.h"
|
||||
#include "OneSixUpdate.h"
|
||||
#include "MinecraftProcess.h"
|
||||
#include "OneSixVersion.h"
|
||||
#include "JavaChecker.h"
|
||||
#include "logic/icons/IconList.h"
|
||||
|
||||
#include <setting.h>
|
||||
#include <pathutils.h>
|
||||
#include <cmdutils.h>
|
||||
#include <JlCompress.h>
|
||||
#include "gui/dialogs/OneSixModEditDialog.h"
|
||||
#include "logger/QsLog.h"
|
||||
#include "logic/assets/AssetsUtils.h"
|
||||
#include <QIcon>
|
||||
|
||||
OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *setting_obj,
|
||||
QObject *parent)
|
||||
: BaseInstance(new OneSixInstancePrivate(), rootDir, setting_obj, parent)
|
||||
#include "OneSixInstance_p.h"
|
||||
#include "OneSixUpdate.h"
|
||||
#include "OneSixVersion.h"
|
||||
#include "pathutils.h"
|
||||
#include "logger/QsLog.h"
|
||||
#include "assets/AssetsUtils.h"
|
||||
#include "MultiMC.h"
|
||||
#include "icons/IconList.h"
|
||||
#include "MinecraftProcess.h"
|
||||
#include "gui/dialogs/OneSixModEditDialog.h"
|
||||
|
||||
OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *settings, QObject *parent)
|
||||
: BaseInstance(new OneSixInstancePrivate(), rootDir, settings, parent)
|
||||
{
|
||||
I_D(OneSixInstance);
|
||||
d->m_settings->registerSetting("IntendedVersion", "");
|
||||
d->m_settings->registerSetting("ShouldUpdate", false);
|
||||
reloadFullVersion();
|
||||
d->version.reset(new OneSixVersion(this, this));
|
||||
d->nonCustomVersion.reset(new OneSixVersion(this, this));
|
||||
if (QDir(instanceRoot()).exists("version.json"))
|
||||
{
|
||||
reloadVersion();
|
||||
}
|
||||
else
|
||||
{
|
||||
clearVersion();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Task> OneSixInstance::doUpdate()
|
||||
@ -135,6 +140,10 @@ QStringList OneSixInstance::processMinecraftArgs(AuthSessionPtr session)
|
||||
I_D(OneSixInstance);
|
||||
auto version = d->version;
|
||||
QString args_pattern = version->minecraftArguments;
|
||||
for (auto tweaker : version->tweakers)
|
||||
{
|
||||
args_pattern += " --tweakClass " + tweaker;
|
||||
}
|
||||
|
||||
QMap<QString, QString> token_mapping;
|
||||
// yggdrasil!
|
||||
@ -267,11 +276,8 @@ bool OneSixInstance::setIntendedVersionId(QString version)
|
||||
{
|
||||
settings().set("IntendedVersion", version);
|
||||
setShouldUpdate(true);
|
||||
auto pathCustom = PathCombine(instanceRoot(), "custom.json");
|
||||
auto pathOrig = PathCombine(instanceRoot(), "version.json");
|
||||
QFile::remove(pathCustom);
|
||||
QFile::remove(pathOrig);
|
||||
reloadFullVersion();
|
||||
QFile::remove(PathCombine(instanceRoot(), "version.json"));
|
||||
clearVersion();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -297,9 +303,10 @@ bool OneSixInstance::shouldUpdate() const
|
||||
|
||||
bool OneSixInstance::versionIsCustom()
|
||||
{
|
||||
QString verpath_custom = PathCombine(instanceRoot(), "custom.json");
|
||||
QFile versionfile(verpath_custom);
|
||||
return versionfile.exists();
|
||||
QDir patches(PathCombine(instanceRoot(), "patches/"));
|
||||
return (patches.exists() && patches.count() >= 0)
|
||||
|| QFile::exists(PathCombine(instanceRoot(), "custom.json"))
|
||||
|| QFile::exists(PathCombine(instanceRoot(), "user.json"));
|
||||
}
|
||||
|
||||
QString OneSixInstance::currentVersionId() const
|
||||
@ -307,62 +314,39 @@ QString OneSixInstance::currentVersionId() const
|
||||
return intendedVersionId();
|
||||
}
|
||||
|
||||
bool OneSixInstance::customizeVersion()
|
||||
{
|
||||
if (!versionIsCustom())
|
||||
{
|
||||
auto pathCustom = PathCombine(instanceRoot(), "custom.json");
|
||||
auto pathOrig = PathCombine(instanceRoot(), "version.json");
|
||||
QFile::copy(pathOrig, pathCustom);
|
||||
return reloadFullVersion();
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OneSixInstance::revertCustomVersion()
|
||||
{
|
||||
if (versionIsCustom())
|
||||
{
|
||||
auto path = PathCombine(instanceRoot(), "custom.json");
|
||||
QFile::remove(path);
|
||||
return reloadFullVersion();
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OneSixInstance::reloadFullVersion()
|
||||
bool OneSixInstance::reloadVersion(QWidget *widgetParent)
|
||||
{
|
||||
I_D(OneSixInstance);
|
||||
|
||||
QString verpath = PathCombine(instanceRoot(), "version.json");
|
||||
bool ret = d->version->reload(widgetParent);
|
||||
if (ret)
|
||||
{
|
||||
QString verpath_custom = PathCombine(instanceRoot(), "custom.json");
|
||||
QFile versionfile(verpath_custom);
|
||||
if (versionfile.exists())
|
||||
verpath = verpath_custom;
|
||||
}
|
||||
|
||||
auto version = OneSixVersion::fromFile(verpath);
|
||||
if (version)
|
||||
{
|
||||
d->version = version;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->version.reset();
|
||||
return false;
|
||||
ret = d->nonCustomVersion->reload(widgetParent, true);
|
||||
}
|
||||
emit versionReloaded();
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::shared_ptr<OneSixVersion> OneSixInstance::getFullVersion()
|
||||
void OneSixInstance::clearVersion()
|
||||
{
|
||||
I_D(OneSixInstance);
|
||||
d->version->clear();
|
||||
d->nonCustomVersion->clear();
|
||||
emit versionReloaded();
|
||||
}
|
||||
|
||||
std::shared_ptr<OneSixVersion> OneSixInstance::getFullVersion() const
|
||||
{
|
||||
I_D(const OneSixInstance);
|
||||
return d->version;
|
||||
}
|
||||
|
||||
std::shared_ptr<OneSixVersion> OneSixInstance::getNonCustomVersion() const
|
||||
{
|
||||
I_D(const OneSixInstance);
|
||||
return d->nonCustomVersion;
|
||||
}
|
||||
|
||||
QString OneSixInstance::defaultBaseJar() const
|
||||
{
|
||||
return "versions/" + intendedVersionId() + "/" + intendedVersionId() + ".jar";
|
||||
@ -382,7 +366,7 @@ bool OneSixInstance::menuActionEnabled(QString action_name) const
|
||||
|
||||
QString OneSixInstance::getStatusbarDescription()
|
||||
{
|
||||
QString descr = "One Six : " + intendedVersionId();
|
||||
QString descr = "OneSix : " + intendedVersionId();
|
||||
if (versionIsCustom())
|
||||
{
|
||||
descr + " (custom)";
|
||||
|
@ -15,14 +15,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
|
||||
#include "BaseInstance.h"
|
||||
|
||||
class OneSixVersion;
|
||||
class Task;
|
||||
class ModList;
|
||||
#include "OneSixVersion.h"
|
||||
#include "ModList.h"
|
||||
|
||||
class OneSixInstance : public BaseInstance
|
||||
{
|
||||
@ -55,14 +51,14 @@ public:
|
||||
|
||||
virtual QDialog *createModEditDialog(QWidget *parent) override;
|
||||
|
||||
/// reload the full version json file. return true on success!
|
||||
bool reloadFullVersion();
|
||||
/// reload the full version json files. return true on success!
|
||||
bool reloadVersion(QWidget *widgetParent = 0);
|
||||
/// clears all version information in preparation for an update
|
||||
void clearVersion();
|
||||
/// get the current full version info
|
||||
std::shared_ptr<OneSixVersion> getFullVersion();
|
||||
/// revert the current custom version back to base
|
||||
bool revertCustomVersion();
|
||||
/// customize the current base version
|
||||
bool customizeVersion();
|
||||
std::shared_ptr<OneSixVersion> getFullVersion() const;
|
||||
/// gets the current version info, excluding custom.json
|
||||
std::shared_ptr<OneSixVersion> getNonCustomVersion() const;
|
||||
/// is the current version original, or custom?
|
||||
virtual bool versionIsCustom() override;
|
||||
|
||||
@ -72,6 +68,9 @@ public:
|
||||
virtual bool menuActionEnabled(QString action_name) const override;
|
||||
virtual QString getStatusbarDescription() override;
|
||||
|
||||
signals:
|
||||
void versionReloaded();
|
||||
|
||||
private:
|
||||
QStringList processMinecraftArgs(AuthSessionPtr account);
|
||||
QDir reconstructAssets(std::shared_ptr<OneSixVersion> version);
|
||||
|
@ -15,16 +15,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "logic/BaseInstance_p.h"
|
||||
#include "logic/OneSixVersion.h"
|
||||
#include "logic/OneSixLibrary.h"
|
||||
#include "logic/ModList.h"
|
||||
#include "BaseInstance_p.h"
|
||||
#include "OneSixVersion.h"
|
||||
#include "ModList.h"
|
||||
|
||||
struct OneSixInstancePrivate : public BaseInstancePrivate
|
||||
{
|
||||
std::shared_ptr<OneSixVersion> version;
|
||||
std::shared_ptr<OneSixVersion> nonCustomVersion;
|
||||
std::shared_ptr<ModList> loader_mod_list;
|
||||
std::shared_ptr<ModList> resource_pack_list;
|
||||
};
|
@ -76,11 +76,11 @@ void OneSixLibrary::finalize()
|
||||
}
|
||||
}
|
||||
|
||||
void OneSixLibrary::setName(QString name)
|
||||
void OneSixLibrary::setName(const QString &name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
void OneSixLibrary::setBaseUrl(QString base_url)
|
||||
void OneSixLibrary::setBaseUrl(const QString &base_url)
|
||||
{
|
||||
m_base_url = base_url;
|
||||
}
|
||||
@ -88,50 +88,54 @@ void OneSixLibrary::setIsNative()
|
||||
{
|
||||
m_is_native = true;
|
||||
}
|
||||
void OneSixLibrary::addNative(OpSys os, QString suffix)
|
||||
void OneSixLibrary::addNative(OpSys os, const QString &suffix)
|
||||
{
|
||||
m_is_native = true;
|
||||
m_native_suffixes[os] = suffix;
|
||||
}
|
||||
void OneSixLibrary::clearSuffixes()
|
||||
{
|
||||
m_native_suffixes.clear();
|
||||
}
|
||||
void OneSixLibrary::setRules(QList<std::shared_ptr<Rule>> rules)
|
||||
{
|
||||
m_rules = rules;
|
||||
}
|
||||
bool OneSixLibrary::isActive()
|
||||
bool OneSixLibrary::isActive() const
|
||||
{
|
||||
return m_is_active;
|
||||
}
|
||||
bool OneSixLibrary::isNative()
|
||||
bool OneSixLibrary::isNative() const
|
||||
{
|
||||
return m_is_native;
|
||||
}
|
||||
QString OneSixLibrary::downloadUrl()
|
||||
QString OneSixLibrary::downloadUrl() const
|
||||
{
|
||||
if (m_absolute_url.size())
|
||||
return m_absolute_url;
|
||||
return m_download_url;
|
||||
}
|
||||
QString OneSixLibrary::storagePath()
|
||||
QString OneSixLibrary::storagePath() const
|
||||
{
|
||||
return m_storage_path;
|
||||
}
|
||||
|
||||
void OneSixLibrary::setAbsoluteUrl(QString absolute_url)
|
||||
void OneSixLibrary::setAbsoluteUrl(const QString &absolute_url)
|
||||
{
|
||||
m_absolute_url = absolute_url;
|
||||
}
|
||||
|
||||
QString OneSixLibrary::absoluteUrl()
|
||||
QString OneSixLibrary::absoluteUrl() const
|
||||
{
|
||||
return m_absolute_url;
|
||||
}
|
||||
|
||||
void OneSixLibrary::setHint(QString hint)
|
||||
void OneSixLibrary::setHint(const QString &hint)
|
||||
{
|
||||
m_hint = hint;
|
||||
}
|
||||
|
||||
QString OneSixLibrary::hint()
|
||||
QString OneSixLibrary::hint() const
|
||||
{
|
||||
return m_hint;
|
||||
}
|
||||
@ -176,7 +180,7 @@ bool OneSixLibrary::extractTo(QString target_dir)
|
||||
cooked_storage.replace("${arch}", "32");
|
||||
QString origin = PathCombine("libraries", cooked_storage);
|
||||
QString target_dir_cooked = PathCombine(target_dir, "32");
|
||||
if(!ensureFolderPathExists(target_dir_cooked))
|
||||
if (!ensureFolderPathExists(target_dir_cooked))
|
||||
{
|
||||
QLOG_ERROR() << "Couldn't create folder " + target_dir_cooked;
|
||||
return false;
|
||||
@ -191,7 +195,7 @@ bool OneSixLibrary::extractTo(QString target_dir)
|
||||
cooked_storage.replace("${arch}", "64");
|
||||
origin = PathCombine("libraries", cooked_storage);
|
||||
target_dir_cooked = PathCombine(target_dir, "64");
|
||||
if(!ensureFolderPathExists(target_dir_cooked))
|
||||
if (!ensureFolderPathExists(target_dir_cooked))
|
||||
{
|
||||
QLOG_ERROR() << "Couldn't create folder " + target_dir_cooked;
|
||||
return false;
|
||||
@ -205,7 +209,7 @@ bool OneSixLibrary::extractTo(QString target_dir)
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!ensureFolderPathExists(target_dir))
|
||||
if (!ensureFolderPathExists(target_dir))
|
||||
{
|
||||
QLOG_ERROR() << "Couldn't create folder " + target_dir;
|
||||
return false;
|
||||
@ -230,8 +234,10 @@ QJsonObject OneSixLibrary::toJson()
|
||||
libRoot.insert("MMC-hint", m_hint);
|
||||
if (m_base_url != "http://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
|
||||
m_base_url != "https://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
|
||||
m_base_url != "https://" + URLConstants::LIBRARY_BASE)
|
||||
m_base_url != "https://" + URLConstants::LIBRARY_BASE && !m_base_url.isEmpty())
|
||||
{
|
||||
libRoot.insert("url", m_base_url);
|
||||
}
|
||||
if (isNative() && m_native_suffixes.size())
|
||||
{
|
||||
QJsonObject nativeList;
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
OneSixLibrary(QString name)
|
||||
OneSixLibrary(const QString &name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
@ -84,48 +84,50 @@ public:
|
||||
void finalize();
|
||||
|
||||
/// Set the library composite name
|
||||
void setName(QString name);
|
||||
void setName(const QString &name);
|
||||
/// get a decent-looking name
|
||||
QString name()
|
||||
QString name() const
|
||||
{
|
||||
return m_decentname;
|
||||
}
|
||||
/// get a decent-looking version
|
||||
QString version()
|
||||
QString version() const
|
||||
{
|
||||
return m_decentversion;
|
||||
}
|
||||
/// what kind of library is it? (for display)
|
||||
QString type()
|
||||
QString type() const
|
||||
{
|
||||
return m_decenttype;
|
||||
}
|
||||
/// Set the url base for downloads
|
||||
void setBaseUrl(QString base_url);
|
||||
void setBaseUrl(const QString &base_url);
|
||||
|
||||
/// Call this to mark the library as 'native' (it's a zip archive with DLLs)
|
||||
void setIsNative();
|
||||
/// Attach a name suffix to the specified OS native
|
||||
void addNative(OpSys os, QString suffix);
|
||||
void addNative(OpSys os, const QString &suffix);
|
||||
/// Clears all suffixes
|
||||
void clearSuffixes();
|
||||
/// Set the load rules
|
||||
void setRules(QList<std::shared_ptr<Rule>> rules);
|
||||
|
||||
/// Returns true if the library should be loaded (or extracted, in case of natives)
|
||||
bool isActive();
|
||||
bool isActive() const;
|
||||
/// Returns true if the library is native
|
||||
bool isNative();
|
||||
bool isNative() const;
|
||||
/// Get the URL to download the library from
|
||||
QString downloadUrl();
|
||||
QString downloadUrl() const;
|
||||
/// Get the relative path where the library should be saved
|
||||
QString storagePath();
|
||||
QString storagePath() const;
|
||||
|
||||
/// set an absolute URL for the library. This is an MMC extension.
|
||||
void setAbsoluteUrl(QString absolute_url);
|
||||
QString absoluteUrl();
|
||||
void setAbsoluteUrl(const QString &absolute_url);
|
||||
QString absoluteUrl() const;
|
||||
|
||||
/// set a hint about how to treat the library. This is an MMC extension.
|
||||
void setHint(QString hint);
|
||||
QString hint();
|
||||
void setHint(const QString &hint);
|
||||
QString hint() const;
|
||||
|
||||
bool extractTo(QString target_dir);
|
||||
bool filesExist();
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
#include "OneSixRule.h"
|
||||
|
||||
QList<std::shared_ptr<Rule>> rulesFromJsonV4(QJsonObject &objectWithRules)
|
||||
QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules)
|
||||
{
|
||||
QList<std::shared_ptr<Rule>> rules;
|
||||
auto rulesVal = objectWithRules.value("rules");
|
||||
|
@ -27,7 +27,7 @@ enum RuleAction
|
||||
};
|
||||
|
||||
RuleAction RuleAction_fromString(QString);
|
||||
QList<std::shared_ptr<Rule>> rulesFromJsonV4(QJsonObject &objectWithRules);
|
||||
QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules);
|
||||
|
||||
class Rule
|
||||
{
|
||||
|
@ -131,7 +131,7 @@ void OneSixUpdate::versionFileFinished()
|
||||
{
|
||||
finfo.remove();
|
||||
}
|
||||
inst->reloadFullVersion();
|
||||
inst->reloadVersion();
|
||||
|
||||
jarlibStart();
|
||||
}
|
||||
@ -229,7 +229,7 @@ void OneSixUpdate::jarlibStart()
|
||||
setStatus(tr("Getting the library files from Mojang..."));
|
||||
QLOG_INFO() << m_inst->name() << ": downloading libraries";
|
||||
OneSixInstance *inst = (OneSixInstance *)m_inst;
|
||||
bool successful = inst->reloadFullVersion();
|
||||
bool successful = inst->reloadVersion();
|
||||
if (!successful)
|
||||
{
|
||||
emitFailed("Failed to load the version description file. It might be "
|
||||
|
@ -13,228 +13,86 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "logic/OneSixVersion.h"
|
||||
#include "logic/OneSixLibrary.h"
|
||||
#include "logic/OneSixRule.h"
|
||||
#include "OneSixVersion.h"
|
||||
|
||||
#include "logger/QsLog.h"
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
|
||||
std::shared_ptr<OneSixVersion> fromJsonV4(QJsonObject root,
|
||||
std::shared_ptr<OneSixVersion> fullVersion)
|
||||
#include "OneSixVersionBuilder.h"
|
||||
|
||||
OneSixVersion::OneSixVersion(OneSixInstance *instance, QObject *parent)
|
||||
: QAbstractListModel(parent), m_instance(instance)
|
||||
{
|
||||
fullVersion->id = root.value("id").toString();
|
||||
|
||||
fullVersion->mainClass = root.value("mainClass").toString();
|
||||
auto procArgsValue = root.value("processArguments");
|
||||
if (procArgsValue.isString())
|
||||
{
|
||||
fullVersion->processArguments = procArgsValue.toString();
|
||||
QString toCompare = fullVersion->processArguments.toLower();
|
||||
if (toCompare == "legacy")
|
||||
{
|
||||
fullVersion->minecraftArguments = " ${auth_player_name} ${auth_session}";
|
||||
}
|
||||
else if (toCompare == "username_session")
|
||||
{
|
||||
fullVersion->minecraftArguments =
|
||||
"--username ${auth_player_name} --session ${auth_session}";
|
||||
}
|
||||
else if (toCompare == "username_session_version")
|
||||
{
|
||||
fullVersion->minecraftArguments = "--username ${auth_player_name} "
|
||||
"--session ${auth_session} "
|
||||
"--version ${profile_name}";
|
||||
}
|
||||
}
|
||||
|
||||
auto minecraftArgsValue = root.value("minecraftArguments");
|
||||
if (minecraftArgsValue.isString())
|
||||
{
|
||||
fullVersion->minecraftArguments = minecraftArgsValue.toString();
|
||||
}
|
||||
|
||||
auto minecraftTypeValue = root.value("type");
|
||||
if (minecraftTypeValue.isString())
|
||||
{
|
||||
fullVersion->type = minecraftTypeValue.toString();
|
||||
}
|
||||
|
||||
fullVersion->releaseTime = root.value("releaseTime").toString();
|
||||
fullVersion->time = root.value("time").toString();
|
||||
|
||||
auto assetsID = root.value("assets");
|
||||
if (assetsID.isString())
|
||||
{
|
||||
fullVersion->assets = assetsID.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
fullVersion->assets = "legacy";
|
||||
}
|
||||
|
||||
QLOG_DEBUG() << "Assets version:" << fullVersion->assets;
|
||||
|
||||
// Iterate through the list, if it's a list.
|
||||
auto librariesValue = root.value("libraries");
|
||||
if (!librariesValue.isArray())
|
||||
return fullVersion;
|
||||
|
||||
QJsonArray libList = root.value("libraries").toArray();
|
||||
for (auto libVal : libList)
|
||||
{
|
||||
if (!libVal.isObject())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QJsonObject libObj = libVal.toObject();
|
||||
|
||||
// Library name
|
||||
auto nameVal = libObj.value("name");
|
||||
if (!nameVal.isString())
|
||||
continue;
|
||||
std::shared_ptr<OneSixLibrary> library(new OneSixLibrary(nameVal.toString()));
|
||||
|
||||
auto urlVal = libObj.value("url");
|
||||
if (urlVal.isString())
|
||||
{
|
||||
library->setBaseUrl(urlVal.toString());
|
||||
}
|
||||
auto hintVal = libObj.value("MMC-hint");
|
||||
if (hintVal.isString())
|
||||
{
|
||||
library->setHint(hintVal.toString());
|
||||
}
|
||||
auto urlAbsVal = libObj.value("MMC-absoluteUrl");
|
||||
auto urlAbsuVal = libObj.value("MMC-absulute_url"); // compatibility
|
||||
if (urlAbsVal.isString())
|
||||
{
|
||||
library->setAbsoluteUrl(urlAbsVal.toString());
|
||||
}
|
||||
else if (urlAbsuVal.isString())
|
||||
{
|
||||
library->setAbsoluteUrl(urlAbsuVal.toString());
|
||||
}
|
||||
// Extract excludes (if any)
|
||||
auto extractVal = libObj.value("extract");
|
||||
if (extractVal.isObject())
|
||||
{
|
||||
QStringList excludes;
|
||||
auto extractObj = extractVal.toObject();
|
||||
auto excludesVal = extractObj.value("exclude");
|
||||
if (excludesVal.isArray())
|
||||
{
|
||||
auto excludesList = excludesVal.toArray();
|
||||
for (auto excludeVal : excludesList)
|
||||
{
|
||||
if (excludeVal.isString())
|
||||
excludes.append(excludeVal.toString());
|
||||
}
|
||||
library->extract_excludes = excludes;
|
||||
}
|
||||
}
|
||||
|
||||
auto nativesVal = libObj.value("natives");
|
||||
if (nativesVal.isObject())
|
||||
{
|
||||
library->setIsNative();
|
||||
auto nativesObj = nativesVal.toObject();
|
||||
auto iter = nativesObj.begin();
|
||||
while (iter != nativesObj.end())
|
||||
{
|
||||
auto osType = OpSys_fromString(iter.key());
|
||||
if (osType == Os_Other)
|
||||
continue;
|
||||
if (!iter.value().isString())
|
||||
continue;
|
||||
library->addNative(osType, iter.value().toString());
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
library->setRules(rulesFromJsonV4(libObj));
|
||||
library->finalize();
|
||||
fullVersion->libraries.append(library);
|
||||
}
|
||||
return fullVersion;
|
||||
clear();
|
||||
}
|
||||
|
||||
std::shared_ptr<OneSixVersion> OneSixVersion::fromJson(QJsonObject root)
|
||||
bool OneSixVersion::reload(QWidget *widgetParent, const bool excludeCustom)
|
||||
{
|
||||
std::shared_ptr<OneSixVersion> readVersion(new OneSixVersion());
|
||||
int launcher_ver = readVersion->minimumLauncherVersion =
|
||||
root.value("minimumLauncherVersion").toDouble();
|
||||
|
||||
// ADD MORE HERE :D
|
||||
if (launcher_ver > 0 && launcher_ver <= 13)
|
||||
return fromJsonV4(root, readVersion);
|
||||
else
|
||||
{
|
||||
return std::shared_ptr<OneSixVersion>();
|
||||
}
|
||||
beginResetModel();
|
||||
bool ret = OneSixVersionBuilder::build(this, m_instance, widgetParent, excludeCustom);
|
||||
endResetModel();
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::shared_ptr<OneSixVersion> OneSixVersion::fromFile(QString filepath)
|
||||
void OneSixVersion::clear()
|
||||
{
|
||||
QFile file(filepath);
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
return std::shared_ptr<OneSixVersion>();
|
||||
}
|
||||
|
||||
auto data = file.readAll();
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
||||
|
||||
if (jsonError.error != QJsonParseError::NoError)
|
||||
{
|
||||
return std::shared_ptr<OneSixVersion>();
|
||||
}
|
||||
|
||||
if (!jsonDoc.isObject())
|
||||
{
|
||||
return std::shared_ptr<OneSixVersion>();
|
||||
}
|
||||
QJsonObject root = jsonDoc.object();
|
||||
auto version = fromJson(root);
|
||||
if (version)
|
||||
version->original_file = filepath;
|
||||
return version;
|
||||
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 OneSixVersion::toOriginalFile()
|
||||
void OneSixVersion::dump() const
|
||||
{
|
||||
if (original_file.isEmpty())
|
||||
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;
|
||||
QSaveFile file(original_file);
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// serialize base attributes (those we care about anyway)
|
||||
QJsonObject root;
|
||||
root.insert("minecraftArguments", minecraftArguments);
|
||||
root.insert("mainClass", mainClass);
|
||||
root.insert("minimumLauncherVersion", minimumLauncherVersion);
|
||||
root.insert("time", time);
|
||||
root.insert("id", id);
|
||||
root.insert("type", type);
|
||||
// screw processArguments
|
||||
root.insert("releaseTime", releaseTime);
|
||||
QJsonArray libarray;
|
||||
for (const auto &lib : libraries)
|
||||
{
|
||||
libarray.append(lib->toJson());
|
||||
}
|
||||
if (libarray.count())
|
||||
root.insert("libraries", libarray);
|
||||
QJsonDocument doc(root);
|
||||
file.write(doc.toJson());
|
||||
return file.commit();
|
||||
}
|
||||
|
||||
QList<std::shared_ptr<OneSixLibrary>> OneSixVersion::getActiveNormalLibs()
|
||||
bool OneSixVersion::remove(const int index)
|
||||
{
|
||||
QList<std::shared_ptr<OneSixLibrary>> output;
|
||||
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())
|
||||
@ -245,9 +103,9 @@ QList<std::shared_ptr<OneSixLibrary>> OneSixVersion::getActiveNormalLibs()
|
||||
return output;
|
||||
}
|
||||
|
||||
QList<std::shared_ptr<OneSixLibrary>> OneSixVersion::getActiveNativeLibs()
|
||||
QList<std::shared_ptr<OneSixLibrary> > OneSixVersion::getActiveNativeLibs()
|
||||
{
|
||||
QList<std::shared_ptr<OneSixLibrary>> output;
|
||||
QList<std::shared_ptr<OneSixLibrary> > output;
|
||||
for (auto lib : libraries)
|
||||
{
|
||||
if (lib->isActive() && lib->isNative())
|
||||
@ -258,14 +116,14 @@ QList<std::shared_ptr<OneSixLibrary>> OneSixVersion::getActiveNativeLibs()
|
||||
return output;
|
||||
}
|
||||
|
||||
void OneSixVersion::externalUpdateStart()
|
||||
std::shared_ptr<OneSixVersion> OneSixVersion::fromJson(const QJsonObject &obj)
|
||||
{
|
||||
beginResetModel();
|
||||
}
|
||||
|
||||
void OneSixVersion::externalUpdateFinish()
|
||||
{
|
||||
endResetModel();
|
||||
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
|
||||
@ -276,7 +134,7 @@ QVariant OneSixVersion::data(const QModelIndex &index, int role) const
|
||||
int row = index.row();
|
||||
int column = index.column();
|
||||
|
||||
if (row < 0 || row >= libraries.size())
|
||||
if (row < 0 || row >= versionFiles.size())
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
@ -284,11 +142,9 @@ QVariant OneSixVersion::data(const QModelIndex &index, int role) const
|
||||
switch (column)
|
||||
{
|
||||
case 0:
|
||||
return libraries[row]->name();
|
||||
return versionFiles.at(row).name;
|
||||
case 1:
|
||||
return libraries[row]->type();
|
||||
case 2:
|
||||
return libraries[row]->version();
|
||||
return versionFiles.at(row).version;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
@ -296,45 +152,61 @@ QVariant OneSixVersion::data(const QModelIndex &index, int role) const
|
||||
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;
|
||||
int row = index.row();
|
||||
if (libraries[row]->isActive())
|
||||
{
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Qt::ItemNeverHasChildren;
|
||||
}
|
||||
// return QAbstractListModel::flags(index);
|
||||
}
|
||||
|
||||
QVariant OneSixVersion::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
|
||||
return QVariant();
|
||||
switch (section)
|
||||
{
|
||||
case 0:
|
||||
return QString("Name");
|
||||
case 1:
|
||||
return QString("Type");
|
||||
case 2:
|
||||
return QString("Version");
|
||||
default:
|
||||
return QString();
|
||||
}
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
}
|
||||
|
||||
int OneSixVersion::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return libraries.size();
|
||||
return versionFiles.size();
|
||||
}
|
||||
|
||||
int OneSixVersion::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 3;
|
||||
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();
|
||||
}
|
||||
|
@ -14,40 +14,48 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QtCore>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <memory>
|
||||
|
||||
class OneSixLibrary;
|
||||
#include "OneSixLibrary.h"
|
||||
|
||||
class OneSixInstance;
|
||||
|
||||
class OneSixVersion : public QAbstractListModel
|
||||
{
|
||||
// Things required to implement the Qt list model
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OneSixVersion(OneSixInstance *instance, QObject *parent = 0);
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
virtual int columnCount(const QModelIndex &parent) const;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
|
||||
// serialization/deserialization
|
||||
public:
|
||||
bool toOriginalFile();
|
||||
static std::shared_ptr<OneSixVersion> fromJson(QJsonObject root);
|
||||
static std::shared_ptr<OneSixVersion> fromFile(QString filepath);
|
||||
bool reload(QWidget *widgetParent, const bool excludeCustom = false);
|
||||
void clear();
|
||||
|
||||
void dump() const;
|
||||
|
||||
bool canRemove(const int index) const;
|
||||
|
||||
public
|
||||
slots:
|
||||
bool remove(const int index);
|
||||
|
||||
public:
|
||||
QList<std::shared_ptr<OneSixLibrary>> getActiveNormalLibs();
|
||||
QList<std::shared_ptr<OneSixLibrary>> getActiveNativeLibs();
|
||||
// called when something starts/stops messing with the object
|
||||
// FIXME: these are ugly in every possible way.
|
||||
void externalUpdateStart();
|
||||
void externalUpdateFinish();
|
||||
|
||||
static std::shared_ptr<OneSixVersion> fromJson(const QJsonObject &obj);
|
||||
|
||||
// data members
|
||||
public:
|
||||
/// file this was read from. blank, if none
|
||||
QString original_file;
|
||||
/// the ID - determines which jar to use! ACTUALLY IMPORTANT!
|
||||
QString id;
|
||||
/// Last updated time - as a string
|
||||
@ -75,6 +83,10 @@ public:
|
||||
* writing)
|
||||
*/
|
||||
int minimumLauncherVersion = 0xDEADBEEF;
|
||||
/**
|
||||
* A list of all tweaker classes
|
||||
*/
|
||||
QStringList tweakers;
|
||||
/**
|
||||
* The main class to load first
|
||||
*/
|
||||
@ -103,4 +115,20 @@ public:
|
||||
}
|
||||
*/
|
||||
// QList<Rule> rules;
|
||||
|
||||
struct VersionFile
|
||||
{
|
||||
QString name;
|
||||
QString id;
|
||||
QString version;
|
||||
QString mcVersion;
|
||||
QString filename;
|
||||
};
|
||||
QList<VersionFile> versionFiles;
|
||||
|
||||
private:
|
||||
OneSixInstance *m_instance;
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug &dbg, const OneSixVersion *version);
|
||||
QDebug operator<<(QDebug &dbg, const OneSixLibrary *library);
|
||||
|
919
logic/OneSixVersionBuilder.cpp
Normal file
919
logic/OneSixVersionBuilder.cpp
Normal file
@ -0,0 +1,919 @@
|
||||
/* 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 "OneSixVersionBuilder.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <QObject>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#include "OneSixVersion.h"
|
||||
#include "OneSixInstance.h"
|
||||
#include "OneSixRule.h"
|
||||
#include "logger/QsLog.h"
|
||||
|
||||
struct VersionFile
|
||||
{
|
||||
int order;
|
||||
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;
|
||||
|
||||
struct Library
|
||||
{
|
||||
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,
|
||||
AppendIfNotExists,
|
||||
PrependIfNotExists,
|
||||
Replace
|
||||
};
|
||||
InsertType insertType;
|
||||
QString insertData;
|
||||
};
|
||||
bool shouldOverwriteLibs = false;
|
||||
QList<Library> overwriteLibs;
|
||||
QList<Library> addLibs;
|
||||
QList<QString> removeLibs;
|
||||
|
||||
static Library fromLibraryJson(const QJsonObject &libObj, const QString &filename,
|
||||
bool &isError)
|
||||
{
|
||||
isError = true;
|
||||
Library out;
|
||||
if (!libObj.contains("name"))
|
||||
{
|
||||
QLOG_ERROR() << filename << "contains a library that doesn't have a 'name' field";
|
||||
return out;
|
||||
}
|
||||
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"))
|
||||
{
|
||||
if (!libObj.value("extract").isObject())
|
||||
{
|
||||
QLOG_ERROR()
|
||||
<< filename
|
||||
<< "contains a library with an 'extract' field that's not an object";
|
||||
return out;
|
||||
}
|
||||
QJsonObject extractObj = libObj.value("extract").toObject();
|
||||
if (!extractObj.contains("exclude") || !extractObj.value("exclude").isArray())
|
||||
{
|
||||
QLOG_ERROR() << filename
|
||||
<< "contains a library with an invalid 'extract' field";
|
||||
return out;
|
||||
}
|
||||
out.applyExcludes = true;
|
||||
QJsonArray excludeArray = extractObj.value("exclude").toArray();
|
||||
for (auto excludeVal : excludeArray)
|
||||
{
|
||||
if (!excludeVal.isString())
|
||||
{
|
||||
QLOG_WARN() << filename << "contains a library that contains an 'extract' "
|
||||
"field that contains an invalid 'exclude' entry "
|
||||
"(skipping)";
|
||||
}
|
||||
else
|
||||
{
|
||||
out.excludes.append(excludeVal.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (libObj.contains("natives"))
|
||||
{
|
||||
if (!libObj.value("natives").isObject())
|
||||
{
|
||||
QLOG_ERROR()
|
||||
<< filename
|
||||
<< "contains a library with a 'natives' field that's not an object";
|
||||
return out;
|
||||
}
|
||||
out.applyNatives = true;
|
||||
QJsonObject nativesObj = libObj.value("natives").toObject();
|
||||
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);
|
||||
}
|
||||
isError = false;
|
||||
return out;
|
||||
}
|
||||
static VersionFile fromJson(const QJsonDocument &doc, const QString &filename,
|
||||
const bool requireOrder, bool &isError)
|
||||
{
|
||||
VersionFile out;
|
||||
isError = true;
|
||||
if (doc.isEmpty() || doc.isNull())
|
||||
{
|
||||
QLOG_ERROR() << filename << "is empty or null";
|
||||
return out;
|
||||
}
|
||||
if (!doc.isObject())
|
||||
{
|
||||
QLOG_ERROR() << "The root of" << filename << "is not an object";
|
||||
return out;
|
||||
}
|
||||
|
||||
QJsonObject root = doc.object();
|
||||
|
||||
if (requireOrder)
|
||||
{
|
||||
if (root.contains("order"))
|
||||
{
|
||||
if (root.value("order").isDouble())
|
||||
{
|
||||
out.order = root.value("order").toDouble();
|
||||
}
|
||||
else
|
||||
{
|
||||
QLOG_ERROR() << "'order' field contains an invalid value in" << filename;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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))
|
||||
{
|
||||
QJsonValue val = root.value(key);
|
||||
if (!val.isString())
|
||||
{
|
||||
QLOG_WARN() << key << "is not a string in" << filename << "(skipping)";
|
||||
}
|
||||
else
|
||||
{
|
||||
variable = val.toString();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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"))
|
||||
{
|
||||
QJsonValue val = root.value("minimumLauncherVersion");
|
||||
if (!val.isDouble())
|
||||
{
|
||||
QLOG_WARN() << "minimumLauncherVersion is not an int in" << filename
|
||||
<< "(skipping)";
|
||||
}
|
||||
else
|
||||
{
|
||||
out.minimumLauncherVersion = val.toDouble();
|
||||
}
|
||||
}
|
||||
|
||||
if (root.contains("tweakers"))
|
||||
{
|
||||
QJsonValue tweakersVal = root.value("tweakers");
|
||||
if (!tweakersVal.isArray())
|
||||
{
|
||||
QLOG_ERROR() << filename << "contains a 'tweakers' field, but it's not an array";
|
||||
return out;
|
||||
}
|
||||
out.shouldOverwriteTweakers = true;
|
||||
QJsonArray tweakers = root.value("tweakers").toArray();
|
||||
for (auto tweakerVal : tweakers)
|
||||
{
|
||||
if (!tweakerVal.isString())
|
||||
{
|
||||
QLOG_ERROR() << filename << "contains a 'tweakers' field entry that's not a string";
|
||||
return out;
|
||||
}
|
||||
out.overwriteTweakers.append(tweakerVal.toString());
|
||||
}
|
||||
}
|
||||
if (root.contains("+tweakers"))
|
||||
{
|
||||
QJsonValue tweakersVal = root.value("+tweakers");
|
||||
if (!tweakersVal.isArray())
|
||||
{
|
||||
QLOG_ERROR() << filename << "contains a '+tweakers' field, but it's not an array";
|
||||
return out;
|
||||
}
|
||||
QJsonArray tweakers = root.value("+tweakers").toArray();
|
||||
for (auto tweakerVal : tweakers)
|
||||
{
|
||||
if (!tweakerVal.isString())
|
||||
{
|
||||
QLOG_ERROR() << filename << "contains a '+tweakers' field entry that's not a string";
|
||||
return out;
|
||||
}
|
||||
out.addTweakers.append(tweakerVal.toString());
|
||||
}
|
||||
}
|
||||
if (root.contains("-tweakers"))
|
||||
{
|
||||
QJsonValue tweakersVal = root.value("-tweakers");
|
||||
if (!tweakersVal.isArray())
|
||||
{
|
||||
QLOG_ERROR() << filename << "contains a '-tweakers' field, but it's not an array";
|
||||
return out;
|
||||
}
|
||||
out.shouldOverwriteTweakers = true;
|
||||
QJsonArray tweakers = root.value("-tweakers").toArray();
|
||||
for (auto tweakerVal : tweakers)
|
||||
{
|
||||
if (!tweakerVal.isString())
|
||||
{
|
||||
QLOG_ERROR() << filename << "contains a '-tweakers' field entry that's not a string";
|
||||
return out;
|
||||
}
|
||||
out.removeTweakers.append(tweakerVal.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (root.contains("libraries"))
|
||||
{
|
||||
out.shouldOverwriteLibs = true;
|
||||
QJsonValue librariesVal = root.value("libraries");
|
||||
if (!librariesVal.isArray())
|
||||
{
|
||||
QLOG_ERROR() << filename
|
||||
<< "contains a 'libraries' field, but its not an array";
|
||||
return out;
|
||||
}
|
||||
QJsonArray librariesArray = librariesVal.toArray();
|
||||
for (auto libVal : librariesArray)
|
||||
{
|
||||
if (!libVal.isObject())
|
||||
{
|
||||
QLOG_ERROR() << filename << "contains a library that's not an object";
|
||||
return out;
|
||||
}
|
||||
QJsonObject libObj = libVal.toObject();
|
||||
bool error;
|
||||
Library lib = fromLibraryJson(libObj, filename, error);
|
||||
if (error)
|
||||
{
|
||||
QLOG_ERROR() << "Error while reading a library entry in" << filename;
|
||||
return out;
|
||||
}
|
||||
out.overwriteLibs.append(lib);
|
||||
}
|
||||
}
|
||||
if (root.contains("+libraries"))
|
||||
{
|
||||
QJsonValue librariesVal = root.value("+libraries");
|
||||
if (!librariesVal.isArray())
|
||||
{
|
||||
QLOG_ERROR() << filename
|
||||
<< "contains a '+libraries' field, but its not an array";
|
||||
return out;
|
||||
}
|
||||
QJsonArray librariesArray = librariesVal.toArray();
|
||||
for (auto libVal : librariesArray)
|
||||
{
|
||||
if (!libVal.isObject())
|
||||
{
|
||||
QLOG_ERROR() << filename << "contains a library that's not an object";
|
||||
return out;
|
||||
}
|
||||
QJsonObject libObj = libVal.toObject();
|
||||
bool error;
|
||||
Library lib = fromLibraryJson(libObj, filename, error);
|
||||
if (error)
|
||||
{
|
||||
QLOG_ERROR() << "Error while reading a library entry in" << filename;
|
||||
return out;
|
||||
}
|
||||
if (!libObj.contains("insert"))
|
||||
{
|
||||
QLOG_ERROR() << "Missing 'insert' field in '+libraries' field in"
|
||||
<< filename;
|
||||
return out;
|
||||
}
|
||||
QJsonValue insertVal = libObj.value("insert");
|
||||
QString insertString;
|
||||
{
|
||||
if (insertVal.isString())
|
||||
{
|
||||
insertString = insertVal.toString();
|
||||
}
|
||||
else if (insertVal.isObject())
|
||||
{
|
||||
QJsonObject insertObj = insertVal.toObject();
|
||||
if (insertObj.isEmpty())
|
||||
{
|
||||
QLOG_ERROR() << "One library has an empty insert object in"
|
||||
<< filename;
|
||||
return out;
|
||||
}
|
||||
insertString = insertObj.keys().first();
|
||||
lib.insertData = insertObj.value(insertString).toString();
|
||||
}
|
||||
}
|
||||
if (insertString == "apply")
|
||||
{
|
||||
lib.insertType = Library::Apply;
|
||||
}
|
||||
else if (insertString == "append")
|
||||
{
|
||||
lib.insertType = Library::Append;
|
||||
}
|
||||
else if (insertString == "prepend")
|
||||
{
|
||||
lib.insertType = Library::Prepend;
|
||||
}
|
||||
else if (insertString == "prepend-if-not-exists")
|
||||
{
|
||||
lib.insertType = Library::PrependIfNotExists;
|
||||
}
|
||||
else if (insertString == "append-if-not-exists")
|
||||
{
|
||||
lib.insertType = Library::PrependIfNotExists;
|
||||
}
|
||||
else if (insertString == "replace")
|
||||
{
|
||||
lib.insertType = Library::Replace;
|
||||
}
|
||||
else
|
||||
{
|
||||
QLOG_ERROR() << "A '+' library in" << filename
|
||||
<< "contains an invalid insert type";
|
||||
return out;
|
||||
}
|
||||
out.addLibs.append(lib);
|
||||
}
|
||||
}
|
||||
if (root.contains("-libraries"))
|
||||
{
|
||||
QJsonValue librariesVal = root.value("-libraries");
|
||||
if (!librariesVal.isArray())
|
||||
{
|
||||
QLOG_ERROR() << filename
|
||||
<< "contains a '-libraries' field, but its not an array";
|
||||
return out;
|
||||
}
|
||||
QJsonArray librariesArray = librariesVal.toArray();
|
||||
for (auto libVal : librariesArray)
|
||||
{
|
||||
if (!libVal.isObject())
|
||||
{
|
||||
QLOG_ERROR() << filename << "contains a library that's not an object";
|
||||
return out;
|
||||
}
|
||||
QJsonObject libObj = libVal.toObject();
|
||||
if (!libObj.contains("name"))
|
||||
{
|
||||
QLOG_ERROR() << filename << "contains a library without a name";
|
||||
return out;
|
||||
}
|
||||
if (!libObj.value("name").isString())
|
||||
{
|
||||
QLOG_ERROR() << filename
|
||||
<< "contains a library without a valid 'name' field";
|
||||
return out;
|
||||
}
|
||||
out.removeLibs.append(libObj.value("name").toString());
|
||||
}
|
||||
}
|
||||
|
||||
isError = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::shared_ptr<OneSixLibrary> createLibrary(const Library &lib)
|
||||
{
|
||||
std::shared_ptr<OneSixLibrary> out(new OneSixLibrary(lib.name));
|
||||
out->setBaseUrl(lib.url);
|
||||
out->setHint(lib.hint);
|
||||
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 findLibrary(QList<std::shared_ptr<OneSixLibrary>> 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 applyTo(OneSixVersion *version, bool &isError)
|
||||
{
|
||||
isError = true;
|
||||
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 Library::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.insertData << "(skipping)";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Library::Append:
|
||||
version->libraries.append(createLibrary(lib));
|
||||
break;
|
||||
case Library::Prepend:
|
||||
version->libraries.prepend(createLibrary(lib));
|
||||
break;
|
||||
case Library::AppendIfNotExists:
|
||||
{
|
||||
|
||||
int index = findLibrary(version->libraries, lib.name);
|
||||
if (index < 0)
|
||||
{
|
||||
version->libraries.append(createLibrary(lib));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Library::PrependIfNotExists:
|
||||
{
|
||||
|
||||
int index = findLibrary(version->libraries, lib.name);
|
||||
if (index < 0)
|
||||
{
|
||||
version->libraries.prepend(createLibrary(lib));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Library::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)";
|
||||
}
|
||||
}
|
||||
|
||||
OneSixVersion::VersionFile versionFile;
|
||||
versionFile.name = name;
|
||||
versionFile.id = fileId;
|
||||
versionFile.version = this->version;
|
||||
versionFile.mcVersion = mcVersion;
|
||||
versionFile.filename = filename;
|
||||
version->versionFiles.append(versionFile);
|
||||
|
||||
isError = false;
|
||||
}
|
||||
};
|
||||
|
||||
OneSixVersionBuilder::OneSixVersionBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
bool OneSixVersionBuilder::build(OneSixVersion *version, OneSixInstance *instance,
|
||||
QWidget *widgetParent, const bool excludeCustom)
|
||||
{
|
||||
OneSixVersionBuilder builder;
|
||||
builder.m_version = version;
|
||||
builder.m_instance = instance;
|
||||
builder.m_widgetParent = widgetParent;
|
||||
return builder.build(excludeCustom);
|
||||
}
|
||||
|
||||
bool OneSixVersionBuilder::read(OneSixVersion *version, const QJsonObject &obj)
|
||||
{
|
||||
OneSixVersionBuilder builder;
|
||||
builder.m_version = version;
|
||||
builder.m_instance = 0;
|
||||
builder.m_widgetParent = 0;
|
||||
return builder.read(obj);
|
||||
}
|
||||
|
||||
bool OneSixVersionBuilder::build(const bool excludeCustom)
|
||||
{
|
||||
m_version->clear();
|
||||
|
||||
QDir root(m_instance->instanceRoot());
|
||||
QDir patches(root.absoluteFilePath("patches/"));
|
||||
|
||||
if (QFile::exists(root.absoluteFilePath("custom.json")))
|
||||
{
|
||||
QLOG_INFO() << "Reading custom.json";
|
||||
VersionFile file;
|
||||
if (!read(QFileInfo(root.absoluteFilePath("custom.json")), false, &file))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool isError = false;
|
||||
file.applyTo(m_version, isError);
|
||||
if (isError)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
m_widgetParent, QObject::tr("Error"),
|
||||
QObject::tr(
|
||||
"Error while applying %1. Please check MultiMC-0.log for more info.")
|
||||
.arg(root.absoluteFilePath("custom.json")));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// version.json -> patches/*.json -> instance.json
|
||||
|
||||
// version.json
|
||||
{
|
||||
QLOG_INFO() << "Reading version.json";
|
||||
VersionFile file;
|
||||
if (!read(QFileInfo(root.absoluteFilePath("version.json")), false, &file))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
file.name = "version.json";
|
||||
file.fileId = "org.multimc.version.json";
|
||||
file.version = m_instance->intendedVersionId();
|
||||
file.mcVersion = m_instance->intendedVersionId();
|
||||
bool isError = false;
|
||||
file.applyTo(m_version, isError);
|
||||
if (isError)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
m_widgetParent, QObject::tr("Error"),
|
||||
QObject::tr(
|
||||
"Error while applying %1. Please check MultiMC-0.log for more info.")
|
||||
.arg(root.absoluteFilePath("version.json")));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// patches/
|
||||
{
|
||||
// load all, put into map for ordering, apply in the right order
|
||||
|
||||
QMap<int, QPair<QString, VersionFile>> files;
|
||||
for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files))
|
||||
{
|
||||
QLOG_INFO() << "Reading" << info.fileName();
|
||||
VersionFile file;
|
||||
if (!read(info, true, &file))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
files.insert(file.order, qMakePair(info.fileName(), file));
|
||||
}
|
||||
for (auto order : files.keys())
|
||||
{
|
||||
QLOG_DEBUG() << "Applying file with order" << order;
|
||||
auto filePair = files[order];
|
||||
bool isError = false;
|
||||
filePair.second.applyTo(m_version, isError);
|
||||
if (isError)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
m_widgetParent, QObject::tr("Error"),
|
||||
QObject::tr(
|
||||
"Error while applying %1. Please check MultiMC-0.log for more info.")
|
||||
.arg(filePair.first));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// user.json
|
||||
if (!excludeCustom)
|
||||
{
|
||||
if (QFile::exists(root.absoluteFilePath("user.json")))
|
||||
{
|
||||
QLOG_INFO() << "Reading user.json";
|
||||
VersionFile file;
|
||||
if (!read(QFileInfo(root.absoluteFilePath("user.json")), false, &file))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
file.name = "user.json";
|
||||
file.fileId = "org.multimc.user.json";
|
||||
file.version = QString();
|
||||
file.mcVersion = QString();
|
||||
bool isError = false;
|
||||
file.applyTo(m_version, isError);
|
||||
if (isError)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
m_widgetParent, QObject::tr("Error"),
|
||||
QObject::tr(
|
||||
"Error while applying %1. Please check MultiMC-0.log for more info.")
|
||||
.arg(root.absoluteFilePath("user.json")));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// some final touches
|
||||
{
|
||||
if (m_version->assets.isEmpty())
|
||||
{
|
||||
m_version->assets = "legacy";
|
||||
}
|
||||
if (m_version->minecraftArguments.isEmpty())
|
||||
{
|
||||
QString toCompare = m_version->processArguments.toLower();
|
||||
if (toCompare == "legacy")
|
||||
{
|
||||
m_version->minecraftArguments = " ${auth_player_name} ${auth_session}";
|
||||
}
|
||||
else if (toCompare == "username_session")
|
||||
{
|
||||
m_version->minecraftArguments =
|
||||
"--username ${auth_player_name} --session ${auth_session}";
|
||||
}
|
||||
else if (toCompare == "username_session_version")
|
||||
{
|
||||
m_version->minecraftArguments = "--username ${auth_player_name} "
|
||||
"--session ${auth_session} "
|
||||
"--version ${profile_name}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OneSixVersionBuilder::read(const QJsonObject &obj)
|
||||
{
|
||||
m_version->clear();
|
||||
|
||||
bool isError = false;
|
||||
VersionFile file = VersionFile::fromJson(QJsonDocument(obj), QString(), false, isError);
|
||||
if (isError)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
m_widgetParent, QObject::tr("Error"),
|
||||
QObject::tr("Error while reading. Please check MultiMC-0.log for more info."));
|
||||
return false;
|
||||
}
|
||||
file.applyTo(m_version, isError);
|
||||
if (isError)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
m_widgetParent, QObject::tr("Error"),
|
||||
QObject::tr("Error while applying. Please check MultiMC-0.log for more info."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OneSixVersionBuilder::read(const QFileInfo &fileInfo, const bool requireOrder,
|
||||
VersionFile *out)
|
||||
{
|
||||
QFile file(fileInfo.absoluteFilePath());
|
||||
if (!file.open(QFile::ReadOnly))
|
||||
{
|
||||
QMessageBox::critical(
|
||||
m_widgetParent, QObject::tr("Error"),
|
||||
QObject::tr("Unable to open %1: %2").arg(file.fileName(), file.errorString()));
|
||||
return false;
|
||||
}
|
||||
QJsonParseError error;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
{
|
||||
QMessageBox::critical(m_widgetParent, QObject::tr("Error"),
|
||||
QObject::tr("Unable to parse %1: %2 at %3")
|
||||
.arg(file.fileName(), error.errorString())
|
||||
.arg(error.offset));
|
||||
return false;
|
||||
}
|
||||
bool isError = false;
|
||||
*out = VersionFile::fromJson(doc, file.fileName(), requireOrder, isError);
|
||||
if (isError)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
m_widgetParent, QObject::tr("Error"),
|
||||
QObject::tr("Error while reading %1. Please check MultiMC-0.log for more info.")
|
||||
.arg(file.fileName()));
|
||||
;
|
||||
}
|
||||
return true;
|
||||
}
|
43
logic/OneSixVersionBuilder.h
Normal file
43
logic/OneSixVersionBuilder.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
class OneSixVersion;
|
||||
class OneSixInstance;
|
||||
class QWidget;
|
||||
class QJsonObject;
|
||||
class QFileInfo;
|
||||
class VersionFile;
|
||||
|
||||
class OneSixVersionBuilder
|
||||
{
|
||||
OneSixVersionBuilder();
|
||||
public:
|
||||
static bool build(OneSixVersion *version, OneSixInstance *instance, QWidget *widgetParent, const bool excludeCustom);
|
||||
static bool read(OneSixVersion *version, const QJsonObject &obj);
|
||||
|
||||
private:
|
||||
OneSixVersion *m_version;
|
||||
OneSixInstance *m_instance;
|
||||
QWidget *m_widgetParent;
|
||||
|
||||
bool build(const bool excludeCustom);
|
||||
bool read(const QJsonObject &obj);
|
||||
|
||||
bool read(const QFileInfo &fileInfo, const bool requireOrder, VersionFile *out);
|
||||
};
|
Loading…
Reference in New Issue
Block a user