diff options
Diffstat (limited to 'api/logic')
17 files changed, 802 insertions, 524 deletions
diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt index 1f795556..a762fb22 100644 --- a/api/logic/CMakeLists.txt +++ b/api/logic/CMakeLists.txt @@ -279,15 +279,21 @@ set(MINECRAFT_SOURCES minecraft/VersionFile.h minecraft/VersionFilterData.h minecraft/VersionFilterData.cpp - minecraft/Mod.h - minecraft/Mod.cpp - minecraft/SimpleModList.h - minecraft/SimpleModList.cpp minecraft/World.h minecraft/World.cpp minecraft/WorldList.h minecraft/WorldList.cpp + minecraft/mod/Mod.h + minecraft/mod/Mod.cpp + minecraft/mod/ModDetails.h + minecraft/mod/ModFolderModel.h + minecraft/mod/ModFolderModel.cpp + minecraft/mod/ModFolderLoadTask.h + minecraft/mod/ModFolderLoadTask.cpp + minecraft/mod/LocalModParseTask.h + minecraft/mod/LocalModParseTask.cpp + # Assets minecraft/AssetsUtils.h minecraft/AssetsUtils.cpp @@ -318,8 +324,8 @@ add_unit_test(Library ) # FIXME: shares data with FileSystem test -add_unit_test(SimpleModList - SOURCES minecraft/SimpleModList_test.cpp +add_unit_test(ModFolderModel + SOURCES minecraft/mod/ModFolderModel_test.cpp DATA testdata LIBS MultiMC_logic ) @@ -479,8 +485,6 @@ set(LOGIC_SOURCES ${FLAME_SOURCES} ) -message(STATUS "FOO! ${LOGIC_SOURCES}") - add_library(MultiMC_logic SHARED ${LOGIC_SOURCES}) set_target_properties(MultiMC_logic PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN 1) diff --git a/api/logic/MMCZip.h b/api/logic/MMCZip.h index ee9c5cc1..85ac7802 100644 --- a/api/logic/MMCZip.h +++ b/api/logic/MMCZip.h @@ -18,7 +18,7 @@ #include <QString> #include <QFileInfo> #include <QSet> -#include "minecraft/Mod.h" +#include "minecraft/mod/Mod.h" #include <functional> #include "multimc_logic_export.h" diff --git a/api/logic/minecraft/MinecraftInstance.cpp b/api/logic/minecraft/MinecraftInstance.cpp index 617d7431..9ca77798 100644 --- a/api/logic/minecraft/MinecraftInstance.cpp +++ b/api/logic/minecraft/MinecraftInstance.cpp @@ -26,7 +26,7 @@ #include "meta/Index.h" #include "meta/VersionList.h" -#include "SimpleModList.h" +#include "mod/ModFolderModel.h" #include "WorldList.h" #include "icons/IIconList.h" @@ -892,46 +892,46 @@ JavaVersion MinecraftInstance::getJavaVersion() const return JavaVersion(settings()->get("JavaVersion").toString()); } -std::shared_ptr<SimpleModList> MinecraftInstance::loaderModList() const +std::shared_ptr<ModFolderModel> MinecraftInstance::loaderModList() const { if (!m_loader_mod_list) { - m_loader_mod_list.reset(new SimpleModList(loaderModsDir())); + m_loader_mod_list.reset(new ModFolderModel(loaderModsDir())); m_loader_mod_list->disableInteraction(isRunning()); - connect(this, &BaseInstance::runningStatusChanged, m_loader_mod_list.get(), &SimpleModList::disableInteraction); + connect(this, &BaseInstance::runningStatusChanged, m_loader_mod_list.get(), &ModFolderModel::disableInteraction); } return m_loader_mod_list; } -std::shared_ptr<SimpleModList> MinecraftInstance::coreModList() const +std::shared_ptr<ModFolderModel> MinecraftInstance::coreModList() const { if (!m_core_mod_list) { - m_core_mod_list.reset(new SimpleModList(coreModsDir())); + m_core_mod_list.reset(new ModFolderModel(coreModsDir())); m_core_mod_list->disableInteraction(isRunning()); - connect(this, &BaseInstance::runningStatusChanged, m_core_mod_list.get(), &SimpleModList::disableInteraction); + connect(this, &BaseInstance::runningStatusChanged, m_core_mod_list.get(), &ModFolderModel::disableInteraction); } return m_core_mod_list; } -std::shared_ptr<SimpleModList> MinecraftInstance::resourcePackList() const +std::shared_ptr<ModFolderModel> MinecraftInstance::resourcePackList() const { if (!m_resource_pack_list) { - m_resource_pack_list.reset(new SimpleModList(resourcePacksDir())); + m_resource_pack_list.reset(new ModFolderModel(resourcePacksDir())); m_resource_pack_list->disableInteraction(isRunning()); - connect(this, &BaseInstance::runningStatusChanged, m_resource_pack_list.get(), &SimpleModList::disableInteraction); + connect(this, &BaseInstance::runningStatusChanged, m_resource_pack_list.get(), &ModFolderModel::disableInteraction); } return m_resource_pack_list; } -std::shared_ptr<SimpleModList> MinecraftInstance::texturePackList() const +std::shared_ptr<ModFolderModel> MinecraftInstance::texturePackList() const { if (!m_texture_pack_list) { - m_texture_pack_list.reset(new SimpleModList(texturePacksDir())); + m_texture_pack_list.reset(new ModFolderModel(texturePacksDir())); m_texture_pack_list->disableInteraction(isRunning()); - connect(this, &BaseInstance::runningStatusChanged, m_texture_pack_list.get(), &SimpleModList::disableInteraction); + connect(this, &BaseInstance::runningStatusChanged, m_texture_pack_list.get(), &ModFolderModel::disableInteraction); } return m_texture_pack_list; } diff --git a/api/logic/minecraft/MinecraftInstance.h b/api/logic/minecraft/MinecraftInstance.h index 501697f7..dd14664f 100644 --- a/api/logic/minecraft/MinecraftInstance.h +++ b/api/logic/minecraft/MinecraftInstance.h @@ -1,13 +1,13 @@ #pragma once #include "BaseInstance.h" #include <java/JavaVersion.h> -#include "minecraft/Mod.h" +#include "minecraft/mod/Mod.h" #include <QProcess> #include <QDir> #include "multimc_logic_export.h" class ModsModel; -class SimpleModList; +class ModFolderModel; class WorldList; class GameOptions; class LaunchStep; @@ -69,10 +69,10 @@ public: ////// Mod Lists ////// std::shared_ptr<ModsModel> modsModel() const; - std::shared_ptr<SimpleModList> loaderModList() const; - std::shared_ptr<SimpleModList> coreModList() const; - std::shared_ptr<SimpleModList> resourcePackList() const; - std::shared_ptr<SimpleModList> texturePackList() const; + std::shared_ptr<ModFolderModel> loaderModList() const; + std::shared_ptr<ModFolderModel> coreModList() const; + std::shared_ptr<ModFolderModel> resourcePackList() const; + std::shared_ptr<ModFolderModel> texturePackList() const; std::shared_ptr<WorldList> worldList() const; std::shared_ptr<GameOptions> gameOptionsModel() const; @@ -124,10 +124,10 @@ private: protected: // data std::shared_ptr<ComponentList> m_components; mutable std::shared_ptr<ModsModel> m_mods_model; - mutable std::shared_ptr<SimpleModList> m_loader_mod_list; - mutable std::shared_ptr<SimpleModList> m_core_mod_list; - mutable std::shared_ptr<SimpleModList> m_resource_pack_list; - mutable std::shared_ptr<SimpleModList> m_texture_pack_list; + mutable std::shared_ptr<ModFolderModel> m_loader_mod_list; + mutable std::shared_ptr<ModFolderModel> m_core_mod_list; + mutable std::shared_ptr<ModFolderModel> m_resource_pack_list; + mutable std::shared_ptr<ModFolderModel> m_texture_pack_list; mutable std::shared_ptr<WorldList> m_world_list; mutable std::shared_ptr<GameOptions> m_game_options; }; diff --git a/api/logic/minecraft/Mod.cpp b/api/logic/minecraft/Mod.cpp deleted file mode 100644 index 936ca00a..00000000 --- a/api/logic/minecraft/Mod.cpp +++ /dev/null @@ -1,433 +0,0 @@ -/* Copyright 2013-2019 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 <QDir> -#include <QString> -#include <QJsonDocument> -#include <QJsonObject> -#include <QJsonArray> -#include <QJsonValue> -#include <quazip.h> -#include <quazipfile.h> - -#include "Mod.h" -#include "settings/INIFile.h" -#include <FileSystem.h> -#include <QDebug> - -namespace { -// NEW format -// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/6f62b37cea040daf350dc253eae6326dd9c822c3 - -// OLD format: -// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc -ModDetails ReadMCModInfo(QByteArray contents) -{ - auto getInfoFromArray = [&](QJsonArray arr)->ModDetails - { - ModDetails details; - if (!arr.at(0).isObject()) { - return details; - } - auto firstObj = arr.at(0).toObject(); - details.mod_id = firstObj.value("modid").toString(); - auto name = firstObj.value("name").toString(); - // NOTE: ignore stupid example mods copies where the author didn't even bother to change the name - if(name != "Example Mod") { - details.name = name; - } - details.version = firstObj.value("version").toString(); - details.updateurl = firstObj.value("updateUrl").toString(); - auto homeurl = firstObj.value("url").toString().trimmed(); - if(!homeurl.isEmpty()) - { - // fix up url. - if (!homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://")) - { - homeurl.prepend("http://"); - } - } - details.homeurl = homeurl; - details.description = firstObj.value("description").toString(); - QJsonArray authors = firstObj.value("authorList").toArray(); - if (authors.size() == 0) { - // FIXME: what is the format of this? is there any? - authors = firstObj.value("authors").toArray(); - } - - for (auto author: authors) - { - details.authors.append(author.toString()); - } - details.credits = firstObj.value("credits").toString(); - details.valid = true; - return details; - }; - QJsonParseError jsonError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError); - // this is the very old format that had just the array - if (jsonDoc.isArray()) - { - return getInfoFromArray(jsonDoc.array()); - } - else if (jsonDoc.isObject()) - { - auto val = jsonDoc.object().value("modinfoversion"); - if(val.isUndefined()) { - val = jsonDoc.object().value("modListVersion"); - } - int version = val.toDouble(); - if (version != 2) - { - qCritical() << "BAD stuff happened to mod json:"; - qCritical() << contents; - return ModDetails(); - } - auto arrVal = jsonDoc.object().value("modlist"); - if(arrVal.isUndefined()) { - arrVal = jsonDoc.object().value("modList"); - } - if (arrVal.isArray()) - { - return getInfoFromArray(arrVal.toArray()); - } - } - return ModDetails(); -} - -// https://fabricmc.net/wiki/documentation:fabric_mod_json -ModDetails ReadFabricModInfo(QByteArray contents) -{ - QJsonParseError jsonError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError); - auto object = jsonDoc.object(); - auto schemaVersion = object.contains("schemaVersion") ? object.value("schemaVersion").toInt(0) : 0; - - ModDetails details; - - details.mod_id = object.value("id").toString(); - details.version = object.value("version").toString(); - - details.name = object.contains("name") ? object.value("name").toString() : details.mod_id; - details.description = object.value("description").toString(); - - if (schemaVersion >= 1) - { - QJsonArray authors = object.value("authors").toArray(); - for (auto author: authors) - { - if(author.isObject()) { - details.authors.append(author.toObject().value("name").toString()); - } - else { - details.authors.append(author.toString()); - } - } - - if (object.contains("contact")) - { - QJsonObject contact = object.value("contact").toObject(); - - if (contact.contains("homepage")) - { - details.homeurl = contact.value("homepage").toString(); - } - } - } - details.valid = !details.name.isEmpty(); - return details; -} - -ModDetails ReadForgeInfo(QByteArray contents) -{ - ModDetails details; - // Read the data - details.name = "Minecraft Forge"; - details.mod_id = "Forge"; - details.homeurl = "http://www.minecraftforge.net/forum/"; - details.valid = true; - INIFile ini; - if (!ini.loadFile(contents)) - return details; - - QString major = ini.get("forge.major.number", "0").toString(); - QString minor = ini.get("forge.minor.number", "0").toString(); - QString revision = ini.get("forge.revision.number", "0").toString(); - QString build = ini.get("forge.build.number", "0").toString(); - - details.version = major + "." + minor + "." + revision + "." + build; - return details; -} - -ModDetails ReadLiteModInfo(QByteArray contents) -{ - ModDetails details; - QJsonParseError jsonError; - QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError); - auto object = jsonDoc.object(); - if (object.contains("name")) - { - details.mod_id = details.name = object.value("name").toString(); - } - if (object.contains("version")) - { - details.version = object.value("version").toString(""); - } - else - { - details.version = object.value("revision").toString(""); - } - details.mcversion = object.value("mcversion").toString(); - auto author = object.value("author").toString(); - if(!author.isEmpty()) { - details.authors.append(author); - } - details.description = object.value("description").toString(); - details.homeurl = object.value("url").toString(); - return details; -} - -ModDetails invalidDetails; - -} - - -Mod::Mod(const QFileInfo &file) -{ - repath(file); - m_changedDateTime = file.lastModified(); -} - -void Mod::repath(const QFileInfo &file) -{ - m_file = file; - QString name_base = file.fileName(); - - m_type = Mod::MOD_UNKNOWN; - - if (m_file.isDir()) - { - m_type = MOD_FOLDER; - m_name = name_base; - m_mmc_id = name_base; - } - else if (m_file.isFile()) - { - if (name_base.endsWith(".disabled")) - { - m_enabled = false; - name_base.chop(9); - } - else - { - m_enabled = true; - } - m_mmc_id = name_base; - if (name_base.endsWith(".zip") || name_base.endsWith(".jar")) - { - m_type = MOD_ZIPFILE; - name_base.chop(4); - } - else if (name_base.endsWith(".litemod")) - { - m_type = MOD_LITEMOD; - name_base.chop(8); - } - else - { - m_type = MOD_SINGLEFILE; - } - m_name = name_base; - } - - if (m_type == MOD_ZIPFILE) - { - QuaZip zip(m_file.filePath()); - if (!zip.open(QuaZip::mdUnzip)) - return; - - QuaZipFile file(&zip); - - if (zip.setCurrentFile("mcmod.info")) - { - if (!file.open(QIODevice::ReadOnly)) - { - zip.close(); - return; - } - - m_localDetails = ReadMCModInfo(file.readAll()); - file.close(); - zip.close(); - return; - } - else if (zip.setCurrentFile("fabric.mod.json")) - { - if (!file.open(QIODevice::ReadOnly)) - { - zip.close(); - return; - } - - m_localDetails = ReadFabricModInfo(file.readAll()); - file.close(); - zip.close(); - return; - } - else if (zip.setCurrentFile("forgeversion.properties")) - { - if (!file.open(QIODevice::ReadOnly)) - { - zip.close(); - return; - } - - m_localDetails = ReadForgeInfo(file.readAll()); - file.close(); - zip.close(); - return; - } - - zip.close(); - } - else if (m_type == MOD_FOLDER) - { - QFileInfo mcmod_info(FS::PathCombine(m_file.filePath(), "mcmod.info")); - if (mcmod_info.isFile()) - { - QFile mcmod(mcmod_info.filePath()); - if (!mcmod.open(QIODevice::ReadOnly)) - return; - auto data = mcmod.readAll(); - if (data.isEmpty() || data.isNull()) - return; - m_localDetails = ReadMCModInfo(data); - } - } - else if (m_type == MOD_LITEMOD) - { - QuaZip zip(m_file.filePath()); - if (!zip.open(QuaZip::mdUnzip)) - return; - - QuaZipFile file(&zip); - - if (zip.setCurrentFile("litemod.json")) - { - if (!file.open(QIODevice::ReadOnly)) - { - zip.close(); - return; - } - - m_localDetails = ReadLiteModInfo(file.readAll()); - file.close(); - } - zip.close(); - } -} - -bool Mod::enable(bool value) -{ - if (m_type == Mod::MOD_UNKNOWN || m_type == Mod::MOD_FOLDER) - return false; - - if (m_enabled == value) - return false; - - QString path = m_file.absoluteFilePath(); - if (value) - { - QFile foo(path); - if (!path.endsWith(".disabled")) - return false; - path.chop(9); - if (!foo.rename(path)) - return false; - } - else - { - QFile foo(path); - path += ".disabled"; - if (!foo.rename(path)) - return false; - } - m_file = QFileInfo(path); - m_enabled = value; - return true; -} - -bool Mod::destroy() -{ - if (m_type == MOD_FOLDER) - { - QDir d(m_file.filePath()); - if (d.removeRecursively()) - { - m_type = MOD_UNKNOWN; - return true; - } - return false; - } - else if (m_type == MOD_SINGLEFILE || m_type == MOD_ZIPFILE || m_type == MOD_LITEMOD) - { - QFile f(m_file.filePath()); - if (f.remove()) - { - m_type = MOD_UNKNOWN; - return true; - } - return false; - } - return true; -} - - -const ModDetails & Mod::details() const -{ - if(!m_localDetails) - return invalidDetails; - return m_localDetails; -} - - -QString Mod::version() const -{ - return details().version; -} - -QString Mod::name() const -{ - auto & d = details(); - if(d && !d.name.isEmpty()) { - return d.name; - } - return m_name; -} - -QString Mod::homeurl() const -{ - return details().homeurl; -} - -QString Mod::description() const -{ - return details().description; -} - -QStringList Mod::authors() const -{ - return details().authors; -} diff --git a/api/logic/minecraft/ParseUtils_test.cpp b/api/logic/minecraft/ParseUtils_test.cpp index fde9cdbf..fcc137e5 100644 --- a/api/logic/minecraft/ParseUtils_test.cpp +++ b/api/logic/minecraft/ParseUtils_test.cpp @@ -33,7 +33,7 @@ slots: auto time_parsed = timeFromS3Time(timestamp); auto time_serialized = timeToS3Time(time_parsed); - + QCOMPARE(time_serialized, timestamp); } diff --git a/api/logic/minecraft/legacy/LegacyInstance.h b/api/logic/minecraft/legacy/LegacyInstance.h index 46fca3e4..7c0b94e8 100644 --- a/api/logic/minecraft/legacy/LegacyInstance.h +++ b/api/logic/minecraft/legacy/LegacyInstance.h @@ -16,12 +16,11 @@ #pragma once #include "BaseInstance.h" -#include "minecraft/Mod.h" #include "launch/LaunchTask.h" #include "multimc_logic_export.h" -class SimpleModList; +class ModFolderModel; class LegacyModList; class WorldList; class Task; diff --git a/api/logic/minecraft/mod/LocalModParseTask.cpp b/api/logic/minecraft/mod/LocalModParseTask.cpp new file mode 100644 index 00000000..22ebd7d4 --- /dev/null +++ b/api/logic/minecraft/mod/LocalModParseTask.cpp @@ -0,0 +1,298 @@ +#include "LocalModParseTask.h" + +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonArray> +#include <QJsonValue> +#include <quazip.h> +#include <quazipfile.h> + +#include "settings/INIFile.h" +#include "FileSystem.h" + +namespace { + +// NEW format +// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/6f62b37cea040daf350dc253eae6326dd9c822c3 + +// OLD format: +// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc +std::shared_ptr<ModDetails> ReadMCModInfo(QByteArray contents) +{ + auto getInfoFromArray = [&](QJsonArray arr)->std::shared_ptr<ModDetails> + { + if (!arr.at(0).isObject()) { + return nullptr; + } + std::shared_ptr<ModDetails> details = std::make_shared<ModDetails>(); + auto firstObj = arr.at(0).toObject(); + details->mod_id = firstObj.value("modid").toString(); + auto name = firstObj.value("name").toString(); + // NOTE: ignore stupid example mods copies where the author didn't even bother to change the name + if(name != "Example Mod") { + details->name = name; + } + details->version = firstObj.value("version").toString(); + details->updateurl = firstObj.value("updateUrl").toString(); + auto homeurl = firstObj.value("url").toString().trimmed(); + if(!homeurl.isEmpty()) + { + // fix up url. + if (!homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://")) + { + homeurl.prepend("http://"); + } + } + details->homeurl = homeurl; + details->description = firstObj.value("description").toString(); + QJsonArray authors = firstObj.value("authorList").toArray(); + if (authors.size() == 0) { + // FIXME: what is the format of this? is there any? + authors = firstObj.value("authors").toArray(); + } + + for (auto author: authors) + { + details->authors.append(author.toString()); + } + details->credits = firstObj.value("credits").toString(); + return details; + }; + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError); + // this is the very old format that had just the array + if (jsonDoc.isArray()) + { + return getInfoFromArray(jsonDoc.array()); + } + else if (jsonDoc.isObject()) + { + auto val = jsonDoc.object().value("modinfoversion"); + if(val.isUndefined()) { + val = jsonDoc.object().value("modListVersion"); + } + int version = val.toDouble(); + if (version != 2) + { + qCritical() << "BAD stuff happened to mod json:"; + qCritical() << contents; + return nullptr; + } + auto arrVal = jsonDoc.object().value("modlist"); + if(arrVal.isUndefined()) { + arrVal = jsonDoc.object().value("modList"); + } + if (arrVal.isArray()) + { + return getInfoFromArray(arrVal.toArray()); + } + } + return nullptr; +} + +// https://fabricmc.net/wiki/documentation:fabric_mod_json +std::shared_ptr<ModDetails> ReadFabricModInfo(QByteArray contents) +{ + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError); + auto object = jsonDoc.object(); + auto schemaVersion = object.contains("schemaVersion") ? object.value("schemaVersion").toInt(0) : 0; + + std::shared_ptr<ModDetails> details = std::make_shared<ModDetails>(); + + details->mod_id = object.value("id").toString(); + details->version = object.value("version").toString(); + + details->name = object.contains("name") ? object.value("name").toString() : details->mod_id; + details->description = object.value("description").toString(); + + if (schemaVersion >= 1) + { + QJsonArray authors = object.value("authors").toArray(); + for (auto author: authors) + { + if(author.isObject()) { + details->authors.append(author.toObject().value("name").toString()); + } + else { + details->authors.append(author.toString()); + } + } + + if (object.contains("contact")) + { + QJsonObject contact = object.value("contact").toObject(); + + if (contact.contains("homepage")) + { + details->homeurl = contact.value("homepage").toString(); + } + } + } + return details; +} + +std::shared_ptr<ModDetails> ReadForgeInfo(QByteArray contents) +{ + std::shared_ptr<ModDetails> details = std::make_shared<ModDetails>(); + // Read the data + details->name = "Minecraft Forge"; + details->mod_id = "Forge"; + details->homeurl = "http://www.minecraftforge.net/forum/"; + INIFile ini; + if (!ini.loadFile(contents)) + return details; + + QString major = ini.get("forge.major.number", "0").toString(); + QString minor = ini.get("forge.minor.number", "0").toString(); + QString revision = ini.get("forge.revision.number", "0").toString(); + QString build = ini.get("forge.build.number", "0").toString(); + + details->version = major + "." + minor + "." + revision + "." + build; + return details; +} + +std::shared_ptr<ModDetails> ReadLiteModInfo(QByteArray contents) +{ + std::shared_ptr<ModDetails> details = std::make_shared<ModDetails>(); + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError); + auto object = jsonDoc.object(); + if (object.contains("name")) + { + details->mod_id = details->name = object.value("name").toString(); + } + if (object.contains("version")) + { + details->version = object.value("version").toString(""); + } + else + { + details->version = object.value("revision").toString(""); + } + details->mcversion = object.value("mcversion").toString(); + auto author = object.value("author").toString(); + if(!author.isEmpty()) { + details->authors.append(author); + } + details->description = object.value("description").toString(); + details->homeurl = object.value("url").toString(); + return details; +} + +} + +LocalModParseTask::LocalModParseTask(int token, Mod::ModType type, const QFileInfo& modFile): + m_token(token), + m_type(type), + m_modFile(modFile), + m_result(new Result()) +{ +} + +void LocalModParseTask::processAsZip() +{ + QuaZip zip(m_modFile.filePath()); + if (!zip.open(QuaZip::mdUnzip)) + return; + + QuaZipFile file(&zip); + + if (zip.setCurrentFile("mcmod.info")) + { + if (!file.open(QIODevice::ReadOnly)) + { + zip.close(); + return; + } + + m_result->details = ReadMCModInfo(file.readAll()); + file.close(); + zip.close(); + return; + } + else if (zip.setCurrentFile("fabric.mod.json")) + { + if (!file.open(QIODevice::ReadOnly)) + { + zip.close(); + return; + } + + m_result->details = ReadFabricModInfo(file.readAll()); + file.close(); + zip.close(); + return; + } + else if (zip.setCurrentFile("forgeversion.properties")) + { + if (!file.open(QIODevice::ReadOnly)) + { + zip.close(); + return; + } + + m_result->details = ReadForgeInfo(file.readAll()); + file.close(); + zip.close(); + return; + } + + zip.close(); +} + +void LocalModParseTask::processAsFolder() +{ + QFileInfo mcmod_info(FS::PathCombine(m_modFile.filePath(), "mcmod.info")); + if (mcmod_info.isFile()) + { + QFile mcmod(mcmod_info.filePath()); + if (!mcmod.open(QIODevice::ReadOnly)) + return; + auto data = mcmod.readAll(); + if (data.isEmpty() || data.isNull()) + return; + m_result->details = ReadMCModInfo(data); + } +} + +void LocalModParseTask::processAsLitemod() +{ + QuaZip zip(m_modFile.filePath()); + if (!zip.open(QuaZip::mdUnzip)) + return; + + QuaZipFile file(&zip); + + if (zip.setCurrentFile("litemod.json")) + { + if (!file.open(QIODevice::ReadOnly)) + { + zip.close(); + return; + } + + m_result->details = ReadLiteModInfo(file.readAll()); + file.close(); + } + zip.close(); +} + +void LocalModParseTask::run() +{ + switch(m_type) + { + case Mod::MOD_ZIPFILE: + processAsZip(); + break; + case Mod::MOD_FOLDER: + processAsFolder(); + break; + case Mod::MOD_LITEMOD: + processAsLitemod(); + break; + default: + break; + } + emit finished(m_token); +} diff --git a/api/logic/minecraft/mod/LocalModParseTask.h b/api/logic/minecraft/mod/LocalModParseTask.h new file mode 100644 index 00000000..0f119ba6 --- /dev/null +++ b/api/logic/minecraft/mod/LocalModParseTask.h @@ -0,0 +1,37 @@ +#p |
