diff options
| -rw-r--r-- | api/logic/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | api/logic/minecraft/AssetsUtils.cpp | 134 | ||||
| -rw-r--r-- | api/logic/minecraft/AssetsUtils.h | 9 | ||||
| -rw-r--r-- | api/logic/minecraft/MinecraftInstance.cpp | 15 | ||||
| -rw-r--r-- | api/logic/minecraft/MinecraftInstance.h | 1 | ||||
| -rw-r--r-- | api/logic/minecraft/launch/ReconstructAssets.cpp | 36 | ||||
| -rw-r--r-- | api/logic/minecraft/launch/ReconstructAssets.h | 33 | ||||
| -rw-r--r-- | api/logic/minecraft/update/AssetUpdateTask.cpp | 4 | 
8 files changed, 209 insertions, 25 deletions
| diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt index 57a197be..39850163 100644 --- a/api/logic/CMakeLists.txt +++ b/api/logic/CMakeLists.txt @@ -235,6 +235,8 @@ set(MINECRAFT_SOURCES      minecraft/launch/LauncherPartLaunch.h      minecraft/launch/PrintInstanceInfo.cpp      minecraft/launch/PrintInstanceInfo.h +    minecraft/launch/ReconstructAssets.cpp +    minecraft/launch/ReconstructAssets.h      minecraft/legacy/LegacyModList.h      minecraft/legacy/LegacyModList.cpp      minecraft/legacy/LegacyInstance.h diff --git a/api/logic/minecraft/AssetsUtils.cpp b/api/logic/minecraft/AssetsUtils.cpp index c44b4ae6..013e7015 100644 --- a/api/logic/minecraft/AssetsUtils.cpp +++ b/api/logic/minecraft/AssetsUtils.cpp @@ -29,6 +29,34 @@  #include "net/ChecksumValidator.h"  #include "net/URLConstants.h" +namespace { +QSet<QString> collectPathsFromDir(QString dirPath) +{ +    std::error_code ignoredError; +    QFileInfo dirInfo(dirPath); + +    if (!dirInfo.exists()) +    { +        return {}; +    } + +    QSet<QString> out; + +    QDirIterator iter(dirPath, QDirIterator::Subdirectories); +    while (iter.hasNext()) +    { +        QString value = iter.next(); +        QFileInfo info(value); +        if(info.isFile()) +        { +            out.insert(value); +            qDebug() << value; +        } +    } +    return out; +} +} +  namespace AssetsUtils  { @@ -37,7 +65,7 @@ namespace AssetsUtils   * Returns true on success, with index populated   * index is undefined otherwise   */ -bool loadAssetsIndexJson(QString assetsId, QString path, AssetsIndex *index) +bool loadAssetsIndexJson(const QString &assetsId, const QString &path, AssetsIndex& index)  {      /*      { @@ -61,7 +89,7 @@ bool loadAssetsIndexJson(QString assetsId, QString path, AssetsIndex *index)          qCritical() << "Failed to read assets index file" << path;          return false;      } -    index->id = assetsId; +    index.id = assetsId;      // Read the file and close it.      QByteArray jsonData = file.readAll(); @@ -90,7 +118,13 @@ bool loadAssetsIndexJson(QString assetsId, QString path, AssetsIndex *index)      QJsonValue isVirtual = root.value("virtual");      if (!isVirtual.isUndefined())      { -        index->isVirtual = isVirtual.toBool(false); +        index.isVirtual = isVirtual.toBool(false); +    } + +    QJsonValue mapToResources = root.value("map_to_resources"); +    if (!mapToResources.isUndefined()) +    { +        index.mapToResources = mapToResources.toBool(false);      }      QJsonValue objects = root.value("objects"); @@ -122,13 +156,14 @@ bool loadAssetsIndexJson(QString assetsId, QString path, AssetsIndex *index)              }          } -        index->objects.insert(iter.key(), object); +        index.objects.insert(iter.key(), object);      }      return true;  } -QDir reconstructAssets(QString assetsId) +// FIXME: ugly code duplication +QDir getAssetsDir(const QString &assetsId, const QString &resourcesFolder)  {      QDir assetsDir = QDir("assets/");      QDir indexDir = QDir(FS::PathCombine(assetsDir.path(), "indexes")); @@ -141,24 +176,77 @@ QDir reconstructAssets(QString assetsId)      if (!indexFile.exists())      { -        qCritical() << "No assets index file" << indexPath << "; can't reconstruct assets"; +        qCritical() << "No assets index file" << indexPath << "; can't determine assets path!";          return virtualRoot;      } -    qDebug() << "reconstructAssets" << assetsDir.path() << indexDir.path() -                 << objectDir.path() << virtualDir.path() << virtualRoot.path(); +    AssetsIndex index; +    if(!AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, index)) +    { +        qCritical() << "Failed to load asset index file" << indexPath << "; can't determine assets path!"; +        return virtualRoot; +    } + +    QString targetPath; +    if(index.isVirtual) +    { +        return virtualRoot; +    } +    else if(index.mapToResources) +    { +        return QDir(resourcesFolder); +    } +    return virtualRoot; +} + +// FIXME: ugly code duplication +bool reconstructAssets(QString assetsId, QString resourcesFolder) +{ +    QDir assetsDir = QDir("assets/"); +    QDir indexDir = QDir(FS::PathCombine(assetsDir.path(), "indexes")); +    QDir objectDir = QDir(FS::PathCombine(assetsDir.path(), "objects")); +    QDir virtualDir = QDir(FS::PathCombine(assetsDir.path(), "virtual")); + +    QString indexPath = FS::PathCombine(indexDir.path(), assetsId + ".json"); +    QFile indexFile(indexPath); +    QDir virtualRoot(FS::PathCombine(virtualDir.path(), assetsId)); + +    if (!indexFile.exists()) +    { +        qCritical() << "No assets index file" << indexPath << "; can't reconstruct assets!"; +        return false; +    } + +    qDebug() << "reconstructAssets" << assetsDir.path() << indexDir.path() << objectDir.path() << virtualDir.path() << virtualRoot.path();      AssetsIndex index; -    bool loadAssetsIndex = AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, &index); +    if(!AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, index)) +    { +        qCritical() << "Failed to load asset index file" << indexPath << "; can't reconstruct assets!"; +        return false; +    } -    if (loadAssetsIndex && index.isVirtual) +    QString targetPath; +    bool removeLeftovers = false; +    if(index.isVirtual) +    { +        targetPath = virtualRoot.path(); +        removeLeftovers = true; +        qDebug() << "Reconstructing virtual assets folder at" << targetPath; +    } +    else if(index.mapToResources)      { -        qDebug() << "Reconstructing virtual assets folder at" << virtualRoot.path(); +        targetPath = resourcesFolder; +        qDebug() << "Reconstructing resources folder at" << targetPath; +    } +    if (!targetPath.isNull()) +    { +        auto presentFiles = collectPathsFromDir(targetPath);          for (QString map : index.objects.keys())          {              AssetObject asset_object = index.objects.value(map); -            QString target_path = FS::PathCombine(virtualRoot.path(), map); +            QString target_path = FS::PathCombine(targetPath, map);              QFile target(target_path);              QString tlk = asset_object.hash.left(2); @@ -167,24 +255,32 @@ QDir reconstructAssets(QString assetsId)              QFile original(original_path);              if (!original.exists())                  continue; + +            presentFiles.remove(target_path); +              if (!target.exists())              {                  QFileInfo info(target_path);                  QDir target_dir = info.dir(); -                // qDebug() << target_dir; -                if (!target_dir.exists()) -                    QDir("").mkpath(target_dir.path()); + +                qDebug() << target_dir.path(); +                FS::ensureFolderPathExists(target_dir.path());                  bool couldCopy = original.copy(target_path); -                qDebug() << " Copying" << original_path << "to" << target_path -                             << QString::number(couldCopy); // << original.errorString(); +                qDebug() << " Copying" << original_path << "to" << target_path << QString::number(couldCopy);              }          }          // TODO: Write last used time to virtualRoot/.lastused +        if(removeLeftovers) +        { +            for(auto & file: presentFiles) +            { +                qDebug() << "Would remove" << file; +            } +        }      } - -    return virtualRoot; +    return true;  }  } diff --git a/api/logic/minecraft/AssetsUtils.h b/api/logic/minecraft/AssetsUtils.h index 3755210c..356b8c8a 100644 --- a/api/logic/minecraft/AssetsUtils.h +++ b/api/logic/minecraft/AssetsUtils.h @@ -38,11 +38,16 @@ struct AssetsIndex      QString id;      QMap<QString, AssetObject> objects;      bool isVirtual = false; +    bool mapToResources = false;  }; +/// FIXME: this is absolutely horrendous. REDO!!!!  namespace AssetsUtils  { -bool loadAssetsIndexJson(QString id, QString file, AssetsIndex* index); +bool loadAssetsIndexJson(const QString &id, const QString &file, AssetsIndex& index); + +QDir getAssetsDir(const QString &assetsId, const QString &resourcesFolder); +  /// Reconstruct a virtual assets folder for the given assets ID and return the folder -QDir reconstructAssets(QString assetsId); +bool reconstructAssets(QString assetsId, QString resourcesFolder);  } diff --git a/api/logic/minecraft/MinecraftInstance.cpp b/api/logic/minecraft/MinecraftInstance.cpp index bf4eb1bd..449a2ed5 100644 --- a/api/logic/minecraft/MinecraftInstance.cpp +++ b/api/logic/minecraft/MinecraftInstance.cpp @@ -20,6 +20,7 @@  #include "minecraft/launch/DirectJavaLaunch.h"  #include "minecraft/launch/ModMinecraftJar.h"  #include "minecraft/launch/ClaimAccount.h" +#include "minecraft/launch/ReconstructAssets.h"  #include "java/launch/CheckJava.h"  #include "java/JavaUtils.h"  #include "meta/Index.h" @@ -216,6 +217,11 @@ QString MinecraftInstance::worldDir() const      return FS::PathCombine(gameRoot(), "saves");  } +QString MinecraftInstance::resourcesDir() const +{ +    return FS::PathCombine(gameRoot(), "resources"); +} +  QDir MinecraftInstance::librariesPath() const  {      return QDir::current().absoluteFilePath("libraries"); @@ -408,8 +414,7 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session) cons      token_mapping["game_directory"] = absRootDir;      QString absAssetsDir = QDir("assets/").absolutePath();      auto assets = profile->getMinecraftAssets(); -    // FIXME: this is wrong and should be run as an async task -    token_mapping["game_assets"] = AssetsUtils::reconstructAssets(assets->id).absolutePath(); +    token_mapping["game_assets"] = AssetsUtils::getAssetsDir(assets->id, resourcesDir()).absolutePath();      // 1.7.3+ assets tokens      token_mapping["assets_root"] = absAssetsDir; @@ -842,6 +847,12 @@ std::shared_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr s          process->appendStep(step);      } +    // reconstruct assets if needed +    { +        auto step = std::make_shared<ReconstructAssets>(pptr); +        process->appendStep(step); +    } +      {          // actually launch the game          auto method = launchMethod(); diff --git a/api/logic/minecraft/MinecraftInstance.h b/api/logic/minecraft/MinecraftInstance.h index 091d1bf7..d9fffe57 100644 --- a/api/logic/minecraft/MinecraftInstance.h +++ b/api/logic/minecraft/MinecraftInstance.h @@ -45,6 +45,7 @@ public:      QString modsCacheLocation() const;      QString libDir() const;      QString worldDir() const; +    QString resourcesDir() const;      QDir jarmodsPath() const;      QDir librariesPath() const;      QDir versionsPath() const; diff --git a/api/logic/minecraft/launch/ReconstructAssets.cpp b/api/logic/minecraft/launch/ReconstructAssets.cpp new file mode 100644 index 00000000..af9af127 --- /dev/null +++ b/api/logic/minecraft/launch/ReconstructAssets.cpp @@ -0,0 +1,36 @@ +/* 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 "ReconstructAssets.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/ComponentList.h" +#include "minecraft/AssetsUtils.h" +#include "launch/LaunchTask.h" + +void ReconstructAssets::executeTask() +{ +    auto instance = m_parent->instance(); +    std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance); +    auto components = minecraftInstance->getComponentList(); +    auto profile = components->getProfile(); +    auto assets = profile->getMinecraftAssets(); + +    if(!AssetsUtils::reconstructAssets(assets->id, minecraftInstance->resourcesDir())) +    { +        emit logLine("Failed to reconstruct Minecraft assets.", MessageLevel::Error); +    } + +    emitSucceeded(); +} diff --git a/api/logic/minecraft/launch/ReconstructAssets.h b/api/logic/minecraft/launch/ReconstructAssets.h new file mode 100644 index 00000000..228fa083 --- /dev/null +++ b/api/logic/minecraft/launch/ReconstructAssets.h @@ -0,0 +1,33 @@ +/* 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. + */ + +#pragma once + +#include <launch/LaunchStep.h> +#include <memory> + +class ReconstructAssets: public LaunchStep +{ +    Q_OBJECT +public: +    explicit ReconstructAssets(LaunchTask *parent) : LaunchStep(parent){}; +    virtual ~ReconstructAssets(){}; + +    void executeTask() override; +    bool canAbort() const override +    { +        return false; +    } +}; diff --git a/api/logic/minecraft/update/AssetUpdateTask.cpp b/api/logic/minecraft/update/AssetUpdateTask.cpp index 1661822d..051b1279 100644 --- a/api/logic/minecraft/update/AssetUpdateTask.cpp +++ b/api/logic/minecraft/update/AssetUpdateTask.cpp @@ -60,7 +60,7 @@ void AssetUpdateTask::assetIndexFinished()      QString asset_fname = "assets/indexes/" + assets->id + ".json";      // FIXME: this looks like a job for a generic validator based on json schema? -    if (!AssetsUtils::loadAssetsIndexJson(assets->id, asset_fname, &index)) +    if (!AssetsUtils::loadAssetsIndexJson(assets->id, asset_fname, index))      {          auto metacache = ENV.metacache();          auto entry = metacache->resolveEntry("asset_indexes", assets->id + ".json"); @@ -101,7 +101,7 @@ bool AssetUpdateTask::abort()      }      else      { -        qWarning() << "Prematurely aborted FMLLibrariesTask"; +        qWarning() << "Prematurely aborted AssetUpdateTask";      }      return true;  } | 
