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.h
|
||||||
logic/LegacyForge.cpp
|
logic/LegacyForge.cpp
|
||||||
|
|
||||||
# 1.6 instances
|
# OneSix instances
|
||||||
logic/OneSixInstance.h
|
|
||||||
logic/OneSixInstance.cpp
|
|
||||||
logic/OneSixInstance_p.h
|
|
||||||
logic/OneSixUpdate.h
|
logic/OneSixUpdate.h
|
||||||
logic/OneSixUpdate.cpp
|
logic/OneSixUpdate.cpp
|
||||||
logic/OneSixVersion.h
|
logic/OneSixVersion.h
|
||||||
@ -425,10 +422,17 @@ logic/OneSixRule.h
|
|||||||
logic/OneSixRule.cpp
|
logic/OneSixRule.cpp
|
||||||
logic/OpSys.h
|
logic/OpSys.h
|
||||||
logic/OpSys.cpp
|
logic/OpSys.cpp
|
||||||
|
logic/BaseInstaller.h
|
||||||
|
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
|
||||||
|
@ -55,7 +55,8 @@ OneSixModEditDialog::OneSixModEditDialog(OneSixInstance *inst, QWidget *parent)
|
|||||||
main_model->setSourceModel(m_version.get());
|
main_model->setSourceModel(m_version.get());
|
||||||
ui->libraryTreeView->setModel(main_model);
|
ui->libraryTreeView->setModel(main_model);
|
||||||
ui->libraryTreeView->installEventFilter(this);
|
ui->libraryTreeView->installEventFilter(this);
|
||||||
ui->mainClassEdit->setText(m_version->mainClass);
|
connect(ui->libraryTreeView->selectionModel(), &QItemSelectionModel::currentChanged,
|
||||||
|
this, &OneSixModEditDialog::versionCurrent);
|
||||||
updateVersionControls();
|
updateVersionControls();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -81,6 +82,8 @@ OneSixModEditDialog::OneSixModEditDialog(OneSixInstance *inst, QWidget *parent)
|
|||||||
ui->resPackTreeView->installEventFilter(this);
|
ui->resPackTreeView->installEventFilter(this);
|
||||||
m_resourcepacks->startWatching();
|
m_resourcepacks->startWatching();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect(m_inst, &OneSixInstance::versionReloaded, this, &OneSixModEditDialog::updateVersionControls);
|
||||||
}
|
}
|
||||||
|
|
||||||
OneSixModEditDialog::~OneSixModEditDialog()
|
OneSixModEditDialog::~OneSixModEditDialog()
|
||||||
@ -92,98 +95,76 @@ OneSixModEditDialog::~OneSixModEditDialog()
|
|||||||
|
|
||||||
void OneSixModEditDialog::updateVersionControls()
|
void OneSixModEditDialog::updateVersionControls()
|
||||||
{
|
{
|
||||||
bool customVersion = m_inst->versionIsCustom();
|
|
||||||
ui->customizeBtn->setEnabled(!customVersion);
|
|
||||||
ui->revertBtn->setEnabled(customVersion);
|
|
||||||
ui->forgeBtn->setEnabled(true);
|
ui->forgeBtn->setEnabled(true);
|
||||||
ui->liteloaderBtn->setEnabled(LiteLoaderInstaller(m_inst->intendedVersionId()).canApply());
|
ui->liteloaderBtn->setEnabled(LiteLoaderInstaller().canApply(m_inst));
|
||||||
ui->customEditorBtn->setEnabled(customVersion);
|
ui->mainClassEdit->setText(m_version->mainClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixModEditDialog::disableVersionControls()
|
void OneSixModEditDialog::disableVersionControls()
|
||||||
{
|
{
|
||||||
ui->customizeBtn->setEnabled(false);
|
|
||||||
ui->revertBtn->setEnabled(false);
|
|
||||||
ui->forgeBtn->setEnabled(false);
|
ui->forgeBtn->setEnabled(false);
|
||||||
ui->liteloaderBtn->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();
|
QFile file(root.absoluteFilePath("user.json"));
|
||||||
main_model->setSourceModel(m_version.get());
|
if (!file.open(QFile::WriteOnly))
|
||||||
updateVersionControls();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OneSixModEditDialog::on_revertBtn_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();
|
QMessageBox::critical(this, tr("Error"), tr("Couldn't write a skeletion user.json file: %1").arg(file.errorString()));
|
||||||
main_model->setSourceModel(m_version.get());
|
return;
|
||||||
updateVersionControls();
|
|
||||||
}
|
}
|
||||||
|
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_customEditorBtn_clicked()
|
void OneSixModEditDialog::on_reloadLibrariesBtn_clicked()
|
||||||
{
|
{
|
||||||
if (m_inst->versionIsCustom())
|
m_inst->reloadVersion(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OneSixModEditDialog::on_removeLibraryBtn_clicked()
|
||||||
|
{
|
||||||
|
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"),
|
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
|
||||||
tr("Unable to open custom.json, check the settings"));
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_inst->reloadVersion(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixModEditDialog::on_forgeBtn_clicked()
|
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);
|
VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this);
|
||||||
vselect.setFilter(1, m_inst->currentVersionId());
|
vselect.setFilter(1, m_inst->currentVersionId());
|
||||||
vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") +
|
vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") +
|
||||||
m_inst->currentVersionId());
|
m_inst->currentVersionId());
|
||||||
if (vselect.exec() && vselect.selectedVersion())
|
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 =
|
ForgeVersionPtr forgeVersion =
|
||||||
std::dynamic_pointer_cast<ForgeVersion>(vselect.selectedVersion());
|
std::dynamic_pointer_cast<ForgeVersion>(vselect.selectedVersion());
|
||||||
if (!forgeVersion)
|
if (!forgeVersion)
|
||||||
@ -200,9 +181,9 @@ void OneSixModEditDialog::on_forgeBtn_clicked()
|
|||||||
// install
|
// install
|
||||||
QString forgePath = entry->getFullPath();
|
QString forgePath = entry->getFullPath();
|
||||||
ForgeInstaller forge(forgePath, forgeVersion->universal_url);
|
ForgeInstaller forge(forgePath, forgeVersion->universal_url);
|
||||||
if (!forge.apply(m_version))
|
if (!forge.add(m_inst))
|
||||||
{
|
{
|
||||||
// failure notice
|
QLOG_ERROR() << "Failure installing forge";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -215,18 +196,27 @@ void OneSixModEditDialog::on_forgeBtn_clicked()
|
|||||||
// install
|
// install
|
||||||
QString forgePath = entry->getFullPath();
|
QString forgePath = entry->getFullPath();
|
||||||
ForgeInstaller forge(forgePath, forgeVersion->universal_url);
|
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()
|
void OneSixModEditDialog::on_liteloaderBtn_clicked()
|
||||||
{
|
{
|
||||||
LiteLoaderInstaller liteloader(m_inst->intendedVersionId());
|
if (QDir(m_inst->instanceRoot()).exists("custom.json"))
|
||||||
if (!liteloader.canApply())
|
{
|
||||||
|
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(
|
QMessageBox::critical(
|
||||||
this, tr("LiteLoader"),
|
this, tr("LiteLoader"),
|
||||||
@ -234,19 +224,16 @@ void OneSixModEditDialog::on_liteloaderBtn_clicked()
|
|||||||
"into this version of Minecraft"));
|
"into this version of Minecraft"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!m_inst->versionIsCustom())
|
if (!liteloader.add(m_inst))
|
||||||
{
|
|
||||||
m_inst->customizeVersion();
|
|
||||||
m_version = m_inst->getFullVersion();
|
|
||||||
main_model->setSourceModel(m_version.get());
|
|
||||||
updateVersionControls();
|
|
||||||
}
|
|
||||||
if (!liteloader.apply(m_version))
|
|
||||||
{
|
{
|
||||||
QMessageBox::critical(this, tr("LiteLoader"),
|
QMessageBox::critical(this, tr("LiteLoader"),
|
||||||
tr("For reasons unknown, the LiteLoader installation failed. "
|
tr("For reasons unknown, the LiteLoader installation failed. "
|
||||||
"Check your MultiMC log files for details."));
|
"Check your MultiMC log files for details."));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_inst->reloadVersion(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OneSixModEditDialog::loaderListFilter(QKeyEvent *keyEvent)
|
bool OneSixModEditDialog::loaderListFilter(QKeyEvent *keyEvent)
|
||||||
@ -365,3 +352,15 @@ void OneSixModEditDialog::loaderCurrent(QModelIndex current, QModelIndex previou
|
|||||||
Mod &m = m_mods->operator[](row);
|
Mod &m = m_mods->operator[](row);
|
||||||
ui->frame->updateWithMod(m);
|
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_buttonBox_rejected();
|
||||||
void on_forgeBtn_clicked();
|
void on_forgeBtn_clicked();
|
||||||
void on_liteloaderBtn_clicked();
|
void on_liteloaderBtn_clicked();
|
||||||
void on_customizeBtn_clicked();
|
void on_userEditorBtn_clicked();
|
||||||
void on_revertBtn_clicked();
|
void on_reloadLibrariesBtn_clicked();
|
||||||
void on_customEditorBtn_clicked();
|
void on_removeLibraryBtn_clicked();
|
||||||
void updateVersionControls();
|
void updateVersionControls();
|
||||||
void disableVersionControls();
|
void disableVersionControls();
|
||||||
|
|
||||||
@ -66,4 +66,5 @@ private:
|
|||||||
public
|
public
|
||||||
slots:
|
slots:
|
||||||
void loaderCurrent(QModelIndex current, QModelIndex previous);
|
void loaderCurrent(QModelIndex current, QModelIndex previous);
|
||||||
|
void versionCurrent(const QModelIndex ¤t, const QModelIndex &previous);
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>1</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="libTab">
|
<widget class="QWidget" name="libTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
@ -43,6 +43,9 @@
|
|||||||
<property name="horizontalScrollBarPolicy">
|
<property name="horizontalScrollBarPolicy">
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<attribute name="headerVisible">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -84,62 +87,24 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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>
|
<item>
|
||||||
<widget class="Line" name="line">
|
<widget class="Line" name="line">
|
||||||
<property name="frameShadow">
|
|
||||||
<enum>QFrame::Sunken</enum>
|
|
||||||
</property>
|
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="addLibraryBtn">
|
<widget class="QPushButton" name="reloadLibrariesBtn">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Add new libraries</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Add</string>
|
<string>Reload</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="removeLibraryBtn">
|
<widget class="QPushButton" name="removeLibraryBtn">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Remove selected libraries</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Remove</string>
|
<string>Remove</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -151,9 +116,9 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="customEditorBtn">
|
<widget class="QPushButton" name="userEditorBtn">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Open custom.json</string>
|
<string>Open user.json</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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 <quazipfile.h>
|
||||||
#include <pathutils.h>
|
#include <pathutils.h>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QRegularExpressionMatch>
|
||||||
#include "MultiMC.h"
|
#include "MultiMC.h"
|
||||||
|
#include "OneSixInstance.h"
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QSaveFile>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
|
ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
|
||||||
{
|
{
|
||||||
@ -66,6 +74,7 @@ ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
|
|||||||
QJsonObject installObj = installVal.toObject();
|
QJsonObject installObj = installVal.toObject();
|
||||||
QString libraryName = installObj.value("path").toString();
|
QString libraryName = installObj.value("path").toString();
|
||||||
internalPath = installObj.value("filePath").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
|
// where do we put the library? decode the mojang path
|
||||||
OneSixLibrary lib(libraryName);
|
OneSixLibrary lib(libraryName);
|
||||||
@ -103,13 +112,22 @@ ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
|
|||||||
realVersionId = m_forge_version->id = installObj.value("minecraft").toString();
|
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)
|
if (!m_forge_version)
|
||||||
return false;
|
return false;
|
||||||
to->externalUpdateStart();
|
|
||||||
int sliding_insert_window = 0;
|
int sliding_insert_window = 0;
|
||||||
{
|
{
|
||||||
|
QJsonArray librariesPlus;
|
||||||
|
|
||||||
// for each library in the version we are adding (except for the blacklisted)
|
// for each library in the version we are adding (except for the blacklisted)
|
||||||
QSet<QString> blacklist{"lwjgl", "lwjgl_util", "lwjgl-platform"};
|
QSet<QString> blacklist{"lwjgl", "lwjgl_util", "lwjgl-platform"};
|
||||||
for (auto lib : m_forge_version->libraries)
|
for (auto lib : m_forge_version->libraries)
|
||||||
@ -128,28 +146,79 @@ bool ForgeInstaller::apply(std::shared_ptr<OneSixVersion> to)
|
|||||||
if (blacklist.contains(libName))
|
if (blacklist.contains(libName))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// find an entry that matches this one
|
QJsonObject libObj = lib->toJson();
|
||||||
|
|
||||||
bool found = false;
|
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)
|
if (tolib->name() != libName)
|
||||||
continue;
|
continue;
|
||||||
found = true;
|
found = true;
|
||||||
|
if (tolib->toJson() == libObj)
|
||||||
|
{
|
||||||
|
equals = true;
|
||||||
|
}
|
||||||
// replace lib
|
// replace lib
|
||||||
tolib = lib;
|
libObj.insert("insert", QString("replace"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (equals)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
// add lib
|
// add lib
|
||||||
to->libraries.insert(sliding_insert_window, lib);
|
libObj.insert("insert", QString("prepend-if-not-exists"));
|
||||||
sliding_insert_window++;
|
sliding_insert_window++;
|
||||||
}
|
}
|
||||||
|
librariesPlus.prepend(libObj);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
to->mainClass = m_forge_version->mainClass;
|
|
||||||
to->minecraftArguments = m_forge_version->minecraftArguments;
|
|
||||||
to->processArguments = m_forge_version->processArguments;
|
|
||||||
}
|
}
|
||||||
to->externalUpdateFinish();
|
|
||||||
return to->toOriginalFile();
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include "BaseInstaller.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class OneSixVersion;
|
class OneSixVersion;
|
||||||
|
|
||||||
class ForgeInstaller
|
class ForgeInstaller : public BaseInstaller
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ForgeInstaller(QString filename, QString universal_url);
|
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:
|
private:
|
||||||
// the version, read from the installer
|
// the version, read from the installer
|
||||||
@ -32,5 +37,6 @@ private:
|
|||||||
QString internalPath;
|
QString internalPath;
|
||||||
QString finalPath;
|
QString finalPath;
|
||||||
QString realVersionId;
|
QString realVersionId;
|
||||||
|
QString m_forgeVersionString;
|
||||||
QString m_universal_url;
|
QString m_universal_url;
|
||||||
};
|
};
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "OneSixInstance.h"
|
#include "OneSixInstance.h"
|
||||||
#include "OneSixFTBInstance.h"
|
#include "OneSixFTBInstance.h"
|
||||||
#include "NostalgiaInstance.h"
|
#include "NostalgiaInstance.h"
|
||||||
|
#include "OneSixInstance.h"
|
||||||
#include "BaseVersion.h"
|
#include "BaseVersion.h"
|
||||||
#include "MinecraftVersion.h"
|
#include "MinecraftVersion.h"
|
||||||
|
|
||||||
@ -50,14 +51,14 @@ InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst
|
|||||||
QString inst_type = m_settings->get("InstanceType").toString();
|
QString inst_type = m_settings->get("InstanceType").toString();
|
||||||
|
|
||||||
// FIXME: replace with a map lookup, where instance classes register their types
|
// FIXME: replace with a map lookup, where instance classes register their types
|
||||||
if (inst_type == "Legacy")
|
if (inst_type == "OneSix")
|
||||||
{
|
|
||||||
inst = new LegacyInstance(instDir, m_settings, this);
|
|
||||||
}
|
|
||||||
else if (inst_type == "OneSix")
|
|
||||||
{
|
{
|
||||||
inst = new OneSixInstance(instDir, m_settings, this);
|
inst = new OneSixInstance(instDir, m_settings, this);
|
||||||
}
|
}
|
||||||
|
else if (inst_type == "Legacy")
|
||||||
|
{
|
||||||
|
inst = new LegacyInstance(instDir, m_settings, this);
|
||||||
|
}
|
||||||
else if (inst_type == "Nostalgia")
|
else if (inst_type == "Nostalgia")
|
||||||
{
|
{
|
||||||
inst = new NostalgiaInstance(instDir, m_settings, this);
|
inst = new NostalgiaInstance(instDir, m_settings, this);
|
||||||
@ -101,6 +102,7 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(BaseInstance *&
|
|||||||
switch (mcVer->type)
|
switch (mcVer->type)
|
||||||
{
|
{
|
||||||
case MinecraftVersion::Legacy:
|
case MinecraftVersion::Legacy:
|
||||||
|
// TODO new instance type
|
||||||
m_settings->set("InstanceType", "Legacy");
|
m_settings->set("InstanceType", "Legacy");
|
||||||
inst = new LegacyInstance(instDir, m_settings, this);
|
inst = new LegacyInstance(instDir, m_settings, this);
|
||||||
inst->setIntendedVersionId(version->descriptor());
|
inst->setIntendedVersionId(version->descriptor());
|
||||||
|
@ -15,12 +15,19 @@
|
|||||||
|
|
||||||
#include "LiteLoaderInstaller.h"
|
#include "LiteLoaderInstaller.h"
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
|
#include "logger/QsLog.h"
|
||||||
|
|
||||||
#include "OneSixVersion.h"
|
#include "OneSixVersion.h"
|
||||||
#include "OneSixLibrary.h"
|
#include "OneSixLibrary.h"
|
||||||
|
#include "OneSixInstance.h"
|
||||||
|
|
||||||
QMap<QString, QString> LiteLoaderInstaller::m_launcherWrapperVersionMapping;
|
QMap<QString, QString> LiteLoaderInstaller::m_launcherWrapperVersionMapping;
|
||||||
|
|
||||||
LiteLoaderInstaller::LiteLoaderInstaller(const QString &mcVersion) : m_mcVersion(mcVersion)
|
LiteLoaderInstaller::LiteLoaderInstaller()
|
||||||
|
: BaseInstaller()
|
||||||
{
|
{
|
||||||
if (m_launcherWrapperVersionMapping.isEmpty())
|
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();
|
if (!BaseInstaller::add(to))
|
||||||
|
|
||||||
applyLaunchwrapper(to);
|
|
||||||
applyLiteLoader(to);
|
|
||||||
|
|
||||||
to->mainClass = "net.minecraft.launchwrapper.Launch";
|
|
||||||
if (!to->minecraftArguments.contains(
|
|
||||||
" --tweakClass com.mumfrey.liteloader.launch.LiteLoaderTweaker"))
|
|
||||||
{
|
{
|
||||||
to->minecraftArguments.append(
|
return false;
|
||||||
" --tweakClass com.mumfrey.liteloader.launch.LiteLoaderTweaker");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
to->externalUpdateFinish();
|
QJsonObject obj;
|
||||||
return to->toOriginalFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LiteLoaderInstaller::applyLaunchwrapper(std::shared_ptr<OneSixVersion> to)
|
obj.insert("mainClass", QString("net.minecraft.launchwrapper.Launch"));
|
||||||
{
|
obj.insert("+tweakers", QJsonArray::fromStringList(QStringList() << "com.mumfrey.liteloader.launch.LiteLoaderTweaker"));
|
||||||
const QString intendedVersion = m_launcherWrapperVersionMapping[m_mcVersion];
|
obj.insert("order", 10);
|
||||||
|
|
||||||
QMutableListIterator<std::shared_ptr<OneSixLibrary>> it(to->libraries);
|
QJsonArray libraries;
|
||||||
while (it.hasNext())
|
|
||||||
|
// launchwrapper
|
||||||
{
|
{
|
||||||
it.next();
|
OneSixLibrary launchwrapperLib("net.minecraft:launchwrapper:" + m_launcherWrapperVersionMapping[to->intendedVersionId()]);
|
||||||
if (it.value()->rawName().startsWith("net.minecraft:launchwrapper:"))
|
launchwrapperLib.finalize();
|
||||||
{
|
QJsonObject lwLibObj = launchwrapperLib.toJson();
|
||||||
if (it.value()->version() >= intendedVersion)
|
lwLibObj.insert("insert", QString("prepend-if-not-exists"));
|
||||||
{
|
libraries.append(lwLibObj);
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<OneSixLibrary> lib(new OneSixLibrary(
|
// liteloader
|
||||||
"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();
|
OneSixLibrary liteloaderLib("com.mumfrey:liteloader:" + to->intendedVersionId());
|
||||||
if (it.value()->rawName().startsWith("com.mumfrey:liteloader:"))
|
liteloaderLib.setBaseUrl("http://dl.liteloader.com/versions/");
|
||||||
{
|
liteloaderLib.finalize();
|
||||||
it.remove();
|
QJsonObject llLibObj = liteloaderLib.toJson();
|
||||||
}
|
llLibObj.insert("insert", QString("prepend"));
|
||||||
|
libraries.append(llLibObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<OneSixLibrary> lib(
|
obj.insert("+libraries", libraries);
|
||||||
new OneSixLibrary("com.mumfrey:liteloader:" + m_mcVersion));
|
obj.insert("name", QString("LiteLoader"));
|
||||||
lib->setBaseUrl("http://dl.liteloader.com/versions/");
|
obj.insert("fileId", id());
|
||||||
lib->finalize();
|
obj.insert("version", to->intendedVersionId());
|
||||||
to->libraries.prepend(lib);
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include "BaseInstaller.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class OneSixVersion;
|
class LiteLoaderInstaller : public BaseInstaller
|
||||||
|
|
||||||
class LiteLoaderInstaller
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LiteLoaderInstaller(const QString &mcVersion);
|
LiteLoaderInstaller();
|
||||||
|
|
||||||
bool canApply() const;
|
bool canApply(OneSixInstance *instance) const override;
|
||||||
|
bool add(OneSixInstance *to) override;
|
||||||
bool apply(std::shared_ptr<OneSixVersion> to);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_mcVersion;
|
virtual QString id() const override { return "com.mumfrey.liteloader"; }
|
||||||
|
|
||||||
void applyLaunchwrapper(std::shared_ptr<OneSixVersion> to);
|
|
||||||
void applyLiteLoader(std::shared_ptr<OneSixVersion> to);
|
|
||||||
|
|
||||||
static QMap<QString, QString> m_launcherWrapperVersionMapping;
|
static QMap<QString, QString> m_launcherWrapperVersionMapping;
|
||||||
};
|
};
|
||||||
|
@ -55,15 +55,13 @@ slots:
|
|||||||
setStatus(tr("Installing Forge..."));
|
setStatus(tr("Installing Forge..."));
|
||||||
QString forgePath = entry->getFullPath();
|
QString forgePath = entry->getFullPath();
|
||||||
ForgeInstaller forge(forgePath, forgeVersion->universal_url);
|
ForgeInstaller forge(forgePath, forgeVersion->universal_url);
|
||||||
if (!instance->reloadFullVersion())
|
if (!instance->reloadVersion())
|
||||||
{
|
{
|
||||||
emitFailed(tr("Couldn't load the version config"));
|
emitFailed(tr("Couldn't load the version config"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
instance->revertCustomVersion();
|
|
||||||
instance->customizeVersion();
|
|
||||||
auto version = instance->getFullVersion();
|
auto version = instance->getFullVersion();
|
||||||
if (!forge.apply(version))
|
if (!forge.add(instance))
|
||||||
{
|
{
|
||||||
emitFailed(tr("Couldn't install Forge"));
|
emitFailed(tr("Couldn't install Forge"));
|
||||||
return;
|
return;
|
||||||
|
@ -13,32 +13,37 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "MultiMC.h"
|
|
||||||
#include "OneSixInstance.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>
|
#include <QIcon>
|
||||||
|
|
||||||
OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *setting_obj,
|
#include "OneSixInstance_p.h"
|
||||||
QObject *parent)
|
#include "OneSixUpdate.h"
|
||||||
: BaseInstance(new OneSixInstancePrivate(), rootDir, setting_obj, parent)
|
#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);
|
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);
|
||||||
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()
|
std::shared_ptr<Task> OneSixInstance::doUpdate()
|
||||||
@ -135,6 +140,10 @@ QStringList OneSixInstance::processMinecraftArgs(AuthSessionPtr session)
|
|||||||
I_D(OneSixInstance);
|
I_D(OneSixInstance);
|
||||||
auto version = d->version;
|
auto version = d->version;
|
||||||
QString args_pattern = version->minecraftArguments;
|
QString args_pattern = version->minecraftArguments;
|
||||||
|
for (auto tweaker : version->tweakers)
|
||||||
|
{
|
||||||
|
args_pattern += " --tweakClass " + tweaker;
|
||||||
|
}
|
||||||
|
|
||||||
QMap<QString, QString> token_mapping;
|
QMap<QString, QString> token_mapping;
|
||||||
// yggdrasil!
|
// yggdrasil!
|
||||||
@ -267,11 +276,8 @@ bool OneSixInstance::setIntendedVersionId(QString version)
|
|||||||
{
|
{
|
||||||
settings().set("IntendedVersion", version);
|
settings().set("IntendedVersion", version);
|
||||||
setShouldUpdate(true);
|
setShouldUpdate(true);
|
||||||
auto pathCustom = PathCombine(instanceRoot(), "custom.json");
|
QFile::remove(PathCombine(instanceRoot(), "version.json"));
|
||||||
auto pathOrig = PathCombine(instanceRoot(), "version.json");
|
clearVersion();
|
||||||
QFile::remove(pathCustom);
|
|
||||||
QFile::remove(pathOrig);
|
|
||||||
reloadFullVersion();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,9 +303,10 @@ bool OneSixInstance::shouldUpdate() const
|
|||||||
|
|
||||||
bool OneSixInstance::versionIsCustom()
|
bool OneSixInstance::versionIsCustom()
|
||||||
{
|
{
|
||||||
QString verpath_custom = PathCombine(instanceRoot(), "custom.json");
|
QDir patches(PathCombine(instanceRoot(), "patches/"));
|
||||||
QFile versionfile(verpath_custom);
|
return (patches.exists() && patches.count() >= 0)
|
||||||
return versionfile.exists();
|
|| QFile::exists(PathCombine(instanceRoot(), "custom.json"))
|
||||||
|
|| QFile::exists(PathCombine(instanceRoot(), "user.json"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString OneSixInstance::currentVersionId() const
|
QString OneSixInstance::currentVersionId() const
|
||||||
@ -307,62 +314,39 @@ QString OneSixInstance::currentVersionId() const
|
|||||||
return intendedVersionId();
|
return intendedVersionId();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OneSixInstance::customizeVersion()
|
bool OneSixInstance::reloadVersion(QWidget *widgetParent)
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
I_D(OneSixInstance);
|
I_D(OneSixInstance);
|
||||||
|
|
||||||
QString verpath = PathCombine(instanceRoot(), "version.json");
|
bool ret = d->version->reload(widgetParent);
|
||||||
|
if (ret)
|
||||||
{
|
{
|
||||||
QString verpath_custom = PathCombine(instanceRoot(), "custom.json");
|
ret = d->nonCustomVersion->reload(widgetParent, true);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
emit versionReloaded();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<OneSixVersion> OneSixInstance::getFullVersion()
|
void OneSixInstance::clearVersion()
|
||||||
{
|
{
|
||||||
I_D(OneSixInstance);
|
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;
|
return d->version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<OneSixVersion> OneSixInstance::getNonCustomVersion() const
|
||||||
|
{
|
||||||
|
I_D(const OneSixInstance);
|
||||||
|
return d->nonCustomVersion;
|
||||||
|
}
|
||||||
|
|
||||||
QString OneSixInstance::defaultBaseJar() const
|
QString OneSixInstance::defaultBaseJar() const
|
||||||
{
|
{
|
||||||
return "versions/" + intendedVersionId() + "/" + intendedVersionId() + ".jar";
|
return "versions/" + intendedVersionId() + "/" + intendedVersionId() + ".jar";
|
||||||
@ -382,7 +366,7 @@ bool OneSixInstance::menuActionEnabled(QString action_name) const
|
|||||||
|
|
||||||
QString OneSixInstance::getStatusbarDescription()
|
QString OneSixInstance::getStatusbarDescription()
|
||||||
{
|
{
|
||||||
QString descr = "One Six : " + intendedVersionId();
|
QString descr = "OneSix : " + intendedVersionId();
|
||||||
if (versionIsCustom())
|
if (versionIsCustom())
|
||||||
{
|
{
|
||||||
descr + " (custom)";
|
descr + " (custom)";
|
||||||
|
@ -15,21 +15,17 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QDir>
|
|
||||||
|
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
|
|
||||||
class OneSixVersion;
|
#include "OneSixVersion.h"
|
||||||
class Task;
|
#include "ModList.h"
|
||||||
class ModList;
|
|
||||||
|
|
||||||
class OneSixInstance : public BaseInstance
|
class OneSixInstance : public BaseInstance
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit OneSixInstance(const QString &rootDir, SettingsObject *settings,
|
explicit OneSixInstance(const QString &rootDir, SettingsObject *settings,
|
||||||
QObject *parent = 0);
|
QObject *parent = 0);
|
||||||
|
|
||||||
////// Mod Lists //////
|
////// Mod Lists //////
|
||||||
std::shared_ptr<ModList> loaderModList();
|
std::shared_ptr<ModList> loaderModList();
|
||||||
@ -55,14 +51,14 @@ public:
|
|||||||
|
|
||||||
virtual QDialog *createModEditDialog(QWidget *parent) override;
|
virtual QDialog *createModEditDialog(QWidget *parent) override;
|
||||||
|
|
||||||
/// reload the full version json file. return true on success!
|
/// reload the full version json files. return true on success!
|
||||||
bool reloadFullVersion();
|
bool reloadVersion(QWidget *widgetParent = 0);
|
||||||
|
/// clears all version information in preparation for an update
|
||||||
|
void clearVersion();
|
||||||
/// get the current full version info
|
/// get the current full version info
|
||||||
std::shared_ptr<OneSixVersion> getFullVersion();
|
std::shared_ptr<OneSixVersion> getFullVersion() const;
|
||||||
/// revert the current custom version back to base
|
/// gets the current version info, excluding custom.json
|
||||||
bool revertCustomVersion();
|
std::shared_ptr<OneSixVersion> getNonCustomVersion() const;
|
||||||
/// customize the current base version
|
|
||||||
bool customizeVersion();
|
|
||||||
/// is the current version original, or custom?
|
/// is the current version original, or custom?
|
||||||
virtual bool versionIsCustom() override;
|
virtual bool versionIsCustom() override;
|
||||||
|
|
||||||
@ -72,6 +68,9 @@ public:
|
|||||||
virtual bool menuActionEnabled(QString action_name) const override;
|
virtual bool menuActionEnabled(QString action_name) const override;
|
||||||
virtual QString getStatusbarDescription() override;
|
virtual QString getStatusbarDescription() override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void versionReloaded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList processMinecraftArgs(AuthSessionPtr account);
|
QStringList processMinecraftArgs(AuthSessionPtr account);
|
||||||
QDir reconstructAssets(std::shared_ptr<OneSixVersion> version);
|
QDir reconstructAssets(std::shared_ptr<OneSixVersion> version);
|
||||||
|
@ -15,16 +15,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include "BaseInstance_p.h"
|
||||||
|
#include "OneSixVersion.h"
|
||||||
#include "logic/BaseInstance_p.h"
|
#include "ModList.h"
|
||||||
#include "logic/OneSixVersion.h"
|
|
||||||
#include "logic/OneSixLibrary.h"
|
|
||||||
#include "logic/ModList.h"
|
|
||||||
|
|
||||||
struct OneSixInstancePrivate : public BaseInstancePrivate
|
struct OneSixInstancePrivate : public BaseInstancePrivate
|
||||||
{
|
{
|
||||||
std::shared_ptr<OneSixVersion> version;
|
std::shared_ptr<OneSixVersion> version;
|
||||||
|
std::shared_ptr<OneSixVersion> nonCustomVersion;
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
@ -76,11 +76,11 @@ void OneSixLibrary::finalize()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixLibrary::setName(QString name)
|
void OneSixLibrary::setName(const QString &name)
|
||||||
{
|
{
|
||||||
m_name = name;
|
m_name = name;
|
||||||
}
|
}
|
||||||
void OneSixLibrary::setBaseUrl(QString base_url)
|
void OneSixLibrary::setBaseUrl(const QString &base_url)
|
||||||
{
|
{
|
||||||
m_base_url = base_url;
|
m_base_url = base_url;
|
||||||
}
|
}
|
||||||
@ -88,50 +88,54 @@ void OneSixLibrary::setIsNative()
|
|||||||
{
|
{
|
||||||
m_is_native = true;
|
m_is_native = true;
|
||||||
}
|
}
|
||||||
void OneSixLibrary::addNative(OpSys os, QString suffix)
|
void OneSixLibrary::addNative(OpSys os, const QString &suffix)
|
||||||
{
|
{
|
||||||
m_is_native = true;
|
m_is_native = true;
|
||||||
m_native_suffixes[os] = suffix;
|
m_native_suffixes[os] = suffix;
|
||||||
}
|
}
|
||||||
|
void OneSixLibrary::clearSuffixes()
|
||||||
|
{
|
||||||
|
m_native_suffixes.clear();
|
||||||
|
}
|
||||||
void OneSixLibrary::setRules(QList<std::shared_ptr<Rule>> rules)
|
void OneSixLibrary::setRules(QList<std::shared_ptr<Rule>> rules)
|
||||||
{
|
{
|
||||||
m_rules = rules;
|
m_rules = rules;
|
||||||
}
|
}
|
||||||
bool OneSixLibrary::isActive()
|
bool OneSixLibrary::isActive() const
|
||||||
{
|
{
|
||||||
return m_is_active;
|
return m_is_active;
|
||||||
}
|
}
|
||||||
bool OneSixLibrary::isNative()
|
bool OneSixLibrary::isNative() const
|
||||||
{
|
{
|
||||||
return m_is_native;
|
return m_is_native;
|
||||||
}
|
}
|
||||||
QString OneSixLibrary::downloadUrl()
|
QString OneSixLibrary::downloadUrl() const
|
||||||
{
|
{
|
||||||
if (m_absolute_url.size())
|
if (m_absolute_url.size())
|
||||||
return m_absolute_url;
|
return m_absolute_url;
|
||||||
return m_download_url;
|
return m_download_url;
|
||||||
}
|
}
|
||||||
QString OneSixLibrary::storagePath()
|
QString OneSixLibrary::storagePath() const
|
||||||
{
|
{
|
||||||
return m_storage_path;
|
return m_storage_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixLibrary::setAbsoluteUrl(QString absolute_url)
|
void OneSixLibrary::setAbsoluteUrl(const QString &absolute_url)
|
||||||
{
|
{
|
||||||
m_absolute_url = absolute_url;
|
m_absolute_url = absolute_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString OneSixLibrary::absoluteUrl()
|
QString OneSixLibrary::absoluteUrl() const
|
||||||
{
|
{
|
||||||
return m_absolute_url;
|
return m_absolute_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixLibrary::setHint(QString hint)
|
void OneSixLibrary::setHint(const QString &hint)
|
||||||
{
|
{
|
||||||
m_hint = hint;
|
m_hint = hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString OneSixLibrary::hint()
|
QString OneSixLibrary::hint() const
|
||||||
{
|
{
|
||||||
return m_hint;
|
return m_hint;
|
||||||
}
|
}
|
||||||
@ -176,7 +180,7 @@ bool OneSixLibrary::extractTo(QString target_dir)
|
|||||||
cooked_storage.replace("${arch}", "32");
|
cooked_storage.replace("${arch}", "32");
|
||||||
QString origin = PathCombine("libraries", cooked_storage);
|
QString origin = PathCombine("libraries", cooked_storage);
|
||||||
QString target_dir_cooked = PathCombine(target_dir, "32");
|
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;
|
QLOG_ERROR() << "Couldn't create folder " + target_dir_cooked;
|
||||||
return false;
|
return false;
|
||||||
@ -191,7 +195,7 @@ bool OneSixLibrary::extractTo(QString target_dir)
|
|||||||
cooked_storage.replace("${arch}", "64");
|
cooked_storage.replace("${arch}", "64");
|
||||||
origin = PathCombine("libraries", cooked_storage);
|
origin = PathCombine("libraries", cooked_storage);
|
||||||
target_dir_cooked = PathCombine(target_dir, "64");
|
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;
|
QLOG_ERROR() << "Couldn't create folder " + target_dir_cooked;
|
||||||
return false;
|
return false;
|
||||||
@ -205,7 +209,7 @@ bool OneSixLibrary::extractTo(QString target_dir)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(!ensureFolderPathExists(target_dir))
|
if (!ensureFolderPathExists(target_dir))
|
||||||
{
|
{
|
||||||
QLOG_ERROR() << "Couldn't create folder " + target_dir;
|
QLOG_ERROR() << "Couldn't create folder " + target_dir;
|
||||||
return false;
|
return false;
|
||||||
@ -230,8 +234,10 @@ QJsonObject OneSixLibrary::toJson()
|
|||||||
libRoot.insert("MMC-hint", m_hint);
|
libRoot.insert("MMC-hint", m_hint);
|
||||||
if (m_base_url != "http://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
|
if (m_base_url != "http://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
|
||||||
m_base_url != "https://" + 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);
|
libRoot.insert("url", m_base_url);
|
||||||
|
}
|
||||||
if (isNative() && m_native_suffixes.size())
|
if (isNative() && m_native_suffixes.size())
|
||||||
{
|
{
|
||||||
QJsonObject nativeList;
|
QJsonObject nativeList;
|
||||||
|
@ -63,7 +63,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
OneSixLibrary(QString name)
|
OneSixLibrary(const QString &name)
|
||||||
{
|
{
|
||||||
m_name = name;
|
m_name = name;
|
||||||
}
|
}
|
||||||
@ -84,48 +84,50 @@ public:
|
|||||||
void finalize();
|
void finalize();
|
||||||
|
|
||||||
/// Set the library composite name
|
/// Set the library composite name
|
||||||
void setName(QString name);
|
void setName(const QString &name);
|
||||||
/// get a decent-looking name
|
/// get a decent-looking name
|
||||||
QString name()
|
QString name() const
|
||||||
{
|
{
|
||||||
return m_decentname;
|
return m_decentname;
|
||||||
}
|
}
|
||||||
/// get a decent-looking version
|
/// get a decent-looking version
|
||||||
QString version()
|
QString version() const
|
||||||
{
|
{
|
||||||
return m_decentversion;
|
return m_decentversion;
|
||||||
}
|
}
|
||||||
/// what kind of library is it? (for display)
|
/// what kind of library is it? (for display)
|
||||||
QString type()
|
QString type() const
|
||||||
{
|
{
|
||||||
return m_decenttype;
|
return m_decenttype;
|
||||||
}
|
}
|
||||||
/// Set the url base for downloads
|
/// 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)
|
/// Call this to mark the library as 'native' (it's a zip archive with DLLs)
|
||||||
void setIsNative();
|
void setIsNative();
|
||||||
/// Attach a name suffix to the specified OS native
|
/// 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
|
/// Set the load rules
|
||||||
void setRules(QList<std::shared_ptr<Rule>> rules);
|
void setRules(QList<std::shared_ptr<Rule>> rules);
|
||||||
|
|
||||||
/// Returns true if the library should be loaded (or extracted, in case of natives)
|
/// 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
|
/// Returns true if the library is native
|
||||||
bool isNative();
|
bool isNative() const;
|
||||||
/// Get the URL to download the library from
|
/// Get the URL to download the library from
|
||||||
QString downloadUrl();
|
QString downloadUrl() const;
|
||||||
/// Get the relative path where the library should be saved
|
/// 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.
|
/// set an absolute URL for the library. This is an MMC extension.
|
||||||
void setAbsoluteUrl(QString absolute_url);
|
void setAbsoluteUrl(const QString &absolute_url);
|
||||||
QString absoluteUrl();
|
QString absoluteUrl() const;
|
||||||
|
|
||||||
/// set a hint about how to treat the library. This is an MMC extension.
|
/// set a hint about how to treat the library. This is an MMC extension.
|
||||||
void setHint(QString hint);
|
void setHint(const QString &hint);
|
||||||
QString hint();
|
QString hint() const;
|
||||||
|
|
||||||
bool extractTo(QString target_dir);
|
bool extractTo(QString target_dir);
|
||||||
bool filesExist();
|
bool filesExist();
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include "OneSixRule.h"
|
#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;
|
QList<std::shared_ptr<Rule>> rules;
|
||||||
auto rulesVal = objectWithRules.value("rules");
|
auto rulesVal = objectWithRules.value("rules");
|
||||||
@ -86,4 +86,4 @@ RuleAction RuleAction_fromString(QString name)
|
|||||||
if (name == "disallow")
|
if (name == "disallow")
|
||||||
return Disallow;
|
return Disallow;
|
||||||
return Defer;
|
return Defer;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ enum RuleAction
|
|||||||
};
|
};
|
||||||
|
|
||||||
RuleAction RuleAction_fromString(QString);
|
RuleAction RuleAction_fromString(QString);
|
||||||
QList<std::shared_ptr<Rule>> rulesFromJsonV4(QJsonObject &objectWithRules);
|
QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules);
|
||||||
|
|
||||||
class Rule
|
class Rule
|
||||||
{
|
{
|
||||||
|
@ -131,7 +131,7 @@ void OneSixUpdate::versionFileFinished()
|
|||||||
{
|
{
|
||||||
finfo.remove();
|
finfo.remove();
|
||||||
}
|
}
|
||||||
inst->reloadFullVersion();
|
inst->reloadVersion();
|
||||||
|
|
||||||
jarlibStart();
|
jarlibStart();
|
||||||
}
|
}
|
||||||
@ -229,7 +229,7 @@ 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->reloadFullVersion();
|
bool successful = inst->reloadVersion();
|
||||||
if (!successful)
|
if (!successful)
|
||||||
{
|
{
|
||||||
emitFailed("Failed to load the version description file. It might be "
|
emitFailed("Failed to load the version description file. It might be "
|
||||||
|
@ -13,228 +13,86 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "logic/OneSixVersion.h"
|
#include "OneSixVersion.h"
|
||||||
#include "logic/OneSixLibrary.h"
|
|
||||||
#include "logic/OneSixRule.h"
|
|
||||||
|
|
||||||
#include "logger/QsLog.h"
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
std::shared_ptr<OneSixVersion> fromJsonV4(QJsonObject root,
|
#include "OneSixVersionBuilder.h"
|
||||||
std::shared_ptr<OneSixVersion> fullVersion)
|
|
||||||
|
OneSixVersion::OneSixVersion(OneSixInstance *instance, QObject *parent)
|
||||||
|
: QAbstractListModel(parent), m_instance(instance)
|
||||||
{
|
{
|
||||||
fullVersion->id = root.value("id").toString();
|
clear();
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<OneSixVersion> OneSixVersion::fromJson(QJsonObject root)
|
bool OneSixVersion::reload(QWidget *widgetParent, const bool excludeCustom)
|
||||||
{
|
{
|
||||||
std::shared_ptr<OneSixVersion> readVersion(new OneSixVersion());
|
beginResetModel();
|
||||||
int launcher_ver = readVersion->minimumLauncherVersion =
|
bool ret = OneSixVersionBuilder::build(this, m_instance, widgetParent, excludeCustom);
|
||||||
root.value("minimumLauncherVersion").toDouble();
|
endResetModel();
|
||||||
|
return ret;
|
||||||
// ADD MORE HERE :D
|
|
||||||
if (launcher_ver > 0 && launcher_ver <= 13)
|
|
||||||
return fromJsonV4(root, readVersion);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return std::shared_ptr<OneSixVersion>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<OneSixVersion> OneSixVersion::fromFile(QString filepath)
|
void OneSixVersion::clear()
|
||||||
{
|
{
|
||||||
QFile file(filepath);
|
beginResetModel();
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
id.clear();
|
||||||
{
|
time.clear();
|
||||||
return std::shared_ptr<OneSixVersion>();
|
releaseTime.clear();
|
||||||
}
|
type.clear();
|
||||||
|
assets.clear();
|
||||||
auto data = file.readAll();
|
processArguments.clear();
|
||||||
QJsonParseError jsonError;
|
minecraftArguments.clear();
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
minimumLauncherVersion = 0xDEADBEAF;
|
||||||
|
mainClass.clear();
|
||||||
if (jsonError.error != QJsonParseError::NoError)
|
libraries.clear();
|
||||||
{
|
tweakers.clear();
|
||||||
return std::shared_ptr<OneSixVersion>();
|
versionFiles.clear();
|
||||||
}
|
endResetModel();
|
||||||
|
|
||||||
if (!jsonDoc.isObject())
|
|
||||||
{
|
|
||||||
return std::shared_ptr<OneSixVersion>();
|
|
||||||
}
|
|
||||||
QJsonObject root = jsonDoc.object();
|
|
||||||
auto version = fromJson(root);
|
|
||||||
if (version)
|
|
||||||
version->original_file = filepath;
|
|
||||||
return version;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OneSixVersion::toOriginalFile()
|
void OneSixVersion::dump() const
|
||||||
{
|
{
|
||||||
if (original_file.isEmpty())
|
qDebug().nospace() << "OneSixVersion("
|
||||||
return false;
|
<< "\n\tid=" << id
|
||||||
QSaveFile file(original_file);
|
<< "\n\ttime=" << time
|
||||||
if (!file.open(QIODevice::WriteOnly))
|
<< "\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)
|
||||||
{
|
{
|
||||||
return false;
|
qDebug().nospace() << "\n\t\t" << lib.get();
|
||||||
}
|
}
|
||||||
// serialize base attributes (those we care about anyway)
|
qDebug().nospace() << "\n)";
|
||||||
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::canRemove(const int index) const
|
||||||
{
|
{
|
||||||
QList<std::shared_ptr<OneSixLibrary>> output;
|
if (index < versionFiles.size())
|
||||||
|
{
|
||||||
|
return versionFiles.at(index).id != "org.multimc.version.json";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
for (auto lib : libraries)
|
||||||
{
|
{
|
||||||
if (lib->isActive() && !lib->isNative())
|
if (lib->isActive() && !lib->isNative())
|
||||||
@ -245,9 +103,9 @@ QList<std::shared_ptr<OneSixLibrary>> OneSixVersion::getActiveNormalLibs()
|
|||||||
return output;
|
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)
|
for (auto lib : libraries)
|
||||||
{
|
{
|
||||||
if (lib->isActive() && lib->isNative())
|
if (lib->isActive() && lib->isNative())
|
||||||
@ -258,14 +116,14 @@ QList<std::shared_ptr<OneSixLibrary>> OneSixVersion::getActiveNativeLibs()
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixVersion::externalUpdateStart()
|
std::shared_ptr<OneSixVersion> OneSixVersion::fromJson(const QJsonObject &obj)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
std::shared_ptr<OneSixVersion> version(new OneSixVersion(0));
|
||||||
}
|
if (OneSixVersionBuilder::read(version.get(), obj))
|
||||||
|
{
|
||||||
void OneSixVersion::externalUpdateFinish()
|
return version;
|
||||||
{
|
}
|
||||||
endResetModel();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant OneSixVersion::data(const QModelIndex &index, int role) const
|
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 row = index.row();
|
||||||
int column = index.column();
|
int column = index.column();
|
||||||
|
|
||||||
if (row < 0 || row >= libraries.size())
|
if (row < 0 || row >= versionFiles.size())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
if (role == Qt::DisplayRole)
|
if (role == Qt::DisplayRole)
|
||||||
@ -284,11 +142,9 @@ QVariant OneSixVersion::data(const QModelIndex &index, int role) const
|
|||||||
switch (column)
|
switch (column)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
return libraries[row]->name();
|
return versionFiles.at(row).name;
|
||||||
case 1:
|
case 1:
|
||||||
return libraries[row]->type();
|
return versionFiles.at(row).version;
|
||||||
case 2:
|
|
||||||
return libraries[row]->version();
|
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@ -296,45 +152,61 @@ QVariant OneSixVersion::data(const QModelIndex &index, int role) const
|
|||||||
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
|
Qt::ItemFlags OneSixVersion::flags(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return Qt::NoItemFlags;
|
return Qt::NoItemFlags;
|
||||||
int row = index.row();
|
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int OneSixVersion::rowCount(const QModelIndex &parent) const
|
int OneSixVersion::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return libraries.size();
|
return versionFiles.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int OneSixVersion::columnCount(const QModelIndex &parent) const
|
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
|
#pragma once
|
||||||
#include <QtCore>
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QList>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class OneSixLibrary;
|
#include "OneSixLibrary.h"
|
||||||
|
|
||||||
|
class OneSixInstance;
|
||||||
|
|
||||||
class OneSixVersion : public QAbstractListModel
|
class OneSixVersion : public QAbstractListModel
|
||||||
{
|
{
|
||||||
// Things required to implement the Qt list model
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
explicit OneSixVersion(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 int rowCount(const QModelIndex &parent = QModelIndex()) 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 int columnCount(const QModelIndex &parent) const;
|
||||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||||
|
|
||||||
// serialization/deserialization
|
bool reload(QWidget *widgetParent, const bool excludeCustom = false);
|
||||||
public:
|
void clear();
|
||||||
bool toOriginalFile();
|
|
||||||
static std::shared_ptr<OneSixVersion> fromJson(QJsonObject root);
|
void dump() const;
|
||||||
static std::shared_ptr<OneSixVersion> fromFile(QString filepath);
|
|
||||||
|
bool canRemove(const int index) const;
|
||||||
|
|
||||||
|
public
|
||||||
|
slots:
|
||||||
|
bool remove(const int index);
|
||||||
|
|
||||||
public:
|
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();
|
||||||
// called when something starts/stops messing with the object
|
|
||||||
// FIXME: these are ugly in every possible way.
|
static std::shared_ptr<OneSixVersion> fromJson(const QJsonObject &obj);
|
||||||
void externalUpdateStart();
|
|
||||||
void externalUpdateFinish();
|
|
||||||
|
|
||||||
// data members
|
// data members
|
||||||
public:
|
public:
|
||||||
/// file this was read from. blank, if none
|
|
||||||
QString original_file;
|
|
||||||
/// the ID - determines which jar to use! ACTUALLY IMPORTANT!
|
/// the ID - determines which jar to use! ACTUALLY IMPORTANT!
|
||||||
QString id;
|
QString id;
|
||||||
/// Last updated time - as a string
|
/// Last updated time - as a string
|
||||||
@ -75,6 +83,10 @@ public:
|
|||||||
* writing)
|
* writing)
|
||||||
*/
|
*/
|
||||||
int minimumLauncherVersion = 0xDEADBEEF;
|
int minimumLauncherVersion = 0xDEADBEEF;
|
||||||
|
/**
|
||||||
|
* A list of all tweaker classes
|
||||||
|
*/
|
||||||
|
QStringList tweakers;
|
||||||
/**
|
/**
|
||||||
* The main class to load first
|
* The main class to load first
|
||||||
*/
|
*/
|
||||||
@ -103,4 +115,20 @@ public:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
// QList<Rule> rules;
|
// 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