Skip to content

Commit

Permalink
fix server conversion error
Browse files Browse the repository at this point in the history
  • Loading branch information
Lightczx committed Nov 29, 2024
1 parent 5f7a9a9 commit c3b694c
Show file tree
Hide file tree
Showing 11 changed files with 269 additions and 139 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,23 @@ public bool TryGetGameFileSystem([NotNullWhen(true)] out IGameFileSystem? gameFi
return true;
}

public void UpdateGamePathEntry()
public void PerformGamePathEntrySynchronization()
{
// Invalidate game file system
gameFileSystem?.Dispose();
gameFileSystem = null;

ImmutableArray<GamePathEntry> gamePathEntries = Options.GetGamePathEntries(out GamePathEntry? selectedEntry);
ViewModel.SetGamePathEntriesAndSelectedGamePathEntry(gamePathEntries, selectedEntry);
ViewModel.SetGamePathEntriesAndSelectedGamePathEntry(Options);
}

public void UpdateGamePath(string gamePath)
{
// Invalidate game file system
gameFileSystem?.Dispose();
gameFileSystem = null;

Options.GamePath = gamePath;
PerformGamePathEntrySynchronization();
}

public void Dispose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ internal interface IPackageConverter
{
ValueTask<bool> EnsureGameResourceAsync(PackageConverterContext context);

ValueTask EnsureDeprecatedFilesAndSdkAsync(PackageConverterContext context);
ValueTask EnsureDeprecatedFilesAndSdkAsync(PackageConverterDeprecationContext context);
}
44 changes: 44 additions & 0 deletions src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.

using Snap.Hutao.Core.IO;
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.DeprecatedFile;
using System.IO;
using System.IO.Compression;

namespace Snap.Hutao.Service.Game.Package;

internal abstract class PackageConverter : IPackageConverter
{
public abstract ValueTask<bool> EnsureGameResourceAsync(PackageConverterContext context);

public virtual async ValueTask EnsureDeprecatedFilesAndSdkAsync(PackageConverterDeprecationContext context)
{
// Just try to delete these files, always download from server when needed
string gameDirectory = context.GameFileSystem.GetGameDirectory();
FileOperation.Delete(Path.Combine(gameDirectory, GameConstants.YuanShenData, "Plugins\\PCGameSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, GameConstants.GenshinImpactData, "Plugins\\PCGameSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, GameConstants.YuanShenData, "Plugins\\EOSSDK-Win64-Shipping.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, GameConstants.GenshinImpactData, "Plugins\\EOSSDK-Win64-Shipping.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, GameConstants.YuanShenData, "Plugins\\PluginEOSSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, GameConstants.GenshinImpactData, "Plugins\\PluginEOSSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, "sdk_pkg_version"));

if (context.GameChannelSdk is not null)
{
using (Stream sdkWebStream = await context.HttpClient.GetStreamAsync(context.GameChannelSdk.ChannelSdkPackage.Url).ConfigureAwait(false))
{
ZipFile.ExtractToDirectory(sdkWebStream, gameDirectory, true);
}
}

if (context.DeprecatedFiles is not null)
{
foreach (DeprecatedFile file in context.DeprecatedFiles.DeprecatedFiles)
{
string filePath = Path.Combine(gameDirectory, file.Name);
FileOperation.Move(filePath, $"{filePath}.backup", true);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,6 @@ private PackageConverterContext(CommonReferences common)

public IGameFileSystem GameFileSystem { get => Common.GameFileSystem; }

public GameChannelSDK? GameChannelSDK { get => Common.GameChannelSDK; }

public DeprecatedFilesWrapper? DeprecatedFiles { get => Common.DeprecatedFiles; }

public IProgress<PackageConvertStatus> Progress { get => Common.Progress; }

public readonly string GetScatteredFilesUrl(string file)
Expand Down Expand Up @@ -124,25 +120,19 @@ internal readonly struct CommonReferences
public readonly LaunchScheme CurrentScheme;
public readonly LaunchScheme TargetScheme;
public readonly IGameFileSystem GameFileSystem;
public readonly GameChannelSDK? GameChannelSDK;
public readonly DeprecatedFilesWrapper? DeprecatedFiles;
public readonly IProgress<PackageConvertStatus> Progress;

public CommonReferences(
HttpClient httpClient,
LaunchScheme currentScheme,
LaunchScheme targetScheme,
IGameFileSystem gameFileSystem,
GameChannelSDK? gameChannelSDK,
DeprecatedFilesWrapper? deprecatedFiles,
IProgress<PackageConvertStatus> progress)
{
HttpClient = httpClient;
CurrentScheme = currentScheme;
TargetScheme = targetScheme;
GameFileSystem = gameFileSystem;
GameChannelSDK = gameChannelSDK;
DeprecatedFiles = deprecatedFiles;
Progress = progress;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.

using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.ChannelSDK;
using Snap.Hutao.Web.Hoyolab.HoyoPlay.Connect.DeprecatedFile;
using System.Net.Http;

namespace Snap.Hutao.Service.Game.Package;

internal readonly struct PackageConverterDeprecationContext
{
public readonly HttpClient HttpClient;
public readonly IGameFileSystem GameFileSystem;
public readonly GameChannelSDK? GameChannelSdk;
public readonly DeprecatedFilesWrapper? DeprecatedFiles;

public PackageConverterDeprecationContext(HttpClient httpClient, IGameFileSystem gameFileSystem, GameChannelSDK? gameChannelSdk, DeprecatedFilesWrapper? deprecatedFiles)
{
HttpClient = httpClient;
GameFileSystem = gameFileSystem;
GameChannelSdk = gameChannelSdk;
DeprecatedFiles = deprecatedFiles;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace Snap.Hutao.Service.Game.Package;

[ConstructorGenerated]
[Injection(InjectAs.Transient, typeof(IPackageConverter), Key = PackageConverterType.ScatteredFiles)]
internal sealed partial class ScatteredFilesPackageConverter : IPackageConverter
internal sealed partial class ScatteredFilesPackageConverter : PackageConverter
{
private const string PackageVersion = "pkg_version";

Expand All @@ -29,7 +29,7 @@ internal sealed partial class ScatteredFilesPackageConverter : IPackageConverter
[GeneratedRegex("^(?:YuanShen_Data|GenshinImpact_Data)(?=/)")]
private static partial Regex DataFolderRegex { get; }

public async ValueTask<bool> EnsureGameResourceAsync(PackageConverterContext context)
public override async ValueTask<bool> EnsureGameResourceAsync(PackageConverterContext context)
{
// 以 国服 -> 国际服 为例
// 1. 下载国际服的 pkg_version 文件,转换为索引字典
Expand Down Expand Up @@ -67,36 +67,6 @@ public async ValueTask<bool> EnsureGameResourceAsync(PackageConverterContext con
return await ReplaceGameResourceAsync(context, diffOperations).ConfigureAwait(false);
}

public async ValueTask EnsureDeprecatedFilesAndSdkAsync(PackageConverterContext context)
{
// Just try to delete these files, always download from server when needed
string gameDirectory = context.GameFileSystem.GetGameDirectory();
FileOperation.Delete(Path.Combine(gameDirectory, YuanShenData, "Plugins\\PCGameSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, GenshinImpactData, "Plugins\\PCGameSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, YuanShenData, "Plugins\\EOSSDK-Win64-Shipping.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, GenshinImpactData, "Plugins\\EOSSDK-Win64-Shipping.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, YuanShenData, "Plugins\\PluginEOSSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, GenshinImpactData, "Plugins\\PluginEOSSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, "sdk_pkg_version"));

if (context.GameChannelSDK is not null)
{
using (Stream sdkWebStream = await context.HttpClient.GetStreamAsync(context.GameChannelSDK.ChannelSdkPackage.Url).ConfigureAwait(false))
{
ZipFile.ExtractToDirectory(sdkWebStream, gameDirectory, true);
}
}

if (context.DeprecatedFiles is not null)
{
foreach (DeprecatedFile file in context.DeprecatedFiles.DeprecatedFiles)
{
string filePath = Path.Combine(gameDirectory, file.Name);
FileOperation.Move(filePath, $"{filePath}.backup", true);
}
}
}

private static IEnumerable<PackageItemOperationInfo> GetItemOperationInfos(RelativePathVersionItemDictionary remote, RelativePathVersionItemDictionary local)
{
foreach ((string remoteName, VersionItem remoteItem) in remote)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ namespace Snap.Hutao.Service.Game.Package;

[ConstructorGenerated]
[Injection(InjectAs.Transient, typeof(IPackageConverter), Key = PackageConverterType.SophonChunks)]
internal sealed partial class SophonChunksPackageConverter : IPackageConverter
internal sealed partial class SophonChunksPackageConverter : PackageConverter
{
private readonly IMemoryStreamFactory memoryStreamFactory;
private readonly ILogger<SophonChunksPackageConverter> logger;
private readonly IServiceProvider serviceProvider;

public async ValueTask<bool> EnsureGameResourceAsync(PackageConverterContext context)
public override async ValueTask<bool> EnsureGameResourceAsync(PackageConverterContext context)
{
// 基本步骤与 ScatteredPackageConverter 相同
// 以 国服 -> 国际服 为例
Expand Down Expand Up @@ -75,36 +75,6 @@ public async ValueTask<bool> EnsureGameResourceAsync(PackageConverterContext con
return ReplaceGameResource(context, diffOperations);
}

public async ValueTask EnsureDeprecatedFilesAndSdkAsync(PackageConverterContext context)
{
// Just try to delete these files, always download from server when needed
string gameDirectory = context.GameFileSystem.GetGameDirectory();
FileOperation.Delete(Path.Combine(gameDirectory, YuanShenData, "Plugins\\PCGameSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, GenshinImpactData, "Plugins\\PCGameSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, YuanShenData, "Plugins\\EOSSDK-Win64-Shipping.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, GenshinImpactData, "Plugins\\EOSSDK-Win64-Shipping.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, YuanShenData, "Plugins\\PluginEOSSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, GenshinImpactData, "Plugins\\PluginEOSSDK.dll"));
FileOperation.Delete(Path.Combine(gameDirectory, "sdk_pkg_version"));

if (context.GameChannelSDK is not null)
{
using (Stream sdkWebStream = await context.HttpClient.GetStreamAsync(context.GameChannelSDK.ChannelSdkPackage.Url).ConfigureAwait(false))
{
ZipFile.ExtractToDirectory(sdkWebStream, gameDirectory, true);
}
}

if (context.DeprecatedFiles is not null)
{
foreach (DeprecatedFile file in context.DeprecatedFiles.DeprecatedFiles)
{
string filePath = Path.Combine(gameDirectory, file.Name);
FileOperation.Move(filePath, $"{filePath}.backup", true);
}
}
}

private static IEnumerable<PackageItemOperationForSophonChunks> GetDiffOperations(SophonDecodedBuild currentDecodedBuild, SophonDecodedBuild targetDecodedBuild)
{
foreach ((SophonDecodedManifest currentManifest, SophonDecodedManifest targetManifest) in currentDecodedBuild.Manifests.Zip(targetDecodedBuild.Manifests))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,45 @@ public static bool TryGetGameFileSystem(this IRestrictedGamePathAccess access, [
return true;
}

public static ImmutableArray<GamePathEntry> GetGamePathEntries(this IRestrictedGamePathAccess access, out GamePathEntry? selected)
public static ImmutableArray<GamePathEntry> PerformGamePathEntrySynchronization(this IRestrictedGamePathAccess access, out GamePathEntry? selected)
{
string gamePath = access.GamePath;

// The game path is null or empty, this means no game path is selected, just return the entries.
if (string.IsNullOrEmpty(gamePath))
{
selected = default;
return access.GamePathEntries;
}

if (access.GamePathEntries.SingleOrDefault(entry => string.Equals(entry.Path, access.GamePath, StringComparison.OrdinalIgnoreCase)) is { } existed)
// The game path is in the entries, just return the entries.
if (access.GamePathEntries.SingleOrDefault(entry => string.Equals(entry.Path, gamePath, StringComparison.OrdinalIgnoreCase)) is { } existed)
{
selected = existed;
return access.GamePathEntries;
}

selected = GamePathEntry.Create(access.GamePath);
return access.GamePathEntries = access.GamePathEntries.Add(selected);
// We need update the entries when game path not in the entries.
if (!access.GamePathLock.TryWriterLock(out AsyncReaderWriterLock.Releaser releaser))
{
throw HutaoException.InvalidOperation("Cannot get game path entries while it is being used.");
}

using (releaser)
{
// The game path is not in the entries, add it to the entries.
selected = GamePathEntry.Create(access.GamePath);
return access.GamePathEntries = access.GamePathEntries.Add(selected);
}
}

public static ImmutableArray<GamePathEntry> RemoveGamePathEntry(this IRestrictedGamePathAccess access, GamePathEntry? entry, out GamePathEntry? selected)
{
// Although normally this should not happen, we still handle it for compatibility.
if (entry is null)
{
return access.GetGamePathEntries(out selected);
// Removes no entry, just return the entries.
return access.PerformGamePathEntrySynchronization(out selected);
}

if (!access.GamePathLock.TryWriterLock(out AsyncReaderWriterLock.Releaser releaser))
Expand All @@ -63,14 +77,18 @@ public static ImmutableArray<GamePathEntry> RemoveGamePathEntry(this IRestricted

using (releaser)
{
// Clear game path if it's selected.
if (string.Equals(access.GamePath, entry.Path, StringComparison.OrdinalIgnoreCase))
{
access.GamePath = string.Empty;
}

access.GamePathEntries = access.GamePathEntries.Remove(entry);
return access.GetGamePathEntries(out selected);
}

// Synchronization takes write lock when game path changed,
// so we release the write lock before calling.
return access.PerformGamePathEntrySynchronization(out selected);
}

public static ImmutableArray<GamePathEntry> UpdateGamePath(this IRestrictedGamePathAccess access, string gamePath)
Expand All @@ -83,7 +101,10 @@ public static ImmutableArray<GamePathEntry> UpdateGamePath(this IRestrictedGameP
using (releaser)
{
access.GamePath = gamePath;
return access.GetGamePathEntries(out _);
}

// Synchronization takes write lock when game path changed,
// so we release the write lock before calling.
return access.PerformGamePathEntrySynchronization(out _);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public async ValueTask<bool> ReceiveAsync(INavigationExtraData data)

protected override ValueTask<bool> LoadOverrideAsync()
{
SetGamePathEntriesAndSelectedGamePathEntry(LaunchOptions.GetGamePathEntries(out GamePathEntry? entry), entry);
this.SetGamePathEntriesAndSelectedGamePathEntry(LaunchOptions);
return ValueTask.FromResult(true);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.

using Snap.Hutao.Service.Game;
using Snap.Hutao.Service.Game.PathAbstraction;

namespace Snap.Hutao.ViewModel.Game;

internal static class ViewModelSupportLaunchExecutionExtension
{
public static void SetGamePathEntriesAndSelectedGamePathEntry(this IViewModelSupportLaunchExecution viewModel, IRestrictedGamePathAccess access)
{
viewModel.SetGamePathEntriesAndSelectedGamePathEntry(access.PerformGamePathEntrySynchronization(out GamePathEntry? selected), selected);
}
}

0 comments on commit c3b694c

Please sign in to comment.