Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor bug fix, new Modrinth API #143

Merged
merged 5 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions ProjBobcat/ProjBobcat/Class/Helper/CurseForgeAPIHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ public static void SetApiKey(string apiKey)
using var req = Req(HttpMethod.Get, reqUrl);
using var res = await Client.SendAsync(req);

res.EnsureSuccessStatusCode();

return (await res.Content.ReadFromJsonAsync(CurseForgeModelContext.Default
.DataModelCurseForgeLatestFileModelArray))?.Data;
}
Expand Down Expand Up @@ -174,11 +176,11 @@ public static void SetApiKey(string apiKey)
return (await res.Content.ReadFromJsonAsync(CurseForgeModelContext.Default.DataModelString))?.Data;
}

public static async Task<CurseForgeFuzzySearchResponseModel?> TryFuzzySearchFile(long fingerprint, int gameId = 432)
public static async Task<CurseForgeFuzzySearchResponseModel?> TryFuzzySearchFile(long[] fingerprint, int gameId = 432)
{
var reqUrl = $"{BaseUrl}/fingerprints/{gameId}";

var data = JsonSerializer.Serialize(new FuzzyFingerPrintReqModel([fingerprint]),
var data = JsonSerializer.Serialize(new FuzzyFingerPrintReqModel(fingerprint),
CurseForgeModelContext.Default.FuzzyFingerPrintReqModel);

using var req = Req(HttpMethod.Post, reqUrl);
Expand Down
58 changes: 45 additions & 13 deletions ProjBobcat/ProjBobcat/Class/Helper/GameResourcesResolveHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Threading;
using System.Threading.Tasks;
using ProjBobcat.Class.Helper.TOMLParser;
using ProjBobcat.Class.Model;
using ProjBobcat.Class.Model.Fabric;
using ProjBobcat.Class.Model.GameResource;
using ProjBobcat.Class.Model.GameResource.ResolvedInfo;
Expand Down Expand Up @@ -143,6 +144,28 @@ static async Task<GameModResolvedInfo> GetFabricModInfo(
}
}

public static ModLoaderType GetModLoaderType(IArchive archive)
{
var fabricEntry = archive.Entries.Any(e =>
e.Key.EndsWith("fabric.mod.json", StringComparison.OrdinalIgnoreCase));

if (fabricEntry) return ModLoaderType.Fabric;

var neoforgeEntry = archive.Entries.Any(e =>
e.Key.EndsWith("_neoforge.mixins.json", StringComparison.OrdinalIgnoreCase));

if (neoforgeEntry) return ModLoaderType.NeoForge;

var forgeEntry = archive.Entries.Any(e =>
e.Key.EndsWith("META-INF/mods.toml", StringComparison.OrdinalIgnoreCase));
var forgeNewEntry = archive.Entries.Any(e =>
e.Key.EndsWith("mcmod.info", StringComparison.OrdinalIgnoreCase));

if (forgeEntry || forgeNewEntry) return ModLoaderType.Forge;

return ModLoaderType.Unknown;
}

public static async IAsyncEnumerable<GameModResolvedInfo> ResolveModListAsync(
IEnumerable<string> files,
[EnumeratorCancellation] CancellationToken ct)
Expand Down Expand Up @@ -174,23 +197,31 @@ public static async IAsyncEnumerable<GameModResolvedInfo> ResolveModListAsync(

GameModResolvedInfo? result = null;

if (modInfoEntry != null)
try
{
result = await GetNewModInfo(modInfoEntry, file, isEnabled, ct);

if (result != null) goto ReturnResult;
}
if (modInfoEntry != null)
{
result = await GetNewModInfo(modInfoEntry, file, isEnabled, ct);

if (tomlInfoEntry != null)
{
result = await GetLegacyModInfo(tomlInfoEntry, file, isEnabled);
if (result != null) goto ReturnResult;
}

if (result != null) goto ReturnResult;
}
if (tomlInfoEntry != null)
{
result = await GetLegacyModInfo(tomlInfoEntry, file, isEnabled);

if (result != null) goto ReturnResult;
}

if (fabricModInfoEntry != null)
if (fabricModInfoEntry != null)
{
result = await GetFabricModInfo(fabricModInfoEntry, file, isEnabled, ct);
goto ReturnResult;
}
}
catch (Exception e)
{
result = await GetFabricModInfo(fabricModInfoEntry, file, isEnabled, ct);
Console.WriteLine(e);
goto ReturnResult;
}

Expand All @@ -202,8 +233,9 @@ public static async IAsyncEnumerable<GameModResolvedInfo> ResolveModListAsync(
null,
"Unknown",
isEnabled);

ReturnResult:
result = result! with { LoaderType = GetModLoaderType(archive) };
yield return result;
}
}
Expand Down
43 changes: 43 additions & 0 deletions ProjBobcat/ProjBobcat/Class/Helper/ModrinthAPIHelper.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using ProjBobcat.Class.Model;
using ProjBobcat.Class.Model.Modrinth;

namespace ProjBobcat.Class.Helper;

#region Temp Models

record FileMatchRequestModel(string[] hashes, string algorithm, string[] loaders, string[] game_versions);

[JsonSerializable(typeof(FileMatchRequestModel))]
partial class ModrinthModelContext : JsonSerializerContext;

#endregion

public static class ModrinthAPIHelper
{
const string BaseUrl = "https://api.modrinth.com/v2";
Expand Down Expand Up @@ -110,4 +123,34 @@ await res.Content.ReadFromJsonAsync(ModrinthProjectDependencyInfoContext.Default

return resModel;
}

public static async Task<ModrinthVersionInfo?> GetVersionInfo(string versionId)
{
var reqUrl = $"{BaseUrl}/version/{versionId}";

using var res = await Get(reqUrl);
var resModel = await res.Content.ReadFromJsonAsync(ModrinthVersionInfoContext.Default.ModrinthVersionInfo);

return resModel;
}

public static async Task<IReadOnlyDictionary<string, ModrinthVersionInfo>?> TryMatchFile(
string[] hashes,
string algorithm,
string[] loaders,
string[] game_versions)
{
const string reqUrl = $"{BaseUrl}/version_files/update";

var data = JsonSerializer.Serialize(new FileMatchRequestModel(hashes, algorithm, loaders, game_versions),
ModrinthModelContext.Default.FileMatchRequestModel);

using var res = await HttpHelper.Post(reqUrl, data);


if (!res.IsSuccessStatusCode) return null;

return await res.Content.ReadFromJsonAsync(ModrinthVersionInfoContext.Default
.IReadOnlyDictionaryStringModrinthVersionInfo);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@

namespace ProjBobcat.Class.Model.CurseForge;

public class CurseForgeFileHashModel
{
[JsonPropertyName("algo")] public int Algorithm { get; init; }
[JsonPropertyName("value")] public string? Value { get; init; }
}

public class CurseForgeLatestFileModel
{
[JsonPropertyName("id")] public int Id { get; set; }
[JsonPropertyName("id")] public long Id { get; set; }

[JsonPropertyName("displayName")] public required string DisplayName { get; init; }

Expand All @@ -28,13 +34,18 @@ public class CurseForgeLatestFileModel

[JsonPropertyName("dependencies")] public CurseForgeDependencyModel[]? Dependencies { get; set; }

[JsonPropertyName("hashes")] public CurseForgeFileHashModel[]? Hashes { get; set; }

[JsonPropertyName("isAvailable")] public bool IsAvailable { get; set; }

[JsonPropertyName("modules")] public CurseForgeModuleModel[]? Modules { get; set; }

[JsonPropertyName("packageFingerprint")]
public long PackageFingerprint { get; set; }

[JsonPropertyName("fileFingerprint")]
public long FileFingerprint { get; set; }

[JsonPropertyName("gameVersions")] public required string[] GameVersions { get; init; }

[JsonPropertyName("sortableGameVersion")]
Expand Down
2 changes: 1 addition & 1 deletion ProjBobcat/ProjBobcat/Class/Model/DownloadSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class DownloadSettings
/// </summary>
public string? Host { get; init; }

public async ValueTask<byte[]> HashDataAsync(Stream stream, CancellationToken? token)
public async Task<byte[]> HashDataAsync(Stream stream, CancellationToken? token)
{
token ??= CancellationToken.None;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ public record GameModResolvedInfo(
string? Title,
string? Version,
string? ModType,
bool IsEnabled);
bool IsEnabled)
{
public ModLoaderType LoaderType { get; init; }
}
10 changes: 10 additions & 0 deletions ProjBobcat/ProjBobcat/Class/Model/ModLoaderType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace ProjBobcat.Class.Model;

public enum ModLoaderType
{
Forge,
NeoForge,
Fabric,
Quilt,
Unknown
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,4 @@ public class ModrinthCategoryInfo

[JsonSerializable(typeof(ModrinthCategoryInfo))]
[JsonSerializable(typeof(ModrinthCategoryInfo[]))]
partial class ModrinthCategoryInfoContext : JsonSerializerContext
{
}
partial class ModrinthCategoryInfoContext : JsonSerializerContext;
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text;
using System.Collections.Generic;
using System.Text;

namespace ProjBobcat.Class.Model.Modrinth;

Expand All @@ -7,19 +8,25 @@ public class ModrinthSearchOptions
public string? Name { get; init; }
public string? Category { get; init; }
public string Index { get; init; } = "relevance";
public string? ProjectType { get; init; } = "mod";
public string? ProjectType { get; init; }
public int? Offset { get; init; }
public int? Limit { get; set; }

public override string ToString()
{
var sb = new StringBuilder($"?query={Name ?? "any"}&index={Index}&facets=[");
var projType = $"[\"project_type:{ProjectType}\"]";
var sb = new StringBuilder($"?query={Name ?? "any"}&index={Index}");

if (!string.IsNullOrEmpty(Category)) sb.Append($"[\"categories:{Category}\"],");
var facets = new List<string>();

sb.Append(projType);
sb.Append(']');
if (!string.IsNullOrEmpty(Category))
facets.Add($"[\"categories:{Category}\"]");
if (!string.IsNullOrEmpty(ProjectType))
facets.Add($"[\"project_type:{ProjectType}\"]");

if (facets.Count > 0)
sb.Append("&facets=[")
.AppendJoin(',', facets)
.Append(']');

if (Offset != null) sb.Append($"&offset={Offset}");
if (Limit != null) sb.Append($"&limit={Limit}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,5 @@ public class ModrinthVersionInfo

[JsonSerializable(typeof(ModrinthVersionInfo))]
[JsonSerializable(typeof(ModrinthVersionInfo[]))]
[JsonSerializable(typeof(IReadOnlyDictionary<string, ModrinthVersionInfo>))]
partial class ModrinthVersionInfoContext : JsonSerializerContext;
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public void Install()
InstallTaskAsync().Wait();
}

public static async ValueTask<(string? FileName, string? Url)> TryGuessModDownloadLink(long fileId)
public static async Task<(string? FileName, string? Url)> TryGuessModDownloadLink(long fileId)
{
try
{
Expand Down Expand Up @@ -69,7 +69,7 @@ public void Install()
}
}

async ValueTask<(bool, DownloadFile?)> TryGuessModDownloadLink(long fileId, string downloadPath)
async Task<(bool, DownloadFile?)> TryGuessModDownloadLink(long fileId, string downloadPath)
{
var pair = await TryGuessModDownloadLink(fileId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ public override (List<NativeFileInfo>, List<FileInfo>) GetNatives(Library[] libr
Logging = rawVersion.Logging,
Id = rawVersion.Id,
InheritsFrom = rawVersion.InheritsFrom,
GameBaseVersion = GameVersionHelper.TryGetMcVersion([.. (inherits ?? []), rawVersion]) ?? id,
GameBaseVersion = GameVersionHelper.TryGetMcVersion([.. inherits ?? [], rawVersion]) ?? id,
DirName = id,
Name = id,
JavaVersion = rawVersion.JavaVersion,
Expand Down Expand Up @@ -559,7 +559,7 @@ public override (List<NativeFileInfo>, List<FileInfo>) GetNatives(Library[] libr
}
}

rawLibs = NativeReplaceHelper.Replace([rawVersion, ..inherits ?? []], rawLibs, NativeReplacementPolicy);
rawLibs = NativeReplaceHelper.Replace([rawVersion, .. inherits ?? []], rawLibs, NativeReplacementPolicy);

var libs = GetNatives([.. rawLibs]);

Expand All @@ -583,40 +583,28 @@ void ProcessProfile(VersionInfo result, string id)
if (LauncherProfileParser == null) return;

var gameId = id.ToGuidHash().ToString("N");
var (oldProfileKey, oldProfileModel) =
LauncherProfileParser.LauncherProfile.Profiles!
.FirstOrDefault(p => p.Key.Equals(gameId, StringComparison.OrdinalIgnoreCase));

var gamePath = Path.Combine(RootPath, GamePathHelper.GetGamePath(id));

if (string.IsNullOrEmpty(oldProfileKey) || oldProfileModel == null)
if (LauncherProfileParser.LauncherProfile.Profiles!.TryGetValue(gameId, out var oldProfileModel))
{
var gameProfile = new GameProfileModel
{
GameDir = gamePath,
LastVersionId = id,
Name = id,
Created = DateTime.Now
};

if (!string.IsNullOrEmpty(oldProfileKey) &&
LauncherProfileParser.LauncherProfile.Profiles!.ContainsKey(oldProfileKey))
{
LauncherProfileParser.LauncherProfile.Profiles![oldProfileKey] = gameProfile;
LauncherProfileParser.SaveProfile();
return;
}

LauncherProfileParser.LauncherProfile.Profiles!.Add(gameId, gameProfile);
result.Name = oldProfileModel.Name!;
oldProfileModel.GameDir = gamePath;
oldProfileModel.LastVersionId = id;
LauncherProfileParser.LauncherProfile.Profiles![gameId] = oldProfileModel;
LauncherProfileParser.SaveProfile();

return;
}

result.Name = oldProfileModel.Name!;
oldProfileModel.GameDir = gamePath;
oldProfileModel.LastVersionId = id;
LauncherProfileParser.LauncherProfile.Profiles![oldProfileKey] = oldProfileModel;
var gameProfile = new GameProfileModel
{
GameDir = gamePath,
LastVersionId = id,
Name = id,
Created = DateTime.Now
};

LauncherProfileParser.LauncherProfile.Profiles!.Add(gameId, gameProfile);
LauncherProfileParser.SaveProfile();
}
}