1 parent
ebf8ff7869
commit
41599fa82f
67 files changed
+8775
-4
No files matched your search
@@ -0,0 +1,194 @@
|
||||
#include "fakemojang.h"
|
||||
|
||||
#include "fixtures.h"
|
||||
|
||||
#include "minecraftversion.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace {
|
||||
|
||||
const QString kMeta = QStringLiteral("https://piston-meta.mojang.com/v1/packages/");
|
||||
const QString kData = QStringLiteral("https://piston-data.mojang.com/v1/objects/");
|
||||
const QString kLibraries = QStringLiteral("https://libraries.minecraft.net/");
|
||||
const QString kResources = QStringLiteral("https://resources.download.minecraft.net/");
|
||||
|
||||
QJsonObject download(const QString &url, const QByteArray &data, const QString &path = {})
|
||||
{
|
||||
QJsonObject object{{"url", url}, {"sha1", Fixtures::sha1(data)}, {"size", data.size()}};
|
||||
if (!path.isEmpty())
|
||||
object.insert("path", path);
|
||||
return object;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
FakeMojang::FakeMojang(FakeInternet &net)
|
||||
: m_net(net)
|
||||
{
|
||||
}
|
||||
|
||||
QString FakeMojang::manifestUrl()
|
||||
{
|
||||
return QStringLiteral("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json");
|
||||
}
|
||||
|
||||
QString FakeMojang::addObject(const QString &relativePath, const QByteArray &data)
|
||||
{
|
||||
QString url;
|
||||
if (relativePath.startsWith(QLatin1String("libraries/")))
|
||||
url = kLibraries + relativePath.mid(int(sizeof("libraries/") - 1));
|
||||
else if (relativePath.startsWith(QLatin1String("assets/objects/")))
|
||||
url = kResources + relativePath.mid(int(sizeof("assets/objects/") - 1));
|
||||
else
|
||||
url = kData + Fixtures::sha1(data) + u'/' + relativePath.section(u'/', -1);
|
||||
|
||||
m_files.insert(relativePath, {url, data});
|
||||
m_net.route(url, FakeResponse::bytes(data));
|
||||
return url;
|
||||
}
|
||||
|
||||
void FakeMojang::overrideFile(const QString &relativePath, const FakeResponse &response)
|
||||
{
|
||||
m_net.route(m_files.value(relativePath).url, response);
|
||||
}
|
||||
|
||||
QString FakeMojang::fileUrl(const QString &relativePath) const
|
||||
{
|
||||
return m_files.value(relativePath).url;
|
||||
}
|
||||
|
||||
void FakeMojang::publish(const VersionSpec &spec)
|
||||
{
|
||||
QHash<QString, QByteArray> expected;
|
||||
QJsonObject json{{"id", spec.id}, {"type", spec.type}, {"releaseTime", spec.releaseTime}};
|
||||
|
||||
if (!spec.inheritsFrom.isEmpty()) {
|
||||
json.insert("inheritsFrom", spec.inheritsFrom);
|
||||
json.insert("mainClass", "net.fabricmc.loader.impl.launch.knot.KnotClient");
|
||||
const QString libPath = QStringLiteral("net/fabricmc/fabric-loader/0.16.10/fabric-loader-0.16.10.jar");
|
||||
const QByteArray libData = "fabric-loader-" + spec.id.toUtf8();
|
||||
const QString url = addObject("libraries/" + libPath, libData);
|
||||
json.insert("libraries", QJsonArray{QJsonObject{
|
||||
{"name", "net.fabricmc:fabric-loader:0.16.10"},
|
||||
{"downloads", QJsonObject{{"artifact", download(url, libData, libPath)}}}}});
|
||||
expected.insert("libraries/" + libPath, libData);
|
||||
} else {
|
||||
json.insert("mainClass", "net.minecraft.client.main.Main");
|
||||
json.insert("arguments", QJsonObject{
|
||||
{"game", QJsonArray{"--username", "${auth_player_name}", "--version", "${version_name}",
|
||||
"--gameDir", "${game_directory}", "--assetsDir", "${assets_root}",
|
||||
"--assetIndex", "${assets_index_name}", "--uuid", "${auth_uuid}",
|
||||
"--accessToken", "${auth_access_token}", "--userType", "${user_type}",
|
||||
"--versionType", "${version_type}"}},
|
||||
{"jvm", QJsonArray{"-Djava.library.path=${natives_directory}", "-cp", "${classpath}"}}});
|
||||
json.insert("javaVersion", QJsonObject{{"component", "java-runtime-gamma"}, {"majorVersion", spec.javaMajor}});
|
||||
|
||||
// client.jar
|
||||
const QString clientPath = "versions/" + spec.id + u'/' + spec.id + ".jar";
|
||||
const QByteArray clientData = "client-jar-of-" + spec.id.toUtf8();
|
||||
const QString clientUrl = addObject(clientPath, clientData);
|
||||
json.insert("downloads", QJsonObject{{"client", download(clientUrl, clientData)}});
|
||||
expected.insert(clientPath, clientData);
|
||||
|
||||
// Обычная библиотека и натив под текущую платформу.
|
||||
const QString native = VersionLoader::nativeClassifier();
|
||||
const QString libPath = QStringLiteral("com/mojang/brigadier/1.1.8/brigadier-1.1.8.jar");
|
||||
const QByteArray libData = "brigadier";
|
||||
const QString nativePath = QStringLiteral("org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-%1.jar").arg(native);
|
||||
const QByteArray nativeData = Fixtures::zipBytes({{"liblwjgl.so", "so"}, {"lwjgl.dll", "dll"},
|
||||
{"liblwjgl.dylib", "dylib"}});
|
||||
const QString libUrl = addObject("libraries/" + libPath, libData);
|
||||
const QString nativeUrl = addObject("libraries/" + nativePath, nativeData);
|
||||
json.insert("libraries", QJsonArray{
|
||||
QJsonObject{{"name", "com.mojang:brigadier:1.1.8"},
|
||||
{"downloads", QJsonObject{{"artifact", download(libUrl, libData, libPath)}}}},
|
||||
QJsonObject{{"name", "org.lwjgl:lwjgl:3.3.1:" + native},
|
||||
{"downloads", QJsonObject{{"artifact", download(nativeUrl, nativeData, nativePath)}}},
|
||||
{"rules", QJsonArray{QJsonObject{{"action", "allow"},
|
||||
{"os", QJsonObject{{"name", VersionLoader::osName()}}}}}}}});
|
||||
expected.insert("libraries/" + libPath, libData);
|
||||
expected.insert("libraries/" + nativePath, nativeData);
|
||||
|
||||
// Ассеты.
|
||||
const QString indexId = spec.legacyAssets ? QStringLiteral("legacy") : spec.id + "-assets";
|
||||
QJsonObject objects;
|
||||
qint64 total = 0;
|
||||
for (const QString &name : {QStringLiteral("minecraft/sounds/click.ogg"), QStringLiteral("icons/icon_16x16.png")}) {
|
||||
const QByteArray data = (name + "@" + spec.id).toUtf8();
|
||||
const QString hash = Fixtures::sha1(data);
|
||||
const QString objectPath = "assets/objects/" + hash.left(2) + u'/' + hash;
|
||||
addObject(objectPath, data);
|
||||
objects.insert(name, QJsonObject{{"hash", hash}, {"size", data.size()}});
|
||||
expected.insert(objectPath, data);
|
||||
if (spec.legacyAssets)
|
||||
expected.insert("assets/virtual/legacy/" + name, data);
|
||||
total += data.size();
|
||||
}
|
||||
QJsonObject index{{"objects", objects}};
|
||||
if (spec.legacyAssets)
|
||||
index.insert("virtual", true);
|
||||
const QByteArray indexData = QJsonDocument(index).toJson(QJsonDocument::Compact);
|
||||
const QString indexPath = "assets/indexes/" + indexId + ".json";
|
||||
const QString indexUrl = addObject(indexPath, indexData);
|
||||
QJsonObject assetIndex = download(indexUrl, indexData);
|
||||
assetIndex.insert("id", indexId);
|
||||
assetIndex.insert("totalSize", total);
|
||||
json.insert("assetIndex", assetIndex);
|
||||
json.insert("assets", indexId);
|
||||
expected.insert(indexPath, indexData);
|
||||
|
||||
// Конфиг логирования.
|
||||
const QByteArray logData = "<Configuration/>";
|
||||
const QString logPath = QStringLiteral("assets/log_configs/client-1.12.xml");
|
||||
const QString logUrl = addObject(logPath, logData);
|
||||
QJsonObject logFile = download(logUrl, logData);
|
||||
logFile.insert("id", "client-1.12.xml");
|
||||
json.insert("logging", QJsonObject{{"client", QJsonObject{
|
||||
{"argument", "-Dlog4j.configurationFile=${path}"},
|
||||
{"file", logFile}, {"type", "log4j2-xml"}}}});
|
||||
expected.insert(logPath, logData);
|
||||
}
|
||||
|
||||
const QByteArray jsonData = QJsonDocument(json).toJson(QJsonDocument::Compact);
|
||||
m_versionJson.insert(spec.id, jsonData);
|
||||
expected.insert("versions/" + spec.id + u'/' + spec.id + ".json", jsonData);
|
||||
m_expected.insert(spec.id, expected);
|
||||
m_net.route(versionJsonUrl(spec.id), FakeResponse::json(jsonData));
|
||||
|
||||
m_specs.removeIf([&](const VersionSpec &s) { return s.id == spec.id; });
|
||||
m_specs << spec;
|
||||
routeManifest();
|
||||
}
|
||||
|
||||
QString FakeMojang::versionJsonUrl(const QString &id) const
|
||||
{
|
||||
return kMeta + Fixtures::sha1(m_versionJson.value(id)) + u'/' + id + ".json";
|
||||
}
|
||||
|
||||
QByteArray FakeMojang::versionJson(const QString &id) const
|
||||
{
|
||||
return m_versionJson.value(id);
|
||||
}
|
||||
|
||||
void FakeMojang::routeManifest()
|
||||
{
|
||||
QJsonArray versions;
|
||||
for (const VersionSpec &spec : std::as_const(m_specs)) {
|
||||
if (!spec.listed)
|
||||
continue;
|
||||
versions << QJsonObject{{"id", spec.id},
|
||||
{"type", spec.type},
|
||||
{"url", versionJsonUrl(spec.id)},
|
||||
{"sha1", Fixtures::sha1(m_versionJson.value(spec.id))},
|
||||
{"releaseTime", spec.releaseTime},
|
||||
{"time", spec.releaseTime}};
|
||||
}
|
||||
m_net.route(manifestUrl(), FakeResponse::json(QJsonObject{{"versions", versions}}));
|
||||
}
|
||||
|
||||
QHash<QString, QByteArray> FakeMojang::expectedFiles(const QString &id) const
|
||||
{
|
||||
return m_expected.value(id);
|
||||
}
|
||||
Reference in new issue
Block a user