diff --git a/api/logic/minecraft/MinecraftProfile.cpp b/api/logic/minecraft/MinecraftProfile.cpp index 4c1ab818..f6e39f45 100644 --- a/api/logic/minecraft/MinecraftProfile.cpp +++ b/api/logic/minecraft/MinecraftProfile.cpp @@ -664,6 +664,12 @@ void MinecraftProfile::installJarMods(QStringList selectedFiles) m_strategy->installJarMods(selectedFiles); } +void MinecraftProfile::installCustomJar(QString selectedFile) +{ + m_strategy->installCustomJar(selectedFile); +} + + /* * TODO: get rid of this. Get rid of all order numbers. */ diff --git a/api/logic/minecraft/MinecraftProfile.h b/api/logic/minecraft/MinecraftProfile.h index 192c77f9..e81ba499 100644 --- a/api/logic/minecraft/MinecraftProfile.h +++ b/api/logic/minecraft/MinecraftProfile.h @@ -58,6 +58,9 @@ public: /// install more jar mods void installJarMods(QStringList selectedFiles); + /// install more jar mods + void installCustomJar(QString selectedFile); + /// DEPRECATED, remove ASAP int getFreeOrderNumber(); diff --git a/api/logic/minecraft/ProfileStrategy.h b/api/logic/minecraft/ProfileStrategy.h index 26bdf661..09a09f24 100644 --- a/api/logic/minecraft/ProfileStrategy.h +++ b/api/logic/minecraft/ProfileStrategy.h @@ -23,6 +23,9 @@ public: /// install a list of jar mods into the instance virtual bool installJarMods(QStringList filepaths) = 0; + /// install a custom jar (replaces the one from the Minecraft component) + virtual bool installCustomJar(QString filepath) = 0; + /// remove any files or records that constitute the version patch virtual bool removePatch(ProfilePatchPtr jarMod) = 0; diff --git a/api/logic/minecraft/ftb/FTBProfileStrategy.cpp b/api/logic/minecraft/ftb/FTBProfileStrategy.cpp index 9fa4e6a1..d5df7848 100644 --- a/api/logic/minecraft/ftb/FTBProfileStrategy.cpp +++ b/api/logic/minecraft/ftb/FTBProfileStrategy.cpp @@ -118,6 +118,11 @@ bool FTBProfileStrategy::installJarMods(QStringList filepaths) return false; } +bool FTBProfileStrategy::installCustomJar(QString filepath) +{ + return false; +} + bool FTBProfileStrategy::customizePatch(ProfilePatchPtr patch) { return false; diff --git a/api/logic/minecraft/ftb/FTBProfileStrategy.h b/api/logic/minecraft/ftb/FTBProfileStrategy.h index 522af098..4637d04b 100644 --- a/api/logic/minecraft/ftb/FTBProfileStrategy.h +++ b/api/logic/minecraft/ftb/FTBProfileStrategy.h @@ -9,13 +9,14 @@ class FTBProfileStrategy : public OneSixProfileStrategy public: FTBProfileStrategy(OneSixFTBInstance * instance); virtual ~FTBProfileStrategy() {}; - virtual void load() override; - virtual bool resetOrder() override; - virtual bool saveOrder(ProfileUtils::PatchOrder order) override; - virtual bool installJarMods(QStringList filepaths) override; - virtual bool customizePatch (ProfilePatchPtr patch) override; - virtual bool revertPatch (ProfilePatchPtr patch) override; + void load() override; + bool resetOrder() override; + bool saveOrder(ProfileUtils::PatchOrder order) override; + bool installJarMods(QStringList filepaths) override; + bool installCustomJar(QString filepath) override; + bool customizePatch (ProfilePatchPtr patch) override; + bool revertPatch (ProfilePatchPtr patch) override; protected: - virtual void loadDefaultBuiltinPatches() override; + void loadDefaultBuiltinPatches() override; }; diff --git a/api/logic/minecraft/onesix/OneSixInstance.cpp b/api/logic/minecraft/onesix/OneSixInstance.cpp index 107da04f..34253f02 100644 --- a/api/logic/minecraft/onesix/OneSixInstance.cpp +++ b/api/logic/minecraft/onesix/OneSixInstance.cpp @@ -637,11 +637,16 @@ QString OneSixInstance::jarModsDir() const return FS::PathCombine(instanceRoot(), "jarmods"); } -QString OneSixInstance::libDir() const +QString OneSixInstance::FMLlibDir() const { return FS::PathCombine(minecraftRoot(), "lib"); } +QString OneSixInstance::customLibrariesDir() const +{ + return FS::PathCombine(instanceRoot(), "libraries"); +} + QString OneSixInstance::worldDir() const { return FS::PathCombine(minecraftRoot(), "saves"); diff --git a/api/logic/minecraft/onesix/OneSixInstance.h b/api/logic/minecraft/onesix/OneSixInstance.h index bf12160e..0cb4340b 100644 --- a/api/logic/minecraft/onesix/OneSixInstance.h +++ b/api/logic/minecraft/onesix/OneSixInstance.h @@ -48,7 +48,8 @@ public: QString texturePacksDir() const; QString loaderModsDir() const; QString coreModsDir() const; - QString libDir() const; + QString FMLlibDir() const; + QString customLibrariesDir() const; QString worldDir() const; virtual QString instanceConfigFolder() const override; diff --git a/api/logic/minecraft/onesix/OneSixProfileStrategy.cpp b/api/logic/minecraft/onesix/OneSixProfileStrategy.cpp index ef2a7294..39dd8343 100644 --- a/api/logic/minecraft/onesix/OneSixProfileStrategy.cpp +++ b/api/logic/minecraft/onesix/OneSixProfileStrategy.cpp @@ -405,3 +405,67 @@ bool OneSixProfileStrategy::installJarMods(QStringList filepaths) return true; } +bool OneSixProfileStrategy::installCustomJar(QString filepath) +{ + QString patchDir = FS::PathCombine(m_instance->instanceRoot(), "patches"); + if(!FS::ensureFolderPathExists(patchDir)) + { + return false; + } + + QString libDir = m_instance->customLibrariesDir(); + if (!FS::ensureFolderPathExists(libDir)) + { + return false; + } + + auto specifier = GradleSpecifier("org.multimc:customjar:1"); + QFileInfo sourceInfo(filepath); + QString target_filename = specifier.getFileName(); + QString target_id = specifier.artifactId(); + QString target_name = sourceInfo.completeBaseName() + " (custom jar)"; + QString finalPath = FS::PathCombine(libDir, target_filename); + + QFileInfo jarInfo(finalPath); + if (jarInfo.exists()) + { + if(!QFile::remove(finalPath)) + { + return false; + } + } + if (!QFile::copy(filepath, finalPath)) + { + return false; + } + + auto f = std::make_shared(); + auto jarMod = std::make_shared(); + jarMod->setRawName(specifier); + jarMod->setDisplayName(sourceInfo.completeBaseName()); + jarMod->setHint("local"); + f->mainJar = jarMod; + f->name = target_name; + f->uid = target_id; + f->order = profile->getFreeOrderNumber(); + QString patchFileName = FS::PathCombine(patchDir, target_id + ".json"); + + QFile file(patchFileName); + if (!file.open(QFile::WriteOnly)) + { + qCritical() << "Error opening" << file.fileName() + << "for reading:" << file.errorString(); + return false; + } + file.write(OneSixVersionFormat::versionFileToJson(f, true).toJson()); + file.close(); + + auto patch = std::make_shared(f, patchFileName); + patch->setMovable(true); + patch->setRemovable(true); + profile->appendPatch(patch); + + profile->saveCurrentOrder(); + profile->reapplyPatches(); + return true; +} diff --git a/api/logic/minecraft/onesix/OneSixProfileStrategy.h b/api/logic/minecraft/onesix/OneSixProfileStrategy.h index 96c1ba7b..e4eee4b2 100644 --- a/api/logic/minecraft/onesix/OneSixProfileStrategy.h +++ b/api/logic/minecraft/onesix/OneSixProfileStrategy.h @@ -8,13 +8,14 @@ class OneSixProfileStrategy : public ProfileStrategy public: OneSixProfileStrategy(OneSixInstance * instance); virtual ~OneSixProfileStrategy() {}; - virtual void load() override; - virtual bool resetOrder() override; - virtual bool saveOrder(ProfileUtils::PatchOrder order) override; - virtual bool installJarMods(QStringList filepaths) override; - virtual bool removePatch(ProfilePatchPtr patch) override; - virtual bool customizePatch(ProfilePatchPtr patch) override; - virtual bool revertPatch(ProfilePatchPtr patch) override; + void load() override; + bool resetOrder() override; + bool saveOrder(ProfileUtils::PatchOrder order) override; + bool installJarMods(QStringList filepaths) override; + bool installCustomJar(QString filepath) override; + bool removePatch(ProfilePatchPtr patch) override; + bool customizePatch(ProfilePatchPtr patch) override; + bool revertPatch(ProfilePatchPtr patch) override; protected: virtual void loadDefaultBuiltinPatches(); diff --git a/api/logic/minecraft/onesix/update/FMLLibrariesTask.cpp b/api/logic/minecraft/onesix/update/FMLLibrariesTask.cpp index 42148e67..13310e92 100644 --- a/api/logic/minecraft/onesix/update/FMLLibrariesTask.cpp +++ b/api/logic/minecraft/onesix/update/FMLLibrariesTask.cpp @@ -45,7 +45,7 @@ void FMLLibrariesTask::executeTask() // now check the lib folder inside the instance for files. for (auto &lib : libList) { - QFileInfo libInfo(FS::PathCombine(inst->libDir(), lib.filename)); + QFileInfo libInfo(FS::PathCombine(inst->FMLlibDir(), lib.filename)); if (libInfo.exists()) continue; fmlLibsToProcess.append(lib); @@ -95,13 +95,13 @@ void FMLLibrariesTask::fmllibsFinished() { progress(index, fmlLibsToProcess.size()); auto entry = metacache->resolveEntry("fmllibs", lib.filename); - auto path = FS::PathCombine(inst->libDir(), lib.filename); + auto path = FS::PathCombine(inst->FMLlibDir(), lib.filename); if (!FS::ensureFilePathExists(path)) { emitFailed(tr("Failed creating FML library folder inside the instance.")); return; } - if (!QFile::copy(entry->getFullPath(), FS::PathCombine(inst->libDir(), lib.filename))) + if (!QFile::copy(entry->getFullPath(), FS::PathCombine(inst->FMLlibDir(), lib.filename))) { emitFailed(tr("Failed copying Forge/FML library: %1.").arg(lib.filename)); return; diff --git a/application/GuiUtil.cpp b/application/GuiUtil.cpp index 26050488..b05fc57c 100644 --- a/application/GuiUtil.cpp +++ b/application/GuiUtil.cpp @@ -56,8 +56,7 @@ void GuiUtil::setClipboardText(const QString &text) QApplication::clipboard()->setText(text); } - -QStringList GuiUtil::BrowseForFiles(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget) +static QStringList BrowseForFileInternal(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget, bool single) { static QMap savedPaths; @@ -82,7 +81,7 @@ QStringList GuiUtil::BrowseForFiles(QString context, QString caption, QString fi } urls.append(QUrl::fromLocalFile(defaultPath)); - w.setFileMode(QFileDialog::ExistingFiles); + w.setFileMode(single ? QFileDialog::ExistingFile : QFileDialog::ExistingFiles); w.setAcceptMode(QFileDialog::AcceptOpen); w.setNameFilter(filter); @@ -114,3 +113,19 @@ QStringList GuiUtil::BrowseForFiles(QString context, QString caption, QString fi savedPaths[context] = w.directory().absolutePath(); return {}; } + +QString GuiUtil::BrowseForFile(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget) +{ + auto resultList = BrowseForFileInternal(context, caption, filter, defaultPath, parentWidget, true); + if(resultList.size()) + { + return resultList[0]; + } + return QString(); +} + + +QStringList GuiUtil::BrowseForFiles(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget) +{ + return BrowseForFileInternal(context, caption, filter, defaultPath, parentWidget, false); +} diff --git a/application/GuiUtil.h b/application/GuiUtil.h index 52520c56..5e109383 100644 --- a/application/GuiUtil.h +++ b/application/GuiUtil.h @@ -7,4 +7,5 @@ namespace GuiUtil QString uploadPaste(const QString &text, QWidget *parentWidget); void setClipboardText(const QString &text); QStringList BrowseForFiles(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget); +QString BrowseForFile(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget); } diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 64e6bba2..4eec3927 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -501,9 +501,6 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) m_settings->registerSetting("UpdateDialogGeometry", ""); - // Jar mod nag dialog in version page - m_settings->registerSetting("JarModNagSeen", false); - // paste.ee API key m_settings->registerSetting("PasteEEAPIKey", "multimc"); diff --git a/application/pages/VersionPage.cpp b/application/pages/VersionPage.cpp index 8c14818f..90fd3241 100644 --- a/application/pages/VersionPage.cpp +++ b/application/pages/VersionPage.cpp @@ -250,34 +250,20 @@ void VersionPage::on_modBtn_clicked() void VersionPage::on_jarmodBtn_clicked() { - bool nagShown = false; - if (!m_profile->hasTrait("legacyLaunch") && !m_profile->hasTrait("alphaLaunch")) - { - // not legacy launch... nag - auto seenNag = MMC->settings()->get("JarModNagSeen").toBool(); - if(!seenNag) - { - auto result = QMessageBox::question(this, - tr("Are you sure?"), - tr("This will add mods directly to the Minecraft jar.\n" - "Unless you KNOW that this is what NEEDS to be done, you should just use the mods folder (Loader mods).\n" - "\n" - "Do you want to continue?"), - tr("I understand, continue."), tr("Cancel"), QString(), 1, 1 - ); - if(result != 0) - return; - nagShown = true; - } - } auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"), MMC->settings()->get("CentralModsDir").toString(), this->parentWidget()); if(!list.empty()) { m_profile->installJarMods(list); - if(nagShown) - { - MMC->settings()->set("JarModNagSeen", QVariant(true)); - } + } + updateButtons(); +} + +void VersionPage::on_jarBtn_clicked() +{ + auto jarPath = GuiUtil::BrowseForFile("jar", tr("Select jar"), tr("Minecraft.jar replacement (*.jar)"), MMC->settings()->get("CentralModsDir").toString(), this->parentWidget()); + if(!jarPath.isEmpty()) + { + m_profile->installCustomJar(jarPath); } updateButtons(); } diff --git a/application/pages/VersionPage.h b/application/pages/VersionPage.h index cc6c0b7b..12a699eb 100644 --- a/application/pages/VersionPage.h +++ b/application/pages/VersionPage.h @@ -58,6 +58,7 @@ private slots: void on_moveUpBtn_clicked(); void on_moveDownBtn_clicked(); void on_jarmodBtn_clicked(); + void on_jarBtn_clicked(); void on_revertBtn_clicked(); void on_editBtn_clicked(); void on_modBtn_clicked(); diff --git a/application/pages/VersionPage.ui b/application/pages/VersionPage.ui index c16208db..afb33164 100644 --- a/application/pages/VersionPage.ui +++ b/application/pages/VersionPage.ui @@ -7,7 +7,7 @@ 0 0 693 - 750 + 788 @@ -206,7 +206,14 @@ Add a mod into the Minecraft jar file. - Add jar mod + Add to Minecraft.jar + + + + + + + Replace Minecraft.jar @@ -281,7 +288,6 @@ - tabWidget packageView changeVersionBtn moveUpBtn