Skip to content

Commit 0983b7a

Browse files
committed
Merge branch 'main' into preview
2 parents f702dc5 + 80e0551 commit 0983b7a

File tree

9 files changed

+158
-39
lines changed

9 files changed

+158
-39
lines changed

CollapseLauncher/Classes/GameManagement/Versioning/GameVersionBase.GameState.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,11 @@ public virtual async ValueTask<List<RegionResourcePlugin>> CheckPluginUpdate(str
528528
// If all not passed, then return null.
529529
return null;
530530
}
531+
532+
public virtual bool IsForceRedirectToSophon()
533+
{
534+
return GamePreset.GameLauncherApi?.IsForceRedirectToSophon ?? false;
535+
}
531536
#endregion
532537
}
533538
}

CollapseLauncher/Classes/Helper/LauncherApiLoader/HoYoPlay/HoYoPlayLauncherApiLoader.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,6 @@ void AfterExecute(Task action)
156156
ConvertPackageResources(sophonResourceData, hypResourceResponse?.Data?.LauncherPackages);
157157

158158
LauncherGameResource = sophonResourcePropRoot;
159-
160-
PerformDebugRoutines();
161159
}
162160
}
163161

CollapseLauncher/Classes/Helper/LauncherApiLoader/HoYoPlay/HoYoPlayLauncherGameInfo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public sealed class HoYoPlayGameInfoBranchField
4040
[JsonPropertyName("branch")] public string? Branch { get; init; }
4141
[JsonPropertyName("password")] public string? Password { get; init; }
4242
[JsonPropertyName("tag")] public string? Tag { get; init; }
43+
[JsonPropertyName("diff_tags")] public List<string>? DiffTags { get; init; }
4344
}
4445

4546
public sealed class HoYoPlayGameInfoField

CollapseLauncher/Classes/Helper/LauncherApiLoader/ILauncherApi.cs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,26 @@
66
using System.Threading;
77
using System.Threading.Tasks;
88
// ReSharper disable UnusedMemberInSuper.Global
9+
// ReSharper disable IdentifierTypo
910

1011
#nullable enable
1112
namespace CollapseLauncher.Helper.LauncherApiLoader
1213
{
1314
public interface ILauncherApi : IDisposable
1415
{
15-
bool IsLoadingCompleted { get; }
16-
string? GameBackgroundImg { get; }
17-
string? GameBackgroundImgLocal { get; set; }
18-
string? GameName { get; }
19-
string? GameRegion { get; }
20-
string? GameNameTranslation { get; }
21-
string? GameRegionTranslation { get; }
22-
HoYoPlayGameInfoField? LauncherGameInfoField { get; }
23-
RegionResourceProp? LauncherGameResource { get; }
24-
LauncherGameNews? LauncherGameNews { get; }
25-
HttpClient? ApiGeneralHttpClient { get; }
26-
HttpClient? ApiResourceHttpClient { get; }
16+
bool IsLoadingCompleted { get; }
17+
bool IsForceRedirectToSophon { get; }
18+
string? GameBackgroundImg { get; }
19+
string? GameBackgroundImgLocal { get; set; }
20+
string? GameName { get; }
21+
string? GameRegion { get; }
22+
string? GameNameTranslation { get; }
23+
string? GameRegionTranslation { get; }
24+
HoYoPlayGameInfoField? LauncherGameInfoField { get; }
25+
RegionResourceProp? LauncherGameResource { get; }
26+
LauncherGameNews? LauncherGameNews { get; }
27+
HttpClient? ApiGeneralHttpClient { get; }
28+
HttpClient? ApiResourceHttpClient { get; }
2729
Task<bool> LoadAsync(OnLoadTaskAction? beforeLoadRoutine = null, OnLoadTaskAction? afterLoadRoutine = null,
2830
ActionOnTimeOutRetry? onTimeoutRoutine = null, ErrorLoadRoutineDelegate? errorLoadRoutine = null,
2931
CancellationToken token = default);

CollapseLauncher/Classes/Helper/LauncherApiLoader/LauncherApiBase.cs

Lines changed: 122 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515
using System.Net;
1616
using System.Net.Http.Json;
1717
using System.Runtime.CompilerServices;
18+
using System.Linq;
19+
using System.Collections.Generic;
1820
// ReSharper disable PartialTypeWithSinglePart
1921
// ReSharper disable IdentifierTypo
2022
// ReSharper disable StringLiteralTypo
2123
// ReSharper disable VirtualMemberCallInConstructor
24+
// ReSharper disable CommentTypo
2225

2326
#nullable enable
2427
namespace CollapseLauncher.Helper.LauncherApiLoader
@@ -33,23 +36,25 @@ internal partial class LauncherApiBase : ILauncherApi
3336
public const int ExecutionTimeoutAttempt = 5;
3437
protected PresetConfig? PresetConfig { get; }
3538

36-
public bool IsLoadingCompleted { get; private set; }
37-
public string? GameBackgroundImg { get => LauncherGameNews?.Content?.Background?.BackgroundImg; }
38-
public string? GameBackgroundImgLocal { get; set; }
39-
public string? GameName { get; init; }
40-
public string? GameRegion { get; init; }
39+
public bool IsLoadingCompleted { get; private set; }
40+
public bool IsForceRedirectToSophon { get; private set; }
41+
public string? GameBackgroundImg { get => LauncherGameNews?.Content?.Background?.BackgroundImg; }
42+
public string? GameBackgroundImgLocal { get; set; }
43+
public string? GameName { get; init; }
44+
public string? GameRegion { get; init; }
4145

4246
public string? GameNameTranslation =>
4347
InnerLauncherConfig.GetGameTitleRegionTranslationString(GameName, Locale.Lang._GameClientTitles);
4448

4549
public string? GameRegionTranslation =>
4650
InnerLauncherConfig.GetGameTitleRegionTranslationString(GameRegion, Locale.Lang._GameClientRegions);
4751

48-
public virtual RegionResourceProp? LauncherGameResource { get; protected set; }
49-
public virtual LauncherGameNews? LauncherGameNews { get; protected set; }
50-
public virtual HoYoPlayGameInfoField? LauncherGameInfoField { get; protected set; }
51-
public virtual HttpClient ApiGeneralHttpClient { get; protected set; }
52-
public virtual HttpClient ApiResourceHttpClient { get; protected set; }
52+
public virtual RegionResourceProp? LauncherGameResource { get; protected set; }
53+
public virtual HoYoPlayLauncherGameInfo? LauncherGameResourceSophon { get; protected set; }
54+
public virtual LauncherGameNews? LauncherGameNews { get; protected set; }
55+
public virtual HoYoPlayGameInfoField? LauncherGameInfoField { get; protected set; }
56+
public virtual HttpClient ApiGeneralHttpClient { get; protected set; }
57+
public virtual HttpClient ApiResourceHttpClient { get; protected set; }
5358

5459
public void Dispose()
5560
{
@@ -114,9 +119,11 @@ protected LauncherApiBase(PresetConfig presetConfig, string gameName, string gam
114119
ApiResourceHttpClient = apiResourceHttpBuilder.Create();
115120
}
116121

117-
public async Task<bool> LoadAsync(OnLoadTaskAction? beforeLoadRoutine, OnLoadTaskAction? afterLoadRoutine,
118-
ActionOnTimeOutRetry? onTimeoutRoutine, ErrorLoadRoutineDelegate? errorLoadRoutine,
119-
CancellationToken token)
122+
public async Task<bool> LoadAsync(OnLoadTaskAction? beforeLoadRoutine,
123+
OnLoadTaskAction? afterLoadRoutine,
124+
ActionOnTimeOutRetry? onTimeoutRoutine,
125+
ErrorLoadRoutineDelegate? errorLoadRoutine,
126+
CancellationToken token)
120127
{
121128
_ = beforeLoadRoutine?.Invoke(token) ?? Task.CompletedTask;
122129

@@ -140,12 +147,109 @@ public async Task<bool> LoadAsync(OnLoadTaskAction? beforeLoadRoutine, OnLoa
140147
}
141148
}
142149

143-
protected virtual Task LoadAsyncInner(ActionOnTimeOutRetry? onTimeoutRoutine,
144-
CancellationToken token)
150+
protected virtual async Task LoadAsyncInner(ActionOnTimeOutRetry? onTimeoutRoutine,
151+
CancellationToken token)
145152
{
146-
return Task.WhenAll(LoadLauncherGameResource(onTimeoutRoutine, token),
147-
LoadLauncherNews(onTimeoutRoutine, token),
148-
LoadLauncherGameInfo(onTimeoutRoutine, token));
153+
// 2025-05-05: As per now, the Sophon resource information requires to be fetched first.
154+
// This is mandatory due to latest Genshin Impact changes which removes zip
155+
// packages and also version infos.
156+
await LoadLauncherGameResourceSophon(onTimeoutRoutine, token);
157+
await Task.WhenAll(LoadLauncherGameResource(onTimeoutRoutine, token),
158+
LoadLauncherNews(onTimeoutRoutine, token),
159+
LoadLauncherGameInfo(onTimeoutRoutine, token));
160+
161+
InitializeFakeVersionInfo();
162+
PerformDebugRoutines();
163+
}
164+
165+
protected virtual void InitializeFakeVersionInfo()
166+
{
167+
if (LauncherGameResource?.data == null)
168+
{
169+
return;
170+
}
171+
172+
HoYoPlayGameInfoBranch? gameBranch = LauncherGameResourceSophon?.GameInfoData?.GameBranchesInfo?
173+
.FirstOrDefault(x => x.GameInfo?.BizName?.Equals(PresetConfig?.LauncherBizName) ?? false);
174+
175+
if (gameBranch == null)
176+
{
177+
return;
178+
}
179+
180+
var branchPreloadField = gameBranch.GamePreloadField;
181+
var branchBaseField = gameBranch.GameMainField;
182+
183+
if (branchPreloadField != null)
184+
{
185+
LauncherGameResource.data.pre_download_game ??= new RegionResourceLatest();
186+
AddFakeVersionInfo(branchPreloadField, LauncherGameResource.data.pre_download_game);
187+
}
188+
189+
if (branchBaseField == null)
190+
{
191+
return;
192+
}
193+
194+
LauncherGameResource.data.game ??= new RegionResourceLatest();
195+
AddFakeVersionInfo(branchBaseField, LauncherGameResource.data.game);
196+
IsForceRedirectToSophon = true;
197+
}
198+
199+
protected virtual void AddFakeVersionInfo(HoYoPlayGameInfoBranchField branchField, RegionResourceLatest region)
200+
{
201+
region.latest ??= new RegionResourceVersion();
202+
region.latest.version = branchField.Tag;
203+
204+
region.diffs ??= [];
205+
206+
HashSet<string> existingDiffsVer = new(region.diffs.Select(x => x.version)!);
207+
foreach (var versionTags in (branchField.DiffTags ?? []).Where(x => !existingDiffsVer.Contains(x)))
208+
{
209+
region.diffs.Add(new RegionResourceVersion
210+
{
211+
version = versionTags
212+
});
213+
}
214+
}
215+
216+
protected virtual async Task LoadLauncherGameResourceSophon(ActionOnTimeOutRetry? onTimeoutRoutine,
217+
CancellationToken token)
218+
{
219+
EnsurePresetConfigNotNull();
220+
221+
SophonChunkUrls? sophonUrls = PresetConfig?.LauncherResourceChunksURL;
222+
if (sophonUrls == null)
223+
{
224+
return;
225+
}
226+
227+
string? sophonBranchUrl = sophonUrls.BranchUrl;
228+
if (string.IsNullOrEmpty(PresetConfig!.LauncherBizName) || string.IsNullOrEmpty(sophonBranchUrl))
229+
{
230+
Logger.LogWriteLine("This game/region doesn't have Sophon->BranchUrl or PresetConfig->LauncherBizName property defined! This might cause the launcher inaccurately check the version if Zip download is unavailable", LogType.Warning, true);
231+
}
232+
233+
await sophonUrls.EnsureReassociated(ApiGeneralHttpClient,
234+
sophonBranchUrl,
235+
PresetConfig.LauncherBizName!,
236+
false,
237+
token);
238+
sophonUrls.ResetAssociation(); // Reset association so it won't conflict with preload/update/install activity
239+
240+
ActionTimeoutTaskAwaitableCallback<HoYoPlayLauncherGameInfo?> launcherSophonBranchCallback =
241+
innerToken =>
242+
ApiGeneralHttpClient.GetFromJsonAsync(PresetConfig.LauncherResourceChunksURL?.BranchUrl,
243+
HoYoPlayLauncherGameInfoJsonContext.Default.HoYoPlayLauncherGameInfo,
244+
innerToken)
245+
.ConfigureAwait(false);
246+
247+
LauncherGameResourceSophon = await launcherSophonBranchCallback
248+
.WaitForRetryAsync(ExecutionTimeout,
249+
ExecutionTimeoutStep,
250+
ExecutionTimeoutAttempt,
251+
onTimeoutRoutine,
252+
token);
149253
}
150254

151255
protected virtual Task LoadLauncherGameResource(ActionOnTimeOutRetry? onTimeoutRoutine,
@@ -213,8 +317,6 @@ void AfterExecute(Task action)
213317
LogType.Debug, true);
214318
#endif
215319
}
216-
217-
PerformDebugRoutines();
218320
}
219321
}
220322

CollapseLauncher/Classes/Helper/Metadata/PresetConfig.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ public class SophonChunkUrls
9898
[JsonConverter(typeof(ServeV3StringConverter))]
9999
public string? SdkUrl { get; set; }
100100

101+
public bool ResetAssociation() => IsReassociated = false;
102+
101103
public Task EnsureReassociated(HttpClient client, string? branchUrl, string bizName, bool isPreloadForPatch, CancellationToken token)
102104
{
103105
if (IsReassociated)

CollapseLauncher/Classes/InstallManagement/Base/InstallManagerBase.Sophon.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,11 @@ protected bool _isSophonPreloadCompleted
8383

8484
#region Public Virtual Properties
8585
public virtual bool IsUseSophon =>
86-
GameVersionManager.GamePreset.LauncherResourceChunksURL != null
86+
GameVersionManager.IsForceRedirectToSophon() ||
87+
(GameVersionManager.GamePreset.LauncherResourceChunksURL != null
8788
&& !File.Exists(Path.Combine(GamePath, "@DisableSophon"))
8889
&& !_canDeltaPatch && !_forceIgnoreDeltaPatch
89-
&& LauncherConfig.GetAppConfigValue("IsEnableSophon").ToBool();
90+
&& LauncherConfig.GetAppConfigValue("IsEnableSophon").ToBool());
9091
#endregion
9192

9293
#region Sophon Verification Methods

CollapseLauncher/Classes/InstallManagement/Genshin/GenshinInstall.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,10 @@ namespace CollapseLauncher.InstallManager.Genshin
2727
internal sealed partial class GenshinInstall : InstallManagerBase
2828
{
2929
#region Override Properties
30-
3130
protected override int _gameVoiceLanguageID => GameVersionManager.GamePreset.GetVoiceLanguageID();
32-
3331
#endregion
3432

3533
#region Properties
36-
3734
protected override string _gameAudioLangListPath
3835
{
3936
get
@@ -74,6 +71,12 @@ public GenshinInstall(UIElement parentUI, IGameVersion GameVersionManager)
7471
#nullable enable
7572
public override async ValueTask<bool> IsPreloadCompleted(CancellationToken token)
7673
{
74+
// If it's forcely redirected to sophon, check the preload using sophon
75+
if (GameVersionManager.IsForceRedirectToSophon())
76+
{
77+
return await base.IsPreloadCompleted(token);
78+
}
79+
7780
// Get the primary file first check
7881
List<RegionResourceVersion>? resource = GameVersionManager.GetGamePreloadZip();
7982

CollapseLauncher/Classes/Interfaces/IGameVersionCheck.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ internal interface IGameVersion
130130
/// </summary>
131131
bool IsGameHasDeltaPatch();
132132

133+
/// <summary>
134+
/// Check if the game installation is forcefully redirected to Sophon.
135+
/// </summary>
136+
bool IsForceRedirectToSophon();
137+
133138
/// <summary>
134139
/// Returns the state of the game.
135140
/// </summary>

0 commit comments

Comments
 (0)