summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2013-12-08 22:19:58 +0100
committerPetr Mrázek <peterix@gmail.com>2013-12-08 22:19:58 +0100
commit8db2e5db81c91cca9291ca35ed74e632278563e6 (patch)
treeb4aa9ff8db2561e674e03027b05107a973e4d3a5
parentb0dbd4f4afcf60e4021cbb3218bfe280c4989859 (diff)
parent2fe27fd0daca14644a2a71456cd60c9a38befbdf (diff)
downloadMultiMC-8db2e5db81c91cca9291ca35ed74e632278563e6.tar
MultiMC-8db2e5db81c91cca9291ca35ed74e632278563e6.tar.gz
MultiMC-8db2e5db81c91cca9291ca35ed74e632278563e6.tar.lz
MultiMC-8db2e5db81c91cca9291ca35ed74e632278563e6.tar.xz
MultiMC-8db2e5db81c91cca9291ca35ed74e632278563e6.zip
Merge branch 'feature_assets' into develop
-rw-r--r--CMakeLists.txt8
-rw-r--r--gui/MainWindow.cpp6
-rw-r--r--logic/OneSixInstance.cpp65
-rw-r--r--logic/OneSixInstance.h2
-rw-r--r--logic/OneSixVersion.cpp16
-rw-r--r--logic/OneSixVersion.h2
-rw-r--r--logic/assets/Assets.cpp14
-rw-r--r--logic/assets/Assets.h16
-rw-r--r--logic/assets/AssetsIndex.cpp31
-rw-r--r--logic/assets/AssetsIndex.h42
-rw-r--r--logic/assets/AssetsUtils.cpp224
-rw-r--r--logic/assets/AssetsUtils.h24
12 files changed, 447 insertions, 3 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 11b64c3d..2c27ca81 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -384,6 +384,14 @@ logic/NagUtils.cpp
logic/SkinUtils.h
logic/SkinUtils.cpp
+# Assets
+logic/assets/AssetsIndex.h
+logic/assets/AssetsIndex.cpp
+logic/assets/AssetsUtils.h
+logic/assets/AssetsUtils.cpp
+logic/assets/Assets.h
+logic/assets/Assets.cpp
+
)
diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp
index bf2ce6b4..b080f610 100644
--- a/gui/MainWindow.cpp
+++ b/gui/MainWindow.cpp
@@ -80,6 +80,8 @@
#include "logic/LegacyInstance.h"
+#include "logic/assets/AssetsUtils.h"
+
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
MultiMCPlatform::fixWM_CLASS(this);
@@ -239,7 +241,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
SLOT(assetsFilesProgress(int, int, int)));
connect(assets_downloader, SIGNAL(failed()), SLOT(assetsFailed()));
connect(assets_downloader, SIGNAL(finished()), SLOT(assetsFinished()));
- assets_downloader->start();
+ //assets_downloader->start();
}
const QString currentInstanceId = MMC->settings()->get("SelectedInstance").toString();
@@ -263,6 +265,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
// removing this looks stupid
view->setFocus();
+
+ AssetsUtils::migrateOldAssets();
}
MainWindow::~MainWindow()
diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp
index b18dd2ba..e804de11 100644
--- a/logic/OneSixInstance.cpp
+++ b/logic/OneSixInstance.cpp
@@ -26,6 +26,8 @@
#include <JlCompress.h>
#include "gui/dialogs/OneSixModEditDialog.h"
#include "logger/QsLog.h"
+#include "logic/assets/AssetsIndex.h"
+#include "logic/assets/AssetsUtils.h"
OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *setting_obj,
QObject *parent)
@@ -66,6 +68,63 @@ QString replaceTokensIn(QString text, QMap<QString, QString> with)
return result;
}
+QDir OneSixInstance::reconstructAssets(std::shared_ptr<OneSixVersion> version)
+{
+ QDir assetsDir = QDir("assets/");
+ QDir indexDir = QDir(PathCombine(assetsDir.path(), "indexes"));
+ QDir objectDir = QDir(PathCombine(assetsDir.path(), "objects"));
+ QDir virtualDir = QDir(PathCombine(assetsDir.path(), "virtual"));
+
+ QString indexPath = PathCombine(indexDir.path(), version->assets + ".json");
+ QFile indexFile(indexPath);
+ QDir virtualRoot(PathCombine(virtualDir.path(), version->assets));
+
+ if(!indexFile.exists())
+ {
+ QLOG_ERROR() << "No assets index file" << indexPath << "; can't reconstruct assets";
+ return virtualRoot;
+ }
+
+ QLOG_DEBUG() << "reconstructAssets" << assetsDir.path() << indexDir.path() << objectDir.path() << virtualDir.path() << virtualRoot.path();
+
+ AssetsIndex index;
+ bool loadAssetsIndex = AssetsUtils::loadAssetsIndexJson(indexPath, &index);
+
+ if(loadAssetsIndex)
+ {
+ if(index.isVirtual)
+ {
+ QLOG_INFO() << "Reconstructing virtual assets folder at" << virtualRoot.path();
+
+ for(QString map : index.objects->keys())
+ {
+ AssetObject asset_object = index.objects->value(map);
+ QString target_path = PathCombine(virtualRoot.path(), map);
+ QFile target(target_path);
+
+ QString tlk = asset_object.hash.left(2);
+
+ QString original_path = PathCombine(PathCombine(objectDir.path(), tlk), asset_object.hash);
+ QFile original(original_path);
+ if(!target.exists())
+ {
+ QFileInfo info(target_path);
+ QDir target_dir = info.dir();
+ //QLOG_DEBUG() << target_dir;
+ if(!target_dir.exists()) QDir("").mkpath(target_dir.path());
+
+ bool couldCopy = original.copy(target_path);
+ QLOG_DEBUG() << " Copying" << original_path << "to" << target_path << QString::number(couldCopy);// << original.errorString();
+ }
+ }
+
+ // TODO: Write last used time to virtualRoot/.lastused
+ }
+ }
+
+ return virtualRoot;
+}
+
QStringList OneSixInstance::processMinecraftArgs(MojangAccountPtr account)
{
I_D(OneSixInstance);
@@ -93,10 +152,14 @@ QStringList OneSixInstance::processMinecraftArgs(MojangAccountPtr account)
QString absRootDir = QDir(minecraftRoot()).absolutePath();
token_mapping["game_directory"] = absRootDir;
QString absAssetsDir = QDir("assets/").absolutePath();
- token_mapping["game_assets"] = absAssetsDir;
+ token_mapping["game_assets"] = reconstructAssets(d->version).absolutePath();
//TODO: this is something new and not even fully implemented in the vanilla launcher.
token_mapping["user_properties"] = "{ }";
+ // 1.7.3+ assets tokens
+ token_mapping["assets_root"] = absAssetsDir;
+ token_mapping["assets_index_name"] = version->assets;
+
QStringList parts = args_pattern.split(' ', QString::SkipEmptyParts);
for (int i = 0; i < parts.length(); i++)
{
diff --git a/logic/OneSixInstance.h b/logic/OneSixInstance.h
index cdfdf324..f869e345 100644
--- a/logic/OneSixInstance.h
+++ b/logic/OneSixInstance.h
@@ -16,6 +16,7 @@
#pragma once
#include <QStringList>
+#include <QDir>
#include "BaseInstance.h"
@@ -73,4 +74,5 @@ public:
private:
QStringList processMinecraftArgs(MojangAccountPtr account);
+ QDir reconstructAssets(std::shared_ptr<OneSixVersion> version);
};
diff --git a/logic/OneSixVersion.cpp b/logic/OneSixVersion.cpp
index cc5b1de1..e586402b 100644
--- a/logic/OneSixVersion.cpp
+++ b/logic/OneSixVersion.cpp
@@ -17,6 +17,8 @@
#include "logic/OneSixLibrary.h"
#include "logic/OneSixRule.h"
+#include "logger/QsLog.h"
+
std::shared_ptr<OneSixVersion> fromJsonV4(QJsonObject root,
std::shared_ptr<OneSixVersion> fullVersion)
{
@@ -60,6 +62,18 @@ std::shared_ptr<OneSixVersion> fromJsonV4(QJsonObject root,
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())
@@ -151,7 +165,7 @@ std::shared_ptr<OneSixVersion> OneSixVersion::fromJson(QJsonObject root)
root.value("minimumLauncherVersion").toDouble();
// ADD MORE HERE :D
- if (launcher_ver > 0 && launcher_ver <= 11)
+ if (launcher_ver > 0 && launcher_ver <= 12)
return fromJsonV4(root, readVersion);
else
{
diff --git a/logic/OneSixVersion.h b/logic/OneSixVersion.h
index 5718dafe..036f3d53 100644
--- a/logic/OneSixVersion.h
+++ b/logic/OneSixVersion.h
@@ -56,6 +56,8 @@ public:
QString releaseTime;
/// Release type - "release" or "snapshot"
QString type;
+ /// Assets type - "legacy" or a version ID
+ QString assets;
/**
* DEPRECATED: Old versions of the new vanilla launcher used this
* ex: "username_session_version"
diff --git a/logic/assets/Assets.cpp b/logic/assets/Assets.cpp
new file mode 100644
index 00000000..a0764674
--- /dev/null
+++ b/logic/assets/Assets.cpp
@@ -0,0 +1,14 @@
+/* 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.
+ */
diff --git a/logic/assets/Assets.h b/logic/assets/Assets.h
new file mode 100644
index 00000000..09998ff8
--- /dev/null
+++ b/logic/assets/Assets.h
@@ -0,0 +1,16 @@
+/* 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
diff --git a/logic/assets/AssetsIndex.cpp b/logic/assets/AssetsIndex.cpp
new file mode 100644
index 00000000..509f1add
--- /dev/null
+++ b/logic/assets/AssetsIndex.cpp
@@ -0,0 +1,31 @@
+/* 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 "AssetsIndex.h"
+
+AssetsIndex::AssetsIndex()
+{
+ // TODO: leak?
+ this->objects = new QMap<QString, AssetObject>();
+ this->isVirtual = false;
+}
+
+AssetObject::AssetObject(QString hash, qint64 size) : hash(hash), size(size)
+{
+}
+
+AssetObject::AssetObject()
+{
+}
diff --git a/logic/assets/AssetsIndex.h b/logic/assets/AssetsIndex.h
new file mode 100644
index 00000000..09ef0d92
--- /dev/null
+++ b/logic/assets/AssetsIndex.h
@@ -0,0 +1,42 @@
+/* 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>
+#include <QMap>
+
+class AssetObject;
+
+class AssetsIndex
+{
+public:
+ QMap<QString, AssetObject> *objects;
+ bool isVirtual;
+
+ AssetsIndex();
+};
+
+class AssetObject
+{
+public:
+ AssetObject(QString hash, qint64 size);
+ AssetObject();
+ bool equals(AssetObject* other);
+ QString getHashCode();
+
+ QString hash;
+ qint64 size;
+};
diff --git a/logic/assets/AssetsUtils.cpp b/logic/assets/AssetsUtils.cpp
new file mode 100644
index 00000000..8d7d6f46
--- /dev/null
+++ b/logic/assets/AssetsUtils.cpp
@@ -0,0 +1,224 @@
+/* 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 <QDir>
+#include <QDirIterator>
+#include <QCryptographicHash>
+#include <QJsonParseError>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+#include "AssetsUtils.h"
+#include "MultiMC.h"
+
+namespace AssetsUtils
+{
+void migrateOldAssets()
+{
+ QDir assets_dir("assets");
+ if(!assets_dir.exists()) return;
+ assets_dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
+ int base_length = assets_dir.path().length();
+
+ QList<QString> blacklist = {"indexes", "objects", "virtual"};
+
+ if(!assets_dir.exists("objects")) assets_dir.mkdir("objects");
+ QDir objects_dir("assets/objects");
+
+ QDirIterator iterator(assets_dir, QDirIterator::Subdirectories);
+ int successes = 0;
+ int failures = 0;
+ while (iterator.hasNext()) {
+ QString currentDir = iterator.next();
+ currentDir = currentDir.remove(0, base_length+1);
+
+ bool ignore = false;
+ for(QString blacklisted : blacklist)
+ {
+ if(currentDir.startsWith(blacklisted)) ignore = true;
+ }
+
+ if (!iterator.fileInfo().isDir() && !ignore) {
+ QString filename = iterator.filePath();
+
+ QFile input(filename);
+ input.open(QIODevice::ReadOnly | QIODevice::WriteOnly);
+ QString sha1sum = QCryptographicHash::hash(input.readAll(), QCryptographicHash::Sha1)
+ .toHex()
+ .constData();
+
+ QString object_name = filename.remove(0, base_length+1);
+ QLOG_DEBUG() << "Processing" << object_name << ":" << sha1sum << input.size();
+
+ QString object_tlk = sha1sum.left(2);
+ QString object_tlk_dir = objects_dir.path() + "/" + object_tlk;
+
+ QDir tlk_dir(object_tlk_dir);
+ if(!tlk_dir.exists()) objects_dir.mkdir(object_tlk);
+
+ QString new_filename = tlk_dir.path() + "/" + sha1sum;
+ QFile new_object(new_filename);
+ if(!new_object.exists())
+ {
+ bool rename_success = input.rename(new_filename);
+ QLOG_DEBUG() << " Doesn't exist, copying to" << new_filename << ":" << QString::number(rename_success);
+ if(rename_success) successes++;
+ else failures++;
+ }
+ else
+ {
+ input.remove();
+ QLOG_DEBUG() << " Already exists, deleting original and not copying.";
+ }
+ }
+ }
+
+ if(successes + failures == 0) {
+ QLOG_DEBUG() << "No legacy assets needed importing.";
+ }
+ else
+ {
+ QLOG_DEBUG() << "Finished copying legacy assets:" << successes << "successes and" << failures << "failures.";
+
+ QDirIterator cleanup_iterator(assets_dir);
+
+ while (cleanup_iterator.hasNext()) {
+ QString currentDir = cleanup_iterator.next();
+ currentDir = currentDir.remove(0, base_length+1);
+
+ bool ignore = false;
+ for(QString blacklisted : blacklist)
+ {
+ if(currentDir.startsWith(blacklisted)) ignore = true;
+ }
+
+ if (cleanup_iterator.fileInfo().isDir() && !ignore) {
+ QString path = cleanup_iterator.filePath();
+ QDir folder(path);
+
+ QLOG_DEBUG() << "Cleaning up legacy assets folder:" << path;
+
+ folder.removeRecursively();
+ }
+ }
+ }
+}
+
+/*
+ * Returns true on success, with index populated
+ * index is undefined otherwise
+ */
+bool loadAssetsIndexJson(QString path, AssetsIndex *index)
+{
+/*
+{
+ "objects": {
+ "icons/icon_16x16.png": {
+ "hash": "bdf48ef6b5d0d23bbb02e17d04865216179f510a",
+ "size": 3665
+ },
+ ...
+ }
+ }
+}
+*/
+
+ QFile file(path);
+
+ // Try to open the file and fail if we can't.
+ // TODO: We should probably report this error to the user.
+ if (!file.open(QIODevice::ReadOnly))
+ {
+ QLOG_ERROR() << "Failed to read assets index file" << path;
+ return false;
+ }
+
+ // Read the file and close it.
+ QByteArray jsonData = file.readAll();
+ file.close();
+
+ QJsonParseError parseError;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError);
+
+ // Fail if the JSON is invalid.
+ if (parseError.error != QJsonParseError::NoError)
+ {
+ QLOG_ERROR() << "Failed to parse assets index file:" << parseError.errorString() << "at offset " << QString::number(parseError.offset);
+ return false;
+ }
+
+ // Make sure the root is an object.
+ if (!jsonDoc.isObject())
+ {
+ QLOG_ERROR() << "Invalid assets index JSON: Root should be an array.";
+ return false;
+ }
+
+ QJsonObject root = jsonDoc.object();
+
+ QJsonValue isVirtual = root.value("virtual");
+ if(!isVirtual.isUndefined())
+ {
+ index->isVirtual = isVirtual.toBool(false);
+ }
+
+ QJsonValue objects = root.value("objects");
+ QVariantMap map = objects.toVariant().toMap();
+
+ for(QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) {
+ //QLOG_DEBUG() << iter.key();
+
+ QVariant variant = iter.value();
+ QVariantMap nested_objects = variant.toMap();
+
+ AssetObject object;
+
+ for(QVariantMap::const_iterator nested_iter = nested_objects.begin(); nested_iter != nested_objects.end(); ++nested_iter) {
+ //QLOG_DEBUG() << nested_iter.key() << nested_iter.value().toString();
+ QString key = nested_iter.key();
+ QVariant value = nested_iter.value();
+
+ if(key == "hash")
+ {
+ object.hash = value.toString();
+ }
+ else if(key == "size")
+ {
+ object.size = value.toDouble();
+ }
+ }
+
+ index->objects->insert(iter.key(), object);
+ }
+
+ return true;
+ /*for (QJsonValue accountVal : objects)
+ {
+ QJsonObject accountObj = accountVal.toObject();
+ MojangAccountPtr account = MojangAccount::loadFromJson(accountObj);
+ if (account.get() != nullptr)
+ {
+ connect(account.get(), SIGNAL(changed()), SLOT(accountChanged()));
+ m_accounts.append(account);
+ }
+ else
+ {
+ QLOG_WARN() << "Failed to load an account.";
+ }
+ }*/
+
+ //return false;
+}
+}
diff --git a/logic/assets/AssetsUtils.h b/logic/assets/AssetsUtils.h
new file mode 100644
index 00000000..88a3b0dc
--- /dev/null
+++ b/logic/assets/AssetsUtils.h
@@ -0,0 +1,24 @@
+/* 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 "AssetsIndex.h"
+
+namespace AssetsUtils
+{
+void migrateOldAssets();
+bool loadAssetsIndexJson(QString file, AssetsIndex* index);
+}