mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Merge pull request #1737 from DGP-Studio/feat/hypapi
This commit is contained in:
@@ -10,8 +10,10 @@ using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Service.Game.Configuration;
|
||||
using Snap.Hutao.Service.Game.Package;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
|
||||
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.ChannelSDK;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.DeprecatedFile;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.Package;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.IO;
|
||||
|
||||
@@ -43,7 +45,7 @@ internal sealed class LaunchExecutionEnsureGameResourceHandler : ILaunchExecutio
|
||||
return;
|
||||
}
|
||||
|
||||
// Backup config file, in order to prevent a incompatible launcher to delete it.
|
||||
// Backup config file, recover when a incompatible launcher deleted it.
|
||||
context.ServiceProvider.GetRequiredService<IGameConfigurationFileService>().Backup(gameFileSystem.GameConfigFilePath);
|
||||
|
||||
await context.TaskContext.SwitchToMainThreadAsync();
|
||||
@@ -96,13 +98,30 @@ internal sealed class LaunchExecutionEnsureGameResourceHandler : ILaunchExecutio
|
||||
|
||||
progress.Report(new(SH.ServiceGameEnsureGameResourceQueryResourceInformation));
|
||||
|
||||
ResourceClient resourceClient = context.ServiceProvider.GetRequiredService<ResourceClient>();
|
||||
Response<GameResource> response = await resourceClient.GetResourceAsync(context.Scheme).ConfigureAwait(false);
|
||||
HoyoPlayClient hoyoPlayClient = context.ServiceProvider.GetRequiredService<HoyoPlayClient>();
|
||||
|
||||
if (!response.TryGetDataWithoutUINotification(out GameResource? resource))
|
||||
// We perform these requests before package conversion to ensure resources index is intact.
|
||||
Response<GamePackagesWrapper> packagesResponse = await hoyoPlayClient.GetPackagesAsync(context.Scheme).ConfigureAwait(false);
|
||||
if (!packagesResponse.TryGetDataWithoutUINotification(out GamePackagesWrapper? gamePackages))
|
||||
{
|
||||
context.Result.Kind = LaunchExecutionResultKind.GameResourceIndexQueryInvalidResponse;
|
||||
context.Result.ErrorMessage = SH.FormatServiceGameLaunchExecutionGameResourceQueryIndexFailed(response);
|
||||
context.Result.ErrorMessage = SH.FormatServiceGameLaunchExecutionGameResourceQueryIndexFailed(packagesResponse);
|
||||
return false;
|
||||
}
|
||||
|
||||
Response<GameChannelSDKsWrapper> sdkResponse = await hoyoPlayClient.GetChannelSDKAsync(context.Scheme).ConfigureAwait(false);
|
||||
if (!sdkResponse.TryGetDataWithoutUINotification(out GameChannelSDKsWrapper? channelSDKs))
|
||||
{
|
||||
context.Result.Kind = LaunchExecutionResultKind.GameResourceIndexQueryInvalidResponse;
|
||||
context.Result.ErrorMessage = SH.FormatServiceGameLaunchExecutionGameResourceQueryIndexFailed(sdkResponse);
|
||||
return false;
|
||||
}
|
||||
|
||||
Response<DeprecatedFileConfigurationsWrapper> deprecatedFileResponse = await hoyoPlayClient.GetDeprecatedFileConfigurationsAsync(context.Scheme).ConfigureAwait(false);
|
||||
if (!deprecatedFileResponse.TryGetDataWithoutUINotification(out DeprecatedFileConfigurationsWrapper? deprecatedFileConfigs))
|
||||
{
|
||||
context.Result.Kind = LaunchExecutionResultKind.GameResourceIndexQueryInvalidResponse;
|
||||
context.Result.ErrorMessage = SH.FormatServiceGameLaunchExecutionGameResourceQueryIndexFailed(deprecatedFileResponse);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -110,7 +129,7 @@ internal sealed class LaunchExecutionEnsureGameResourceHandler : ILaunchExecutio
|
||||
|
||||
if (!context.Scheme.ExecutableMatches(gameFileName))
|
||||
{
|
||||
if (!await packageConverter.EnsureGameResourceAsync(context.Scheme, resource, gameFolder, progress).ConfigureAwait(false))
|
||||
if (!await packageConverter.EnsureGameResourceAsync(context.Scheme, gamePackages.GamePackages.Single(), gameFolder, progress).ConfigureAwait(false))
|
||||
{
|
||||
context.Result.Kind = LaunchExecutionResultKind.GameResourcePackageConvertInternalError;
|
||||
context.Result.ErrorMessage = SH.ViewModelLaunchGameEnsureGameResourceFail;
|
||||
@@ -124,7 +143,7 @@ internal sealed class LaunchExecutionEnsureGameResourceHandler : ILaunchExecutio
|
||||
context.Options.UpdateGamePathAndRefreshEntries(Path.Combine(gameFolder, executableName));
|
||||
}
|
||||
|
||||
await packageConverter.EnsureDeprecatedFilesAndSdkAsync(resource, gameFolder).ConfigureAwait(false);
|
||||
await packageConverter.EnsureDeprecatedFilesAndSdkAsync(channelSDKs.GameChannelSDKs.SingleOrDefault(), deprecatedFileConfigs.DeprecatedFileConfigurations.SingleOrDefault(), gameFolder).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ internal sealed class LaunchExecutionSetChannelOptionsHandler : ILaunchExecution
|
||||
string configPath = gameFileSystem.GameConfigFilePath;
|
||||
context.Logger.LogInformation("Game config file path: {ConfigPath}", configPath);
|
||||
|
||||
List<IniElement> elements = default!;
|
||||
List<IniElement> elements;
|
||||
try
|
||||
{
|
||||
elements = [.. IniSerializer.DeserializeFromFile(configPath)];
|
||||
|
||||
@@ -8,7 +8,9 @@ using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Core.IO.Hashing;
|
||||
using Snap.Hutao.Core.IO.Http.Sharding;
|
||||
using Snap.Hutao.Service.Game.Scheme;
|
||||
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.ChannelSDK;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.DeprecatedFile;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.Package;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
@@ -34,9 +36,9 @@ internal sealed partial class PackageConverter
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly ILogger<PackageConverter> logger;
|
||||
|
||||
public async ValueTask<bool> EnsureGameResourceAsync(LaunchScheme targetScheme, GameResource gameResource, string gameFolder, IProgress<PackageConvertStatus> progress)
|
||||
public async ValueTask<bool> EnsureGameResourceAsync(LaunchScheme targetScheme, GamePackage gamePackage, string gameFolder, IProgress<PackageConvertStatus> progress)
|
||||
{
|
||||
// 以 国服 => 国际 为例
|
||||
// 以 国服 -> 国际服 为例
|
||||
// 1. 下载国际服的 pkg_version 文件,转换为索引字典
|
||||
// 获取本地对应 pkg_version 文件,转换为索引字典
|
||||
//
|
||||
@@ -56,7 +58,7 @@ internal sealed partial class PackageConverter
|
||||
// 替换操作等于 先备份国服文件,随后新增国际服文件
|
||||
|
||||
// 准备下载链接
|
||||
string scatteredFilesUrl = gameResource.Game.Latest.DecompressedPath;
|
||||
string scatteredFilesUrl = gamePackage.Main.Major.ResourceListUrl;
|
||||
string pkgVersionUrl = $"{scatteredFilesUrl}/{PackageVersion}";
|
||||
|
||||
PackageConverterFileSystemContext context = new(targetScheme.IsOversea, runtimeOptions.GetDataFolderServerCacheFolder(), gameFolder, scatteredFilesUrl);
|
||||
@@ -77,7 +79,7 @@ internal sealed partial class PackageConverter
|
||||
return await ReplaceGameResourceAsync(diffOperations, context, progress).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async ValueTask EnsureDeprecatedFilesAndSdkAsync(GameResource resource, string gameFolder)
|
||||
public async ValueTask EnsureDeprecatedFilesAndSdkAsync(GameChannelSDK? channelSDK, DeprecatedFilesWrapper? deprecatedFiles, string gameFolder)
|
||||
{
|
||||
string sdkDllBackup = Path.Combine(gameFolder, YuanShenData, "Plugins\\PCGameSDK.dll.backup");
|
||||
string sdkDll = Path.Combine(gameFolder, YuanShenData, "Plugins\\PCGameSDK.dll");
|
||||
@@ -86,9 +88,9 @@ internal sealed partial class PackageConverter
|
||||
string sdkVersion = Path.Combine(gameFolder, "sdk_pkg_version");
|
||||
|
||||
// Only bilibili's sdk is not null
|
||||
if (resource.Sdk is not null)
|
||||
if (channelSDK is not null)
|
||||
{
|
||||
using (Stream sdkWebStream = await httpClient.GetStreamAsync(resource.Sdk.Path).ConfigureAwait(false))
|
||||
using (Stream sdkWebStream = await httpClient.GetStreamAsync(channelSDK.ChannelSdkPackage.Url).ConfigureAwait(false))
|
||||
{
|
||||
ZipFile.ExtractToDirectory(sdkWebStream, gameFolder, true);
|
||||
}
|
||||
@@ -106,9 +108,9 @@ internal sealed partial class PackageConverter
|
||||
FileOperation.Move(sdkVersion, sdkVersionBackup, true);
|
||||
}
|
||||
|
||||
if (resource.DeprecatedFiles is not null)
|
||||
if (deprecatedFiles is not null)
|
||||
{
|
||||
foreach (NameMd5 file in resource.DeprecatedFiles)
|
||||
foreach (DeprecatedFile file in deprecatedFiles.DeprecatedFiles)
|
||||
{
|
||||
string filePath = Path.Combine(gameFolder, file.Name);
|
||||
FileOperation.Move(filePath, $"{filePath}.backup", true);
|
||||
|
||||
@@ -30,25 +30,13 @@ internal class LaunchScheme : IEquatable<ChannelOptions>
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通道
|
||||
/// </summary>
|
||||
public ChannelType Channel { get; private protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子通道
|
||||
/// </summary>
|
||||
public SubChannelType SubChannel { get; private protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启动器 Id
|
||||
/// </summary>
|
||||
public int LauncherId { get; private protected set; }
|
||||
public string LauncherId { get; private protected set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// API Key
|
||||
/// </summary>
|
||||
public string Key { get; private protected set; } = default!;
|
||||
public string GameId { get; private protected set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为海外
|
||||
|
||||
@@ -7,13 +7,13 @@ namespace Snap.Hutao.Service.Game.Scheme;
|
||||
|
||||
internal sealed class LaunchSchemeBilibili : LaunchScheme
|
||||
{
|
||||
private const int SdkStaticLauncherBilibiliId = 17;
|
||||
private const string SdkStaticLauncherBilibiliKey = "KAtdSsoQ";
|
||||
private const string HoyoPlayLauncherBilibiliId = "umfgRO5gh5";
|
||||
private const string HoyoPlayGameBilibiliId = "T2S0Gz4Dr2";
|
||||
|
||||
public LaunchSchemeBilibili(SubChannelType subChannel, bool isNotCompatOnly = true)
|
||||
{
|
||||
LauncherId = SdkStaticLauncherBilibiliId;
|
||||
Key = SdkStaticLauncherBilibiliKey;
|
||||
LauncherId = HoyoPlayLauncherBilibiliId;
|
||||
GameId = HoyoPlayGameBilibiliId;
|
||||
Channel = ChannelType.Bili;
|
||||
SubChannel = subChannel;
|
||||
IsOversea = false;
|
||||
|
||||
@@ -7,13 +7,13 @@ namespace Snap.Hutao.Service.Game.Scheme;
|
||||
|
||||
internal sealed class LaunchSchemeChinese : LaunchScheme
|
||||
{
|
||||
private const int SdkStaticLauncherChineseId = 18;
|
||||
private const string SdkStaticLauncherChineseKey = "eYd89JmJ";
|
||||
private const string HoyoPlayLauncherChineseId = "jGHBHlcOq1";
|
||||
private const string HoyoPlayGameChineseId = "1Z8W5NHUQb";
|
||||
|
||||
public LaunchSchemeChinese(ChannelType channel, SubChannelType subChannel, bool isNotCompatOnly = true)
|
||||
{
|
||||
LauncherId = SdkStaticLauncherChineseId;
|
||||
Key = SdkStaticLauncherChineseKey;
|
||||
LauncherId = HoyoPlayLauncherChineseId;
|
||||
GameId = HoyoPlayGameChineseId;
|
||||
Channel = channel;
|
||||
SubChannel = subChannel;
|
||||
IsOversea = false;
|
||||
|
||||
@@ -7,13 +7,13 @@ namespace Snap.Hutao.Service.Game.Scheme;
|
||||
|
||||
internal sealed class LaunchSchemeOversea : LaunchScheme
|
||||
{
|
||||
private const int SdkStaticLauncherOverseaId = 10;
|
||||
private const string SdkStaticLauncherOverseaKey = "gcStgarh";
|
||||
private const string HoyoPlayLauncherOverseaId = "VYTpXlbWo8";
|
||||
private const string HoyoPlayGameOverseaId = "gopR6Cufr3";
|
||||
|
||||
public LaunchSchemeOversea(ChannelType channel, SubChannelType subChannel, bool isNotCompatOnly = true)
|
||||
{
|
||||
LauncherId = SdkStaticLauncherOverseaId;
|
||||
Key = SdkStaticLauncherOverseaKey;
|
||||
LauncherId = HoyoPlayLauncherOverseaId;
|
||||
GameId = HoyoPlayGameOverseaId;
|
||||
Channel = channel;
|
||||
SubChannel = subChannel;
|
||||
IsOversea = true;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
d:DataContext="{d:DesignInstance shva:AchievementViewModelSlim}"
|
||||
Background="Transparent"
|
||||
BorderBrush="{x:Null}"
|
||||
BorderThickness="0"
|
||||
Command="{Binding NavigateCommand}"
|
||||
Style="{ThemeResource DefaultButtonStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
d:DataContext="{d:DesignInstance shvd:DailyNoteViewModelSlim}"
|
||||
Background="Transparent"
|
||||
BorderBrush="{x:Null}"
|
||||
BorderThickness="0"
|
||||
Command="{Binding NavigateCommand}"
|
||||
Style="{ThemeResource DefaultButtonStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
d:DataContext="{d:DesignInstance shvg:GachaLogViewModelSlim}"
|
||||
Background="Transparent"
|
||||
BorderBrush="{x:Null}"
|
||||
BorderThickness="0"
|
||||
Command="{Binding NavigateCommand}"
|
||||
Style="{ThemeResource DefaultButtonStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
d:DataContext="{d:DesignInstance shvg:LaunchGameViewModelSlim}"
|
||||
Background="Transparent"
|
||||
BorderBrush="{x:Null}"
|
||||
BorderThickness="0"
|
||||
Command="{Binding LaunchCommand}"
|
||||
Style="{ThemeResource DefaultButtonStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
xmlns:shwhshlr="using:Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource"
|
||||
xmlns:shwhhpc="using:Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect"
|
||||
xmlns:shwhhpcp="using:Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.Package"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
d:DataContext="{d:DesignInstance shwhshlr:Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource.Package}"
|
||||
d:DataContext="{d:DesignInstance shwhhpcp:Package}"
|
||||
BorderThickness="0"
|
||||
IsExpanded="True"
|
||||
ItemsSource="{Binding VoicePacks}"
|
||||
ItemsSource="{Binding AllPackages}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<cwc:SettingsExpander.Resources>
|
||||
@@ -24,7 +26,7 @@
|
||||
</cwc:SettingsExpander.Resources>
|
||||
|
||||
<cwc:SettingsExpander.ItemTemplate>
|
||||
<DataTemplate x:DataType="shwhshlr:VoicePackage">
|
||||
<DataTemplate x:DataType="shwhhpc:PackageSegment">
|
||||
<cwc:SettingsCard
|
||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||
ActionIcon="{shcm:FontIcon Glyph={StaticResource FontIconContentCopy}}"
|
||||
@@ -35,70 +37,26 @@
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Margin="0,4,0,0"
|
||||
Orientation="Horizontal">
|
||||
Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="{StaticResource FontIconContentZipFolder}"/>
|
||||
<TextBlock
|
||||
Width="80"
|
||||
Margin="8,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding PackageSize, Converter={StaticResource FileSizeToFriendlyStringConverter}}"/>
|
||||
Text="{Binding Size, Converter={StaticResource FileSizeToFriendlyStringConverter}}"/>
|
||||
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="{StaticResource FontIconContentFolder}"/>
|
||||
<TextBlock
|
||||
Width="80"
|
||||
Margin="8,0,0,0"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding Size, Converter={StaticResource FileSizeToFriendlyStringConverter}}"/>
|
||||
Text="{Binding DecompressedSize, Converter={StaticResource FileSizeToFriendlyStringConverter}}"/>
|
||||
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="{StaticResource FontIconContentAsteriskBadge12}"/>
|
||||
<TextBlock
|
||||
Margin="8,0,0,0"
|
||||
IsTextSelectionEnabled="True"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding Md5}"/>
|
||||
Text="{Binding MD5}"/>
|
||||
</StackPanel>
|
||||
</cwc:SettingsCard.Description>
|
||||
</cwc:SettingsCard>
|
||||
</DataTemplate>
|
||||
</cwc:SettingsExpander.ItemTemplate>
|
||||
|
||||
<cwc:SettingsExpander.ItemsHeader>
|
||||
<cwc:SettingsCard
|
||||
MinHeight="52"
|
||||
Padding="{ThemeResource SettingsExpanderItemHasIconPadding}"
|
||||
ActionIcon="{shcm:FontIcon Glyph={StaticResource FontIconContentCopy}}"
|
||||
Background="{ThemeResource InfoBarInformationalSeverityBackgroundBrush}"
|
||||
BorderThickness="0"
|
||||
Command="{Binding CopyPathCommand}"
|
||||
CornerRadius="0"
|
||||
Header="{Binding DisplayName}"
|
||||
IsClickEnabled="True">
|
||||
<cwc:SettingsCard.Description>
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Margin="0,4,0,0"
|
||||
Orientation="Horizontal">
|
||||
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="{StaticResource FontIconContentZipFolder}"/>
|
||||
<TextBlock
|
||||
Width="80"
|
||||
Margin="8,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding PackageSize, Converter={StaticResource FileSizeToFriendlyStringConverter}}"/>
|
||||
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="{StaticResource FontIconContentFolder}"/>
|
||||
<TextBlock
|
||||
Width="80"
|
||||
Margin="8,0,0,0"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding Size, Converter={StaticResource FileSizeToFriendlyStringConverter}}"/>
|
||||
<FontIcon FontSize="{StaticResource CaptionTextBlockFontSize}" Glyph="{StaticResource FontIconContentAsteriskBadge12}"/>
|
||||
<TextBlock
|
||||
Margin="8,0,0,0"
|
||||
IsTextSelectionEnabled="True"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding Md5}"/>
|
||||
</StackPanel>
|
||||
</cwc:SettingsCard.Description>
|
||||
</cwc:SettingsCard>
|
||||
</cwc:SettingsExpander.ItemsHeader>
|
||||
|
||||
</cwc:SettingsExpander>
|
||||
|
||||
@@ -366,13 +366,13 @@
|
||||
</PivotItem>
|
||||
<PivotItem Header="{shcm:ResourceString Name=ViewPageLaunchGameResourceHeader}">
|
||||
<Grid>
|
||||
<ScrollViewer Visibility="{Binding GameResource, Converter={StaticResource EmptyObjectToBoolConverter}}">
|
||||
<ScrollViewer Visibility="{Binding GamePackage, Converter={StaticResource EmptyObjectToBoolConverter}}">
|
||||
<StackPanel>
|
||||
<Border Margin="16,16,16,0" cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
||||
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
||||
<shvc:LaunchGameResourceExpander
|
||||
cw:Effects.Shadow="{ThemeResource CompatCardShadow}"
|
||||
DataContext="{Binding GameResource.PreDownloadGame.Latest, Mode=OneWay}"
|
||||
DataContext="{Binding GamePackage.PreDownload.Major, Mode=OneWay}"
|
||||
Header="{shcm:ResourceString Name=ViewPageLaunchGameResourcePreDownloadHeader}"
|
||||
IsEnabled="{Binding FallbackValue=False, Converter={StaticResource EmptyObjectToBoolConverter}}"
|
||||
IsExpanded="{Binding FallbackValue=False, Converter={StaticResource EmptyObjectToBoolConverter}, Mode=OneTime}"/>
|
||||
@@ -382,22 +382,22 @@
|
||||
<ItemsControl
|
||||
Margin="0,0,0,0"
|
||||
ItemTemplate="{StaticResource GameResourceTemplate}"
|
||||
ItemsSource="{Binding GameResource.PreDownloadGame.Diffs, Mode=OneWay}"/>
|
||||
ItemsSource="{Binding GamePackage.PreDownload.Patches, Mode=OneWay}"/>
|
||||
<Border Margin="16,16,16,0" cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
||||
<Border Style="{ThemeResource AcrylicBorderCardStyle}">
|
||||
<shvc:LaunchGameResourceExpander
|
||||
cw:Effects.Shadow="{ThemeResource CompatCardShadow}"
|
||||
DataContext="{Binding GameResource.Game.Latest, Mode=OneWay}"
|
||||
DataContext="{Binding GamePackage.Main.Major, Mode=OneWay}"
|
||||
Header="{shcm:ResourceString Name=ViewPageLaunchGameResourceLatestHeader}"/>
|
||||
</Border>
|
||||
</Border>
|
||||
<ItemsControl
|
||||
Margin="0,0,0,16"
|
||||
ItemTemplate="{StaticResource GameResourceTemplate}"
|
||||
ItemsSource="{Binding GameResource.Game.Diffs, Mode=OneWay}"/>
|
||||
ItemsSource="{Binding GamePackage.Main.Patches, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<shvc:LoadingView IsLoading="{Binding GameResource, Converter={StaticResource EmptyObjectToBoolRevertConverter}}"/>
|
||||
<shvc:LoadingView IsLoading="{Binding GamePackage, Converter={StaticResource EmptyObjectToBoolRevertConverter}}"/>
|
||||
</Grid>
|
||||
</PivotItem>
|
||||
</Pivot>
|
||||
|
||||
@@ -11,26 +11,26 @@ internal static class LaunchGameLaunchExecution
|
||||
{
|
||||
public static async ValueTask LaunchExecutionAsync(this IViewModelSupportLaunchExecution launchExecution, LaunchScheme? targetScheme)
|
||||
{
|
||||
IServiceProvider root = Ioc.Default;
|
||||
IInfoBarService infoBarService = root.GetRequiredService<IInfoBarService>();
|
||||
ILogger<IViewModelSupportLaunchExecution> logger = root.GetRequiredService<ILogger<IViewModelSupportLaunchExecution>>();
|
||||
|
||||
// LaunchScheme? scheme = launchExecution.Shared.GetCurrentLaunchSchemeFromConfigFile();
|
||||
try
|
||||
using (IServiceScope scope = Ioc.Default.CreateScope())
|
||||
{
|
||||
// Root service provider is required.
|
||||
LaunchExecutionContext context = new(root, launchExecution, targetScheme, launchExecution.SelectedGameAccount);
|
||||
LaunchExecutionResult result = await new LaunchExecutionInvoker().InvokeAsync(context).ConfigureAwait(false);
|
||||
IInfoBarService infoBarService = scope.ServiceProvider.GetRequiredService<IInfoBarService>();
|
||||
ILogger<IViewModelSupportLaunchExecution> logger = scope.ServiceProvider.GetRequiredService<ILogger<IViewModelSupportLaunchExecution>>();
|
||||
|
||||
if (result.Kind is not LaunchExecutionResultKind.Ok)
|
||||
try
|
||||
{
|
||||
infoBarService.Warning(result.ErrorMessage);
|
||||
LaunchExecutionContext context = new(scope.ServiceProvider, launchExecution, targetScheme, launchExecution.SelectedGameAccount);
|
||||
LaunchExecutionResult result = await new LaunchExecutionInvoker().InvokeAsync(context).ConfigureAwait(false);
|
||||
|
||||
if (result.Kind is not LaunchExecutionResultKind.Ok)
|
||||
{
|
||||
infoBarService.Warning(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogCritical(ex, "Launch failed");
|
||||
infoBarService.Error(ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogCritical(ex, "Launch failed");
|
||||
infoBarService.Error(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@ using Snap.Hutao.Service.Game.PathAbstraction;
|
||||
using Snap.Hutao.Service.Game.Scheme;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
using Snap.Hutao.Service.User;
|
||||
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
|
||||
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.Package;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
|
||||
@@ -39,19 +39,19 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
|
||||
private readonly IGameLocatorFactory gameLocatorFactory;
|
||||
private readonly LaunchGameShared launchGameShared;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly ResourceClient resourceClient;
|
||||
private readonly IGameServiceFacade gameService;
|
||||
private readonly RuntimeOptions runtimeOptions;
|
||||
private readonly HoyoPlayClient hoyoPlayClient;
|
||||
private readonly LaunchOptions launchOptions;
|
||||
private readonly IUserService userService;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IGameServiceFacade gameService;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
private readonly AppOptions appOptions;
|
||||
|
||||
private LaunchScheme? selectedScheme;
|
||||
private AdvancedCollectionView<GameAccount>? gameAccountsView;
|
||||
private GameAccount? selectedGameAccount;
|
||||
private GameResource? gameResource;
|
||||
private GamePackage? gamePackage;
|
||||
private bool gamePathSelectedAndValid;
|
||||
private ImmutableList<GamePathEntry> gamePathEntries;
|
||||
private GamePathEntry? selectedGamePathEntry;
|
||||
@@ -69,7 +69,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
|
||||
|
||||
public List<LaunchScheme> KnownSchemes { get; } = KnownLaunchSchemes.Get();
|
||||
|
||||
[AlsoAsyncSets(nameof(GameResource), nameof(GameAccountsView))]
|
||||
[AlsoAsyncSets(nameof(GamePackage), nameof(GameAccountsView))]
|
||||
public LaunchScheme? SelectedScheme
|
||||
{
|
||||
get => selectedScheme;
|
||||
@@ -80,7 +80,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
|
||||
|
||||
public GameAccount? SelectedGameAccount { get => selectedGameAccount; set => SetProperty(ref selectedGameAccount, value); }
|
||||
|
||||
public GameResource? GameResource { get => gameResource; set => SetProperty(ref gameResource, value); }
|
||||
public GamePackage? GamePackage { get => gamePackage; set => SetProperty(ref gamePackage, value); }
|
||||
|
||||
public bool GamePathSelectedAndValid
|
||||
{
|
||||
@@ -301,10 +301,10 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
|
||||
SelectedGameAccount = default;
|
||||
|
||||
await UpdateGameAccountsViewAsync().ConfigureAwait(false);
|
||||
UpdateGameResourceAsync(value).SafeForget();
|
||||
UpdateGamePackageAsync(value).SafeForget();
|
||||
}
|
||||
|
||||
async ValueTask UpdateGameResourceAsync(LaunchScheme? scheme)
|
||||
async ValueTask UpdateGamePackageAsync(LaunchScheme? scheme)
|
||||
{
|
||||
if (scheme is null)
|
||||
{
|
||||
@@ -312,14 +312,14 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
|
||||
}
|
||||
|
||||
await taskContext.SwitchToBackgroundAsync();
|
||||
Web.Response.Response<GameResource> response = await resourceClient
|
||||
.GetResourceAsync(scheme)
|
||||
Web.Response.Response<GamePackagesWrapper> response = await hoyoPlayClient
|
||||
.GetPackagesAsync(scheme)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (response.IsOk())
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
GameResource = response.Data;
|
||||
GamePackage = response.Data.GamePackages.Single();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -284,6 +284,25 @@ internal static class ApiEndpoints
|
||||
|
||||
#endregion
|
||||
|
||||
#region HoyoPlayApi
|
||||
|
||||
public static string HoyoPlayConnectGamePackages(LaunchScheme scheme)
|
||||
{
|
||||
return $"{HoyoPlayApiConnectApi}/getGamePackages?game_ids[]={scheme.GameId}&launcher_id={scheme.LauncherId}";
|
||||
}
|
||||
|
||||
public static string HoyoPlayConnectGameChannelSDKs(LaunchScheme scheme)
|
||||
{
|
||||
return $"{HoyoPlayApiConnectApi}/getGameChannelSDKs?channel={scheme.Channel:D}&game_ids[]={scheme.GameId}&launcher_id={scheme.LauncherId}&sub_channel={scheme.SubChannel:D}";
|
||||
}
|
||||
|
||||
public static string HoyoPlayConnectDeprecatedFileConfigs(LaunchScheme scheme)
|
||||
{
|
||||
return $"{HoyoPlayApiConnectApi}/getGameDeprecatedFileConfigs?channel={scheme.Channel:D}&game_ids[]={scheme.GameId}&launcher_id={scheme.LauncherId}&sub_channel={scheme.SubChannel:D}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PassportApi | PassportApiV4
|
||||
|
||||
/// <summary>
|
||||
@@ -348,26 +367,6 @@ internal static class ApiEndpoints
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SdkStaticLauncherApi
|
||||
|
||||
/// <summary>
|
||||
/// 启动器资源
|
||||
/// </summary>
|
||||
/// <param name="scheme">启动方案</param>
|
||||
/// <returns>启动器资源字符串</returns>
|
||||
public static string SdkStaticLauncherResource(LaunchScheme scheme)
|
||||
{
|
||||
return $"{SdkStaticLauncherApi}/resource?key={scheme.Key}&launcher_id={scheme.LauncherId}&channel_id={scheme.Channel:D}&sub_channel_id={scheme.SubChannel:D}";
|
||||
}
|
||||
|
||||
public static string SdkStaticLauncherContent(LaunchScheme scheme, string languageCode, bool advOnly = true)
|
||||
{
|
||||
return advOnly
|
||||
? $"{SdkStaticLauncherApi}/content?filter_adv=true&key={scheme.Key}&launcher_id={scheme.LauncherId}&language={languageCode}"
|
||||
: $"{SdkStaticLauncherApi}/content?key={scheme.Key}&launcher_id={scheme.LauncherId}&language={languageCode}";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Hosts | Queries
|
||||
private const string ApiTakumi = "https://api-takumi.mihoyo.com";
|
||||
private const string ApiTakumiAuthApi = $"{ApiTakumi}/auth/api";
|
||||
@@ -395,6 +394,9 @@ internal static class ApiEndpoints
|
||||
|
||||
private const string Hk4eSdk = "https://hk4e-sdk.mihoyo.com";
|
||||
|
||||
private const string HoyoPlayApi = "https://hyp-api.mihoyo.com";
|
||||
private const string HoyoPlayApiConnectApi = $"{HoyoPlayApi}/hyp/hyp-connect/api";
|
||||
|
||||
private const string PassportApi = "https://passport-api.mihoyo.com";
|
||||
private const string PassportApiAuthApi = $"{PassportApi}/account/auth/api";
|
||||
private const string PassportApiV4 = "https://passport-api-v4.mihoyo.com";
|
||||
|
||||
@@ -298,19 +298,23 @@ internal static class ApiOsEndpoints
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SdkOsStaticLauncherApi
|
||||
#region SgHoyoPlayApi
|
||||
|
||||
public static string SdkOsStaticLauncherResource(LaunchScheme scheme)
|
||||
public static string SgHoyoPlayConnectGamePackages(LaunchScheme scheme)
|
||||
{
|
||||
return $"{SdkOsStaticLauncherApi}/resource?key={scheme.Key}&launcher_id={scheme.LauncherId}&channel_id={scheme.Channel:D}&sub_channel_id={scheme.SubChannel:D}";
|
||||
return $"{SgHoyoPlayApiConnectApi}/getGamePackages?game_ids[]={scheme.GameId}&launcher_id={scheme.LauncherId}";
|
||||
}
|
||||
|
||||
public static string SdkOsStaticLauncherContent(LaunchScheme scheme, string languageCode, bool advOnly = true)
|
||||
public static string SgHoyoPlayConnectGameChannelSDKs(LaunchScheme scheme)
|
||||
{
|
||||
return advOnly
|
||||
? $"{SdkOsStaticLauncherApi}/content?filter_adv=true&key={scheme.Key}&launcher_id={scheme.LauncherId}&language={languageCode}"
|
||||
: $"{SdkOsStaticLauncherApi}/content?key={scheme.Key}&launcher_id={scheme.LauncherId}&language={languageCode}";
|
||||
return $"{SgHoyoPlayApiConnectApi}/getGameChannelSDKs?channel={scheme.Channel:D}&game_ids[]={scheme.GameId}&launcher_id={scheme.LauncherId}&sub_channel={scheme.SubChannel:D}";
|
||||
}
|
||||
|
||||
public static string SgHoyoPlayConnectDeprecatedFileConfigs(LaunchScheme scheme)
|
||||
{
|
||||
return $"{SgHoyoPlayApiConnectApi}/getGameDeprecatedFileConfigs?channel={scheme.Channel:D}&game_ids[]={scheme.GameId}&launcher_id={scheme.LauncherId}&sub_channel={scheme.SubChannel:D}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region WebApiOsAccountApi
|
||||
@@ -344,6 +348,9 @@ internal static class ApiOsEndpoints
|
||||
private const string SgPublicApi = "https://sg-public-api.hoyoverse.com";
|
||||
private const string SgHk4eApi = "https://sg-hk4e-api.hoyoverse.com";
|
||||
|
||||
private const string SgHoyoPlayApi = "https://sg-hyp-api.hoyoverse.com";
|
||||
private const string SgHoyoPlayApiConnectApi = $"{SgHoyoPlayApi}/hyp/hyp-connect/api";
|
||||
|
||||
private const string WebApiOs = "https://webapi-os.account.hoyoverse.com";
|
||||
private const string WebApiOsAccountApi = $"{WebApiOs}/Api";
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.ChannelSDK;
|
||||
|
||||
internal sealed class GameChannelSDK : GameIndexedObject
|
||||
{
|
||||
[JsonPropertyName("channel_sdk_pkg")]
|
||||
public PackageSegment ChannelSdkPackage { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("pkg_version_file_name")]
|
||||
public string PackageVersionFileName { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("version")]
|
||||
public string Version { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.ChannelSDK;
|
||||
|
||||
internal sealed class GameChannelSDKsWrapper
|
||||
{
|
||||
[JsonPropertyName("game_channel_sdks")]
|
||||
public List<GameChannelSDK> GameChannelSDKs { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.DeprecatedFile;
|
||||
|
||||
internal sealed class DeprecatedFile
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.DeprecatedFile;
|
||||
|
||||
internal sealed class DeprecatedFileConfigurationsWrapper
|
||||
{
|
||||
[JsonPropertyName("deprecated_file_configs")]
|
||||
public List<DeprecatedFilesWrapper> DeprecatedFileConfigurations { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.DeprecatedFile;
|
||||
|
||||
internal sealed class DeprecatedFilesWrapper : GameIndexedObject
|
||||
{
|
||||
[JsonPropertyName("deprecated_files")]
|
||||
public List<DeprecatedFile> DeprecatedFiles { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect;
|
||||
|
||||
internal sealed class Game
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("biz")]
|
||||
public string Biz { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect;
|
||||
|
||||
internal abstract class GameIndexedObject
|
||||
{
|
||||
[JsonPropertyName("game")]
|
||||
public Game Game { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Service.Game.Scheme;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.ChannelSDK;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.DeprecatedFile;
|
||||
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.Package;
|
||||
using Snap.Hutao.Web.Request.Builder;
|
||||
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect;
|
||||
|
||||
[ConstructorGenerated(ResolveHttpClient = true)]
|
||||
[HttpClient(HttpClientConfiguration.Default)]
|
||||
internal sealed partial class HoyoPlayClient
|
||||
{
|
||||
private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory;
|
||||
private readonly ILogger<HoyoPlayClient> logger;
|
||||
private readonly HttpClient httpClient;
|
||||
|
||||
public async ValueTask<Response<GamePackagesWrapper>> GetPackagesAsync(LaunchScheme scheme, CancellationToken token = default)
|
||||
{
|
||||
string url = scheme.IsOversea
|
||||
? ApiOsEndpoints.SgHoyoPlayConnectGamePackages(scheme)
|
||||
: ApiEndpoints.HoyoPlayConnectGamePackages(scheme);
|
||||
|
||||
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
||||
.SetRequestUri(url)
|
||||
.Get();
|
||||
|
||||
Response<GamePackagesWrapper>? resp = await builder
|
||||
.SendAsync<Response<GamePackagesWrapper>>(httpClient, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return Response.Response.DefaultIfNull(resp);
|
||||
}
|
||||
|
||||
public async ValueTask<Response<GameChannelSDKsWrapper>> GetChannelSDKAsync(LaunchScheme scheme, CancellationToken token = default)
|
||||
{
|
||||
string url = scheme.IsOversea
|
||||
? ApiOsEndpoints.SgHoyoPlayConnectGameChannelSDKs(scheme)
|
||||
: ApiEndpoints.HoyoPlayConnectGameChannelSDKs(scheme);
|
||||
|
||||
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
||||
.SetRequestUri(url)
|
||||
.Get();
|
||||
|
||||
Response<GameChannelSDKsWrapper>? resp = await builder
|
||||
.SendAsync<Response<GameChannelSDKsWrapper>>(httpClient, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return Response.Response.DefaultIfNull(resp);
|
||||
}
|
||||
|
||||
public async ValueTask<Response<DeprecatedFileConfigurationsWrapper>> GetDeprecatedFileConfigurationsAsync(LaunchScheme scheme, CancellationToken token = default)
|
||||
{
|
||||
string url = scheme.IsOversea
|
||||
? ApiOsEndpoints.SgHoyoPlayConnectDeprecatedFileConfigs(scheme)
|
||||
: ApiEndpoints.HoyoPlayConnectDeprecatedFileConfigs(scheme);
|
||||
|
||||
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
||||
.SetRequestUri(url)
|
||||
.Get();
|
||||
|
||||
Response<DeprecatedFileConfigurationsWrapper>? resp = await builder
|
||||
.SendAsync<Response<DeprecatedFileConfigurationsWrapper>>(httpClient, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return Response.Response.DefaultIfNull(resp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.Package;
|
||||
|
||||
internal sealed class AudioPackageSegment : PackageSegment
|
||||
{
|
||||
[JsonPropertyName("language")]
|
||||
public string Language { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.Package;
|
||||
|
||||
internal sealed class GameBranch
|
||||
{
|
||||
[JsonPropertyName("major")]
|
||||
public Package Major { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("patches")]
|
||||
public List<Package> Patches { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.Package;
|
||||
|
||||
internal sealed class GamePackage : GameIndexedObject
|
||||
{
|
||||
[JsonPropertyName("main")]
|
||||
public GameBranch Main { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("pre_download")]
|
||||
public GameBranch PreDownload { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.Package;
|
||||
|
||||
internal sealed class GamePackagesWrapper
|
||||
{
|
||||
[JsonPropertyName("game_packages")]
|
||||
public List<GamePackage> GamePackages { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.Package;
|
||||
|
||||
internal sealed class Package
|
||||
{
|
||||
[JsonPropertyName("version")]
|
||||
public string Version { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("game_pkgs")]
|
||||
public List<PackageSegment> GamePackages { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("audio_pkgs")]
|
||||
public List<AudioPackageSegment> AudioPackages { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("res_list_url")]
|
||||
public string ResourceListUrl { get; set; } = default!;
|
||||
|
||||
[JsonIgnore]
|
||||
public List<PackageSegment> AllPackages
|
||||
{
|
||||
get => [.. GamePackages, .. AudioPackages];
|
||||
}
|
||||
}
|
||||
@@ -4,36 +4,30 @@
|
||||
using Snap.Hutao.Core.IO.DataTransfer;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
namespace Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect;
|
||||
|
||||
/// <summary>
|
||||
/// 下载的文件
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal partial class PathMd5
|
||||
internal partial class PackageSegment
|
||||
{
|
||||
/// <summary>
|
||||
/// 下载地址
|
||||
/// </summary>
|
||||
[JsonPropertyName("path")]
|
||||
public string Path { get; set; } = default!;
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// MD5校验
|
||||
/// </summary>
|
||||
[JsonPropertyName("md5")]
|
||||
public string Md5 { get; set; } = default!;
|
||||
public string MD5 { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
public string DisplayName { get => System.IO.Path.GetFileName(Path); }
|
||||
[JsonPropertyName("size")]
|
||||
public long Size { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("decompressed_size")]
|
||||
public long DecompressedSize { get; set; } = default!;
|
||||
|
||||
[JsonIgnore]
|
||||
public string DisplayName { get => System.IO.Path.GetFileName(Url); }
|
||||
|
||||
[Command("CopyPathCommand")]
|
||||
private void CopyPathToClipboard()
|
||||
{
|
||||
IServiceProvider serviceProvider = Ioc.Default;
|
||||
serviceProvider.GetRequiredService<IClipboardProvider>().SetText(Path);
|
||||
serviceProvider.GetRequiredService<IClipboardProvider>().SetText(Url);
|
||||
serviceProvider.GetRequiredService<IInfoBarService>().Success(SH.WebGameResourcePathCopySucceed);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Content;
|
||||
|
||||
internal sealed class Advertisement
|
||||
{
|
||||
[JsonPropertyName("background")]
|
||||
public string Background { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("icon")]
|
||||
public string Icon { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("version")]
|
||||
public string Version { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("bg_checksum")]
|
||||
public string BackgroundChecksum { get; set; } = default!;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Content;
|
||||
|
||||
internal sealed class Banner
|
||||
{
|
||||
[JsonPropertyName("banner_id")]
|
||||
public string BannerId { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("img")]
|
||||
public string Image { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("order")]
|
||||
public string Order { get; set; } = default!;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Content;
|
||||
|
||||
internal sealed class GameContent
|
||||
{
|
||||
[JsonPropertyName("adv")]
|
||||
public Advertisement? Advertisement { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("banner")]
|
||||
public List<Banner> Banners { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("icon")]
|
||||
public List<Icon> Icons { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("post")]
|
||||
public List<Post> Posts { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("qq")]
|
||||
public List<QQ> QQs { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("more")]
|
||||
public More More { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("links")]
|
||||
public Link Links { get; set; } = default!;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Content;
|
||||
|
||||
internal sealed class Icon
|
||||
{
|
||||
[JsonPropertyName("icon_id")]
|
||||
public string IconId { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("img")]
|
||||
public string Image { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("qr_img")]
|
||||
public string QrImage { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("qr_desc")]
|
||||
public string QrDescription { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("img_hover")]
|
||||
public string ImageHover { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("other_links")]
|
||||
public List<IconLink> OtherLinks { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("icon_link")]
|
||||
public string IconLink { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("links")]
|
||||
public List<IconLink> Links { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("enable_red_dot")]
|
||||
public bool EnableRedDot { get; set; }
|
||||
|
||||
[JsonPropertyName("red_dot_content")]
|
||||
public string RedDotContent { get; set; } = default!;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
|
||||
|
||||
internal sealed class IconLink
|
||||
{
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; set; } = default!;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Content;
|
||||
|
||||
internal sealed class Link
|
||||
{
|
||||
[JsonPropertyName("faq")]
|
||||
public string FAQ { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("version")]
|
||||
public string Version { get; set; } = default!;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Content;
|
||||
|
||||
internal sealed class More
|
||||
{
|
||||
[JsonPropertyName("activity_link")]
|
||||
public string ActivityLink { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("announce_link")]
|
||||
public string AnnounceLink { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("info_link")]
|
||||
public string InfoLink { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("news_link")]
|
||||
public string NewsLink { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("trends_link")]
|
||||
public string TrendsLink { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("supply_link")]
|
||||
public string SupplyLink { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("tools_link")]
|
||||
public string ToolsLink { get; set; } = default!;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Content;
|
||||
|
||||
internal sealed class Post
|
||||
{
|
||||
[JsonPropertyName("post_id")]
|
||||
public string PostId { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// POST_TYPE_ACTIVITY|POST_TYPE_ANNOUNCE|POST_TYPE_INFO
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// MM/dd format
|
||||
/// </summary>
|
||||
[JsonPropertyName("show_time")]
|
||||
public string ShowTime { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("order")]
|
||||
public string Order { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; } = default!;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Content;
|
||||
|
||||
internal sealed class QQ
|
||||
{
|
||||
[JsonPropertyName("qq_id")]
|
||||
public string QQId { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("number")]
|
||||
public string Number { get; set; } = default!;
|
||||
|
||||
[JsonPropertyName("code")]
|
||||
public string Code { get; set; } = default!;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// 差异文件
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class DiffPackage : Package
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否为推荐更新
|
||||
/// </summary>
|
||||
[JsonPropertyName("is_recommended_update")]
|
||||
public bool IsRecommendedUpdate { get; set; }
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// 游戏
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class Game
|
||||
{
|
||||
/// <summary>
|
||||
/// 最新客户端
|
||||
/// </summary>
|
||||
[JsonPropertyName("latest")]
|
||||
public LatestPackage Latest { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 相对于当前版本的之前版本的差异文件(非预下载)
|
||||
/// </summary>
|
||||
[JsonPropertyName("diffs")]
|
||||
public List<DiffPackage> Diffs { get; set; } = default!;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// 游戏资源
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class GameResource
|
||||
{
|
||||
/// <summary>
|
||||
/// 本体
|
||||
/// </summary>
|
||||
[JsonPropertyName("game")]
|
||||
public Game Game { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 插件
|
||||
/// </summary>
|
||||
[JsonPropertyName("plugin")]
|
||||
public Plugin Plugin { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 官网地址 https://ys.mihoyo.com/launcher
|
||||
/// </summary>
|
||||
[JsonPropertyName("web_url")]
|
||||
public Uri WebUrl { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 强制更新文件 null
|
||||
/// </summary>
|
||||
[JsonPropertyName("force_update")]
|
||||
public object? ForceUpdate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 预下载
|
||||
/// </summary>
|
||||
[JsonPropertyName("pre_download_game")]
|
||||
public Game? PreDownloadGame { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 过期更新包
|
||||
/// </summary>
|
||||
[JsonPropertyName("deprecated_packages")]
|
||||
public List<NameMd5> DeprecatedPackages { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 渠道服 sdk
|
||||
/// </summary>
|
||||
[JsonPropertyName("sdk")]
|
||||
public Sdk? Sdk { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 过期的单个文件
|
||||
/// </summary>
|
||||
[JsonPropertyName("deprecated_files")]
|
||||
public List<NameMd5>? DeprecatedFiles { get; set; }
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
internal sealed class LatestPackage : Package
|
||||
{
|
||||
[JsonPropertyName("segments")]
|
||||
public List<PackageSegment> Segments { get; set; } = default!;
|
||||
|
||||
public new string DisplayName { get => Name; }
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
internal static class LatestPackageExtension
|
||||
{
|
||||
public static void Patch(this LatestPackage latest)
|
||||
{
|
||||
StringBuilder pathBuilder = new();
|
||||
foreach (PackageSegment segment in latest.Segments)
|
||||
{
|
||||
pathBuilder.AppendLine(segment.Path);
|
||||
}
|
||||
|
||||
latest.Path = pathBuilder.ToStringTrimEndReturn();
|
||||
latest.Name = Path.GetFileName(latest.Segments[0].Path[..^4]); // .00X
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// 资源文件
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal class NameMd5
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件名称
|
||||
/// 相对于 EXE 的路径,如 YuanShen_Data/Plugins/PCGameSDK.dll
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Md5 校验值
|
||||
/// </summary>
|
||||
[JsonPropertyName("md5")]
|
||||
public string Md5 { get; set; } = default!;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// 最新客户端
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal class Package : PathMd5
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称 空
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 版本
|
||||
/// </summary>
|
||||
[JsonPropertyName("version")]
|
||||
public string Version { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 尺寸
|
||||
/// </summary>
|
||||
[JsonPropertyName("size")]
|
||||
public long Size { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 主程序相对路径 YuanShen.exe
|
||||
/// </summary>
|
||||
public string Entry { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 语音包
|
||||
/// </summary>
|
||||
[JsonPropertyName("voice_packs")]
|
||||
public List<VoicePackage> VoicePacks { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 松散文件
|
||||
/// 用于校验完整性
|
||||
/// </summary>
|
||||
[JsonPropertyName("decompressed_path")]
|
||||
public string DecompressedPath { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 包大小 bytes
|
||||
/// </summary>
|
||||
[JsonPropertyName("package_size")]
|
||||
public long PackageSize { get; set; } = default!;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
internal sealed class PackageSegment : PathMd5
|
||||
{
|
||||
[JsonPropertyName("package_size")]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
|
||||
public long PackageSize { get; set; } = default!;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// 插件
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class Plugin
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件列表
|
||||
/// </summary>
|
||||
[JsonPropertyName("plugins")]
|
||||
public List<PluginItem> Plugins { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 一般为 1
|
||||
/// </summary>
|
||||
[JsonPropertyName("version")]
|
||||
public string Version { get; set; } = default!;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// 插件项
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class PluginItem : NameMd5
|
||||
{
|
||||
/// <summary>
|
||||
/// 版本 一般为空
|
||||
/// </summary>
|
||||
[JsonPropertyName("version")]
|
||||
public string Version { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 下载地址
|
||||
/// </summary>
|
||||
[JsonPropertyName("path")]
|
||||
public Uri Path { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 尺寸
|
||||
/// </summary>
|
||||
[JsonPropertyName("size")]
|
||||
public long Size { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 一般为空
|
||||
/// </summary>
|
||||
[JsonPropertyName("entry")]
|
||||
public string Entry { get; set; } = default!;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// Sdk
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class Sdk : PathMd5
|
||||
{
|
||||
/// <summary>
|
||||
/// 版本
|
||||
/// </summary>
|
||||
[JsonPropertyName("version")]
|
||||
public string Version { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 常量 sdk_pkg_version
|
||||
/// </summary>
|
||||
[JsonPropertyName("pkg_version")]
|
||||
public string PackageVersion { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
[JsonPropertyName("desc")]
|
||||
public string Description { get; set; } = default!;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
|
||||
/// <summary>
|
||||
/// 语音包
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class VoicePackage : PathMd5
|
||||
{
|
||||
/// <summary>
|
||||
/// 语音
|
||||
/// </summary>
|
||||
[JsonPropertyName("language")]
|
||||
public string Language { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 名称 一般为空
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 解压尺寸
|
||||
/// </summary>
|
||||
[JsonPropertyName("size")]
|
||||
public long Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 包尺寸
|
||||
/// </summary>
|
||||
[JsonPropertyName("package_size")]
|
||||
public long PackageSize { get; set; } = default!;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Service.Game.Scheme;
|
||||
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Content;
|
||||
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher.Resource;
|
||||
using Snap.Hutao.Web.Request.Builder;
|
||||
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
|
||||
|
||||
/// <summary>
|
||||
/// 游戏资源客户端
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[ConstructorGenerated(ResolveHttpClient = true)]
|
||||
[HttpClient(HttpClientConfiguration.Default)]
|
||||
internal sealed partial class ResourceClient
|
||||
{
|
||||
private readonly IHttpRequestMessageBuilderFactory httpRequestMessageBuilderFactory;
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly ILogger<ResourceClient> logger;
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取游戏资源
|
||||
/// </summary>
|
||||
/// <param name="scheme">方案</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>游戏资源</returns>
|
||||
public async ValueTask<Response<GameResource>> GetResourceAsync(LaunchScheme scheme, CancellationToken token = default)
|
||||
{
|
||||
string url = scheme.IsOversea
|
||||
? ApiOsEndpoints.SdkOsStaticLauncherResource(scheme)
|
||||
: ApiEndpoints.SdkStaticLauncherResource(scheme);
|
||||
|
||||
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
||||
.SetRequestUri(url)
|
||||
.Get();
|
||||
|
||||
Response<GameResource>? resp = await builder
|
||||
.SendAsync<Response<GameResource>>(httpClient, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// 最新版完整包
|
||||
if (resp is { Data.Game.Latest: LatestPackage latest })
|
||||
{
|
||||
latest.Patch();
|
||||
}
|
||||
|
||||
// 预下载完整包
|
||||
if (resp is { Data.PreDownloadGame.Latest: LatestPackage preDownloadLatest })
|
||||
{
|
||||
preDownloadLatest.Patch();
|
||||
}
|
||||
|
||||
return Response.Response.DefaultIfNull(resp);
|
||||
}
|
||||
|
||||
public async ValueTask<Response<GameContent>> GetContentAsync(LaunchScheme scheme, string languageCode, bool advOnly = true, CancellationToken token = default)
|
||||
{
|
||||
string url = scheme.IsOversea
|
||||
? ApiOsEndpoints.SdkOsStaticLauncherContent(scheme, languageCode, advOnly)
|
||||
: ApiEndpoints.SdkStaticLauncherContent(scheme, languageCode, advOnly);
|
||||
|
||||
HttpRequestMessageBuilder builder = httpRequestMessageBuilderFactory.Create()
|
||||
.SetRequestUri(url)
|
||||
.Get();
|
||||
|
||||
Response<GameContent>? resp = await builder
|
||||
.SendAsync<Response<GameContent>>(httpClient, logger, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return Response.Response.DefaultIfNull(resp);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user