Skip to content
Draft
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
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"dotnet.preferCSharpExtension": true
}
4 changes: 4 additions & 0 deletions PCL.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@
<Compile Include="Utils\Logger\Logger.cs" />
<Compile Include="Utils\Logger\LoggerConfiguration.cs" />
<Compile Include="Utils\Logger\LoggerSegmentMode.cs" />
<Compile Include="Utils\Modpack\CurseForge.cs" />
<Compile Include="Utils\Mod\CurseForge.cs" />
<Compile Include="Utils\Network.cs" />
<Compile Include="Utils\Override.cs" />
<Compile Include="Utils\PEHeaderReader.cs" />
<Compile Include="Utils\RoutedWebServer.cs" />
<Compile Include="Utils\StringStream.cs" />
Expand Down
24 changes: 24 additions & 0 deletions PCL.Core.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCL.Core", "PCL.Core.csproj", "{F46883D6-36B8-D972-8661-D0CA2DB6695B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F46883D6-36B8-D972-8661-D0CA2DB6695B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F46883D6-36B8-D972-8661-D0CA2DB6695B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F46883D6-36B8-D972-8661-D0CA2DB6695B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F46883D6-36B8-D972-8661-D0CA2DB6695B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E1C68EDF-2735-4241-A0AE-513B3C1AC497}
EndGlobalSection
EndGlobal
33 changes: 33 additions & 0 deletions Utils/Mod/CurseForge.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;

namespace PCL.Core.Utils.Mod;

public class CurseForgeMod
{
private static string CurseForgeBaseAPI = "https://api.curseforge.com/v1";

public static async Task<JsonNode?> GetModInfomationByHash(List<string> modHash)
{
HttpResponseMessage result = await Network.GetResponse(
CurseForgeBaseAPI + "/fingerprints/432",
HttpMethod.Post,
new Dictionary<string, string>()
{
["Content-Type"] = "application/json"
},
new JsonObject()
{
["fingerprints"] = JsonSerializer.Serialize(modHash)
}.ToJsonString());



return JsonNode.Parse(await result.Content.ReadAsStringAsync());
}

}
152 changes: 152 additions & 0 deletions Utils/Modpack/CurseForge.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@


using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using PCL.Core.Utils.Mod;

namespace PCL.Core.Utils.Modpack;


public class CurseForge
{
public string? Author;
public string? Name;
public string? Version;
public string? InputFolder;
public string? OutputFile;
public List<CfModloaders?> Modloaders = new();
private List<CfModFile> ModFiles = new();
private JsonNode? Manifest;
private List<string> AddToFile = new();
private dynamic? Entry;
private void OnFinsh()
{
Task.Run(() =>
{
this.Export();
});
}

private void Start()
{
List<Task?> tasks = [
this.PrepareMods(),
this.PrepareOverride()
];
Task.WaitAll(tasks.ToArray());
this.PrepareJson().GetAwaiter().GetResult();
this.OnFinsh();
}

private void Export()
{
if(this.OutputFile is null) throw new ArgumentNullException("参数无效:OutputFile");
using (FileStream fs = new(this.OutputFile, FileMode.Create))
{
using (ZipArchive Zipfile = new(fs))
{
using(var Entry = Zipfile.CreateEntry("manifest.json").Open())
{
using (MemoryStream memoryStream = new(this.Manifest!.ToJsonString().GetBytes()))
{
memoryStream.CopyTo(Entry);
}
}



}
}
}

public async Task<bool> PrepareOverride()
{
foreach (var (file,Entry) in this.ModFiles.Zip(this.Entry, (f,e) => (f,e)))
{
if(file.FileId == Entry.FileId) continue;
}
foreach (var file in Directory.GetFiles(this.InputFolder))
{

}
return true;
}
public async Task<bool> PrepareJson()
{
this.Manifest = new JsonObject()
{
["minecraft"] = new JsonObject()
{
["version"] = this.Version,
["modloaders"] = JsonSerializer.Serialize(this.Modloaders)
},
["manifestType"] = "minecraftModpack",
["overrides"] = "overrides",
["manifestVersion"] = 1,
["version"] = this.Version,
["author"] = this.Author,
["name"] = this.Name,
["files"] = JsonSerializer.Serialize(this.ModFiles)
};
}
public async Task<bool> PrepareMods(dynamic? modHashes = null)
{
if (modHashes is null) goto ModCompareFinished;
this.Entry = modHashes;
modHashes["modloaders"] = JsonSerializer.Serialize(this.Modloaders);
string modsFolder = InputFolder?.TrimEnd('/') + "/mods";
if (Directory.Exists(modsFolder))
{
List<string> modHash = new();
JsonNode? result = await CurseForgeMod.GetModInfomationByHash(modHash);
if (result is null) goto ModCompareFinished;
JsonArray? data = result["data"]?["exactMatches"]?.AsObject().AsArray();
if (data is null) goto ModCompareFinished;
foreach (JsonNode? modInfo in data)
{
try
{
ModFiles.Add(new CfModFile()
{
ProjectId = int.Parse(data["id"]?.ToString()),
FileId = int.Parse(data["file"]?["id"]?.ToString()),
Required = true,
});
}
catch
{
continue;
}
}
}
ModCompareFinished:
return true;
}
}


public class CfPackVersion
{
public string Version;
public List<CfModloaders> Modloaders;
}

public class CfModloaders
{
public string? Id;
public bool Primary;
}

public class CfModFile
{
public int ProjectId;
public int FileId;
public bool Required;
}
75 changes: 75 additions & 0 deletions Utils/Network.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Threading.Tasks;
using PCL.Core.Utils;
namespace PCL.Core.Utils;

public class Network
{
private static readonly HttpClientHandler Handler = new()
{
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip | DecompressionMethods.None
};
private static readonly HttpClient Client = new(Handler);

public static async Task<HttpResponseMessage> GetResponse(
string requestUrl,
HttpMethod method,
Dictionary<string,string>? headers = null,
object? data = null,
int timeout = 25000
)
{
int retry = 3;
retry:
using (HttpRequestMessage request = new(method,requestUrl))
{
if (data is not null)
request.Content = new ByteArrayContent((data is string)? (data as string).GetBytes():data as byte[]);
if (headers is not null) foreach (var header in headers)
{
if (header.Key.StartsWith("Content", StringComparison.OrdinalIgnoreCase) && request.Content is not null)
{
request.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
continue;
}

request.Headers.TryAddWithoutValidation(header.Key, header.Value);
}

using (CancellationTokenSource cts = new(timeout))
{
HttpResponseMessage response =
await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cts.Token);
try
{
response.EnsureSuccessStatusCode();
return response;
}
catch (HttpRequestException ex)
{
if (retry > 0)
{
retry--;
goto retry;
}
// 尝试读取远程服务器返回的数据数据
try
{
if (response.Content.Headers.ContentLength <= 1024 * 1024)
ex.Data["ServerResponse"] = (await response.Content.ReadAsByteArrayAsync()).GetString();
}
catch
{

}
throw;
}
}
}
}
}
14 changes: 14 additions & 0 deletions Utils/Override.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace PCL.Core.Utils;
using System.Text;

public static class Override
{
public static byte[] GetBytes(this string content,Encoding? encode = null)
{
return (encode ?? Encoding.UTF8).GetBytes(content);
}
public static string GetString(this byte[] content,Encoding? encode = null)
{
return (encode ?? Encoding.UTF8).GetString(content);
}
}