Skip to content

Commit 34c01cd

Browse files
committed
[HonkaiRepair] Fix streamingasb:80 host error while EnableHTTPRepairOverride is true
1 parent 5c73984 commit 34c01cd

6 files changed

Lines changed: 198 additions & 236 deletions

File tree

CollapseLauncher/Classes/CachesManagement/Honkai/Fetch.cs

Lines changed: 14 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using CollapseLauncher.Helper;
22
using CollapseLauncher.Helper.Metadata;
33
using CollapseLauncher.Interfaces;
4+
using CollapseLauncher.RepairManagement;
45
using Hi3Helper;
56
using Hi3Helper.EncTool;
67
using Hi3Helper.EncTool.Parser.KianaDispatch;
@@ -20,6 +21,7 @@
2021
// ReSharper disable SwitchStatementHandlesSomeKnownEnumValuesWithDefault
2122
// ReSharper disable CommentTypo
2223
// ReSharper disable StringLiteralTypo
24+
#pragma warning disable IDE0130
2325

2426
namespace CollapseLauncher
2527
{
@@ -97,13 +99,14 @@ private async Task BuildGameRepoURL(HttpClient client, CancellationToken token)
9799
string key = GameVersionManager.GamePreset.DispatcherKey;
98100

99101
// Try assign dispatcher
100-
dispatch = await KianaDispatch.GetDispatch(client,
101-
baseURL,
102-
GameVersionManager.GamePreset.GameDispatchURLTemplate,
103-
GameVersionManager.GamePreset.GameDispatchChannelName,
104-
key,
105-
GameVersion.VersionArray,
106-
token);
102+
if (GameVersionManager.GamePreset is { GameDispatchURLTemplate: not null, GameDispatchChannelName: not null })
103+
dispatch = await KianaDispatch.GetDispatch(client,
104+
baseURL,
105+
GameVersionManager.GamePreset.GameDispatchURLTemplate,
106+
GameVersionManager.GamePreset.GameDispatchChannelName,
107+
key,
108+
GameVersion.VersionArray,
109+
token);
107110
lastException = null;
108111
break;
109112
}
@@ -117,12 +120,11 @@ private async Task BuildGameRepoURL(HttpClient client, CancellationToken token)
117120
if (lastException != null) throw lastException;
118121

119122
// Get gatewayURl and fetch the gateway
120-
GameGateway =
121-
await KianaDispatch.GetGameserver(client, dispatch!, GameVersionManager.GamePreset.GameGatewayDefault!, token);
123+
GameGateway = await KianaDispatch.GetGameserver(client, dispatch!, GameVersionManager.GamePreset.GameGatewayDefault!, token);
122124
GameRepoURL = BuildAssetBundleURL(GameGateway);
123125
}
124126

125-
private static string BuildAssetBundleURL(KianaDispatch gateway) => CombineURLFromString(gateway!.AssetBundleUrls![0], "/{0}/editor_compressed/");
127+
private string BuildAssetBundleURL(KianaDispatch gateway) => CombineURLFromString(this.GetRandomCacheBaseUrl(gateway), "/{0}/editor_compressed/");
126128

127129
private async Task<(int, long)> FetchByType(CacheAssetType type, HttpClient client, List<CacheAsset> assetIndex, CancellationToken token)
128130
{
@@ -133,7 +135,7 @@ private async Task BuildGameRepoURL(HttpClient client, CancellationToken token)
133135
UpdateStatus();
134136

135137
// Get the asset index properties
136-
string baseURL = string.Format(GameRepoURL!, type.ToString().ToLowerInvariant());
138+
string baseURL = string.Format(BuildAssetBundleURL(GameGateway), type.ToString().ToLowerInvariant());
137139
string assetIndexURL = string.Format(CombineURLFromString(baseURL, "{0}Version.unity3d"),
138140
type == CacheAssetType.Data ? "Data" : "Resource");
139141

@@ -151,25 +153,6 @@ private async Task BuildGameRepoURL(HttpClient client, CancellationToken token)
151153
return returnValue;
152154
}
153155

154-
/*
155-
private void BuildDataPatchConfig(MemoryStream stream, List<CacheAsset> assetIndex)
156-
{
157-
// Reset position
158-
stream.Position = 0;
159-
160-
// Initialize manifest file
161-
CachePatchManifest manifest = new CachePatchManifest(stream, true);
162-
163-
for (int i = 0; i < assetIndex.Count; i++)
164-
{
165-
if (assetIndex[i].DataType == CacheAssetType.Data)
166-
{
167-
CachePatchInfo info = manifest.PatchAsset.Where(x => IsArrayMatch(x.NewHashSHA1, assetIndex[i].CRCArray)).FirstOrDefault();
168-
}
169-
}
170-
}
171-
*/
172-
173156
private IEnumerable<CacheAsset> EnumerateCacheTextAsset(CacheAssetType type, IEnumerable<string> enumerator, string baseUrl)
174157
{
175158
// Set isFirst flag as true if type is Data and
@@ -288,7 +271,7 @@ await Parallel.ForEachAsync(EnumerateCacheTextAsset(type, dataTextAsset.GetStrin
288271
UpdateStatus();
289272

290273
// Check for the URL availability and is not available, then skip.
291-
var urlStatus = await client.GetURLStatusCode(content.ConcatURL, cancellationToken);
274+
UrlStatus urlStatus = await client.GetURLStatusCode(content.ConcatURL, cancellationToken);
292275
LogWriteLine($"The Cache {type} asset: {content.N} " + (urlStatus.IsSuccessStatusCode ? "is" : "is not") + $" available (Status code: {urlStatus.StatusCode})", LogType.Default, true);
293276

294277
if (!urlStatus.IsSuccessStatusCode) return;
@@ -343,21 +326,5 @@ private static bool IsValidRegionFile(string input, string lang)
343326
}
344327

345328
public KianaDispatch GetCurrentGateway() => GameGateway;
346-
347-
public async Task<(List<CacheAsset>, string, string, int)> GetCacheAssetList(HttpClient client, CacheAssetType type, CancellationToken token)
348-
{
349-
// Initialize asset index for the return
350-
List<CacheAsset> returnAsset = [];
351-
352-
// Build _gameRepoURL from loading Dispatcher and Gateway
353-
await BuildGameRepoURL(client, token);
354-
355-
// Fetch the progress
356-
_ = await FetchByType(type, client, returnAsset, token);
357-
358-
// Return the list and base asset bundle repo URL
359-
return (returnAsset, GameGateway!.ExternalAssetUrls!.FirstOrDefault(), BuildAssetBundleURL(GameGateway),
360-
LuckyNumber);
361-
}
362329
}
363330
}

CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
using System.Collections;
2525
using System.Collections.Generic;
2626
using System.Collections.ObjectModel;
27+
using System.Diagnostics.CodeAnalysis;
2728
using System.IO;
2829
using System.IO.Hashing;
2930
using System.Linq;
@@ -1379,6 +1380,31 @@ await downloadClient.DownloadAsync(assetURL,
13791380
}
13801381
}
13811382
}
1383+
1384+
[return: NotNullIfNotNull(nameof(url))]
1385+
internal string? GetHttpsOrHttpOverrideUrl(string? url)
1386+
{
1387+
const string schemeStart = "://";
1388+
1389+
if (string.IsNullOrEmpty(url))
1390+
{
1391+
return url;
1392+
}
1393+
1394+
string scheme = IsForceHttpOverride ? "http://" : "https://";
1395+
if (url.StartsWith(scheme, StringComparison.OrdinalIgnoreCase))
1396+
{
1397+
return url;
1398+
}
1399+
1400+
string urlNoScheme = url;
1401+
int indexOfSchemeMark = url.IndexOf(schemeStart, StringComparison.OrdinalIgnoreCase);
1402+
if (indexOfSchemeMark < 0) return scheme + urlNoScheme;
1403+
1404+
indexOfSchemeMark += schemeStart.Length;
1405+
urlNoScheme = url[indexOfSchemeMark..];
1406+
return scheme + urlNoScheme;
1407+
}
13821408
#endregion
13831409

13841410
#region Stream and Archive Tools

CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Audio.cs

Lines changed: 62 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -56,88 +56,74 @@ internal static async Task<List<FilePropertiesRemote>>
5656

5757
progressibleInstance.UpdateStatus();
5858

59-
bool isUseHttpRepairOverride = progressibleInstance.IsForceHttpOverride;
60-
AudioLanguageType gameLanguageType = GetCurrentGameAudioLanguage(presetConfig);
61-
62-
Exception? lastException = null;
63-
foreach (string baseAsbUrl in gameServerInfo.ExternalAssetUrls)
59+
AudioLanguageType gameLanguageType = GetCurrentGameAudioLanguage(presetConfig);
60+
string baseUrl = progressibleInstance.GetRandomAsbBaseUrl(gameServerInfo);
61+
string baseAudioUrl =
62+
baseUrl.CombineURLFromString($"Audio/Windows/{gameVersion.Major}_{gameVersion.Minor}/{gameServerInfo
63+
.Manifest
64+
.ManifestAudio
65+
.ManifestAudioRevision}");
66+
67+
await using Stream manifestStream = audioFileIdentifier.fileStream ?? throw new NullReferenceException("Senadina Audio Identifier Stream cannot be null!");
68+
KianaAudioManifest manifestData =
69+
new(manifestStream, gameVersion.VersionArrayManifest);
70+
71+
List<FilePropertiesRemote> assetList = [];
72+
await Parallel.ForEachAsync(manifestData.AudioAssets,
73+
new ParallelOptions
74+
{
75+
CancellationToken = token,
76+
MaxDegreeOfParallelism = parallelThread
77+
},
78+
ImplCheckAndAdd);
79+
80+
return assetList;
81+
82+
async ValueTask ImplCheckAndAdd(ManifestAssetInfo audioAsset, CancellationToken innerToken)
6483
{
65-
try
84+
// Eliminate removed audio assets or not matching language.
85+
if ((audioAsset.Language != gameLanguageType &&
86+
audioAsset.Language != AudioLanguageType.Common) ||
87+
ignoredAudioHashset.Contains(audioAsset.PckType))
6688
{
67-
string baseAudioAssetUrl = ((isUseHttpRepairOverride ? "http://" : "https://") + baseAsbUrl)
68-
.CombineURLFromString($"Audio/Windows/{gameVersion.Major}_{gameVersion.Minor}/{gameServerInfo
69-
.Manifest
70-
.ManifestAudio
71-
.ManifestAudioRevision}");
72-
73-
await using Stream manifestStream = audioFileIdentifier.fileStream ?? throw new NullReferenceException("Senadina Audio Identifier Stream cannot be null!");
74-
KianaAudioManifest manifestData =
75-
new(manifestStream, gameVersion.VersionArrayManifest);
76-
77-
List<FilePropertiesRemote> assetList = [];
78-
await Parallel.ForEachAsync(manifestData.AudioAssets,
79-
new ParallelOptions
80-
{
81-
CancellationToken = token,
82-
MaxDegreeOfParallelism = parallelThread
83-
},
84-
ImplCheckAndAdd);
85-
86-
return assetList;
87-
88-
async ValueTask ImplCheckAndAdd(ManifestAssetInfo audioAsset, CancellationToken innerToken)
89-
{
90-
// Eliminate removed audio assets or not matching language.
91-
if ((audioAsset.Language != gameLanguageType &&
92-
audioAsset.Language != AudioLanguageType.Common) ||
93-
ignoredAudioHashset.Contains(audioAsset.PckType))
94-
{
95-
return;
96-
}
97-
98-
if (audioAsset.NeedMap)
99-
{
100-
goto AddAsset; // I love goto. Dun ask me why :>
101-
}
102-
103-
progressibleInstance.Status.ActivityStatus = string.Format(Locale.Lang._GameRepairPage.Status15, audioAsset.Path);
104-
progressibleInstance.Status.IsProgressAllIndetermined = true;
105-
progressibleInstance.Status.IsProgressPerFileIndetermined = true;
106-
progressibleInstance.UpdateStatus();
107-
108-
string assetUrl = baseAudioAssetUrl.CombineURLFromString(audioAsset.Path);
109-
UrlStatus urlStatus = await assetBundleHttpClient.GetURLStatusCode(assetUrl, innerToken);
110-
Logger.LogWriteLine($"The audio asset: {audioAsset.Path} " + (urlStatus.IsSuccessStatusCode ? "is" : "is not") + $" available (Status code: {urlStatus.StatusCode})", LogType.Default, true);
111-
112-
if (!urlStatus.IsSuccessStatusCode)
113-
{
114-
return;
115-
}
116-
117-
AddAsset:
118-
lock (assetList)
119-
{
120-
assetList.Add(new FilePropertiesRemote
121-
{
122-
IsPatchApplicable = audioAsset.IsHasPatch,
123-
AssociatedObject = audioAsset,
124-
AudioPatchInfo = audioAsset.PatchInfo,
125-
CRC = audioAsset.HashString,
126-
FT = FileType.Audio,
127-
RN = baseAudioAssetUrl.CombineURLFromString(audioAsset.Path),
128-
N = audioAsset.Name + ".pck",
129-
S = audioAsset.Size
130-
});
131-
}
132-
}
89+
return;
13390
}
134-
catch (Exception e)
91+
92+
if (audioAsset.NeedMap)
13593
{
136-
lastException = e;
94+
goto AddAsset; // I love goto. Dun ask me why :>
13795
}
138-
}
13996

140-
throw lastException ?? new HttpRequestException("No Asset bundle URLs were reachable");
97+
progressibleInstance.Status.ActivityStatus = string.Format(Locale.Current.Lang?._GameRepairPage?.Status15 ?? "", audioAsset.Path);
98+
progressibleInstance.Status.IsProgressAllIndetermined = true;
99+
progressibleInstance.Status.IsProgressPerFileIndetermined = true;
100+
progressibleInstance.UpdateStatus();
101+
102+
string assetUrl = baseAudioUrl.CombineURLFromString(audioAsset.Path);
103+
UrlStatus urlStatus = await assetBundleHttpClient.GetURLStatusCode(assetUrl, innerToken);
104+
Logger.LogWriteLine($"The audio asset: {audioAsset.Path} " + (urlStatus.IsSuccessStatusCode ? "is" : "is not") + $" available (Status code: {urlStatus.StatusCode})", LogType.Default, true);
105+
106+
if (!urlStatus.IsSuccessStatusCode)
107+
{
108+
throw new HttpRequestException("No Asset bundle URLs were reachable");
109+
}
110+
111+
AddAsset:
112+
lock (assetList)
113+
{
114+
assetList.Add(new FilePropertiesRemote
115+
{
116+
IsPatchApplicable = audioAsset.IsHasPatch,
117+
AssociatedObject = audioAsset,
118+
AudioPatchInfo = audioAsset.PatchInfo,
119+
CRC = audioAsset.HashString,
120+
FT = FileType.Audio,
121+
RN = baseAudioUrl.CombineURLFromString(audioAsset.Path),
122+
N = audioAsset.Name + ".pck",
123+
S = audioAsset.Size
124+
});
125+
}
126+
}
141127
}
142128

143129
internal static bool GetAudioPatchUrlProperty(

CollapseLauncher/Classes/RepairManagement/HonkaiV2/HonkaiRepairV2.AsbExt.Block.cs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ internal static async Task<List<FilePropertiesRemote>>
5858
progressibleInstance.Status.IsIncludePerFileIndicator = false;
5959
progressibleInstance.UpdateStatus();
6060

61-
bool isUseHttpRepairOverride = progressibleInstance.IsForceHttpOverride;
62-
6361
await using Stream xmfMetaCurrentFileStream = senadinaResults.XmfMeta?.fileStream ?? throw new NullReferenceException("Senadina BlockMeta Identifier Stream cannot be null!");
6462
await using Stream xmfPatchCurrentFileStream = senadinaResults.XmfPatch?.fileStream ?? throw new NullReferenceException("Senadina BlockPatch Identifier Stream cannot be null!");
6563

@@ -106,15 +104,18 @@ internal static async Task<List<FilePropertiesRemote>>
106104
ref BlockPatchInfo patchInfoRef =
107105
ref CollectionsMarshal.GetValueRefOrNullRef(patchInfos, xmfBlock.BlockName);
108106

107+
string asbBaseUrl = progressibleInstance.GetRandomAsbBaseUrl(gameServerInfo);
108+
string assetUrl =
109+
asbBaseUrl.CombineURLFromString($"StreamingAsb/{baseUrlVersionPrefix}/pc/HD/asb", xmfBlock.BlockName);
110+
109111
FilePropertiesRemote asset = new()
110112
{
111113
AssociatedObject = xmfBlock,
112-
CRC = Path.GetFileNameWithoutExtension(xmfBlock.BlockName),
113-
FT = FileType.Block,
114-
RN = GetRandomBaseUrl(gameServerInfo)
115-
.CombineURLFromString($"StreamingAsb/{baseUrlVersionPrefix}/pc/HD/asb", xmfBlock.BlockName),
116-
N = xmfBlock.BlockName,
117-
S = xmfBlock.Size
114+
CRC = Path.GetFileNameWithoutExtension(xmfBlock.BlockName),
115+
FT = FileType.Block,
116+
RN = assetUrl,
117+
N = xmfBlock.BlockName,
118+
S = xmfBlock.Size
118119
};
119120
assetList.Add(asset);
120121

@@ -128,12 +129,20 @@ internal static async Task<List<FilePropertiesRemote>>
128129
}
129130

130131
return assetList;
132+
}
131133

132-
string GetRandomBaseUrl(KianaDispatch kianaDispatch)
133-
{
134-
string selectedUrl = kianaDispatch.ExternalAssetUrls.RandomSelectSingle();
135-
return isUseHttpRepairOverride ? "http://" : "https://" + selectedUrl;
136-
}
134+
internal static string GetRandomAsbBaseUrl<T>(this ProgressBase<T> instance, KianaDispatch kianaDispatch)
135+
where T : IAssetIndexSummary
136+
{
137+
string selectedUrl = kianaDispatch.ExternalAssetUrls.RandomSelectSingle();
138+
return instance.GetHttpsOrHttpOverrideUrl(selectedUrl);
139+
}
140+
141+
internal static string GetRandomCacheBaseUrl<T>(this ProgressBase<T> instance, KianaDispatch kianaDispatch)
142+
where T : IAssetIndexSummary
143+
{
144+
string selectedUrl = kianaDispatch.AssetBundleUrls.RandomSelectSingle();
145+
return instance.GetHttpsOrHttpOverrideUrl(selectedUrl);
137146
}
138147

139148
internal static bool GetBlockPatchUrlProperty(

0 commit comments

Comments
 (0)