Skip to content

Commit e6ade54

Browse files
authored
[Re-push][Emergency Hotfix] Stable 1.82.36 (#816)
Due to a reported recent ban for using this feature, we are disabling it for now by force. While the ban seems to be only applicable for co-op, we are not taking the report lightly and are disabling this feature until we are sure that it is safe to use. If you have similar issue with this feature and/or other feature that causes something to your account, please contact us immediately. If you are from HoYo, thank you, for doing this to your players, I'm sure that game cloud subscription is worth it. # What's changed? - **[Imp]** Update Discord RPC submodule, by @bagusnl - **[New]** Update backend install and repair systems for Honkai: Impact 3rd Sophon changes: - Add fetcher for Block files. This implementation should now accepts patching for block files which are older than current version (e.g. 8.4 -> 8.5) - Re-implement Generic file parsing and updating - Process Audio and Block fetching in parallel simulatneously - Make `KianaDispatch` and `SenadinaFileResult` fetch asynchronously - Improve CDN caching mechanism - Reimplement Audio & Video file parsing and updating - Add mechanism to fix basic asset - `ProgressPerFile` counters are now containing how many bytes of downloadable data instead of the byte size of each of progressing files - Add additional speed counter on `ProgressAll` status to the UI - Simplify `base.ProgressBase` `PopRepairAssetEntry()` - Refactor Unused files checking mechanism - `HonkaiRepairV2` now uses its own new `UpdateProgressCounter()` method to update the `ProgressAll` or `ProgressPerFile` counters - Add matching field exclude mechanism - Use `HashSet` for checking ignored assets - Implement repair for Block/BlockUpdate and Audio/AudioUpdate kind - **[New]** Keep ScreenShot folder post-uninstall for Genshin Impact, by @Cryotechnic - **[Imp]** Disable Mobile Mode in all available games. ### Templates <details> <summary>Changelog Prefixes</summary> ``` **[New]** **[Imp]** **[Fix]** **[Loc]** **[Doc]** ``` </details>
2 parents 28a4058 + 5336047 commit e6ade54

File tree

64 files changed

+4522
-938
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+4522
-938
lines changed

CollapseLauncher/Classes/CachesManagement/Honkai/Check.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,12 @@ private void CheckUnusedAssets(List<CacheAsset> assetIndex, List<CacheAsset> ret
9494
// Add asset to the returnAsset
9595
CacheAsset asset = new CacheAsset
9696
{
97-
BasePath = Path.GetDirectoryName(fileInfo.FullName),
98-
N = Path.GetFileName(fileInfo.FullName),
99-
DataType = CacheAssetType.Unused,
100-
CS = fileInfo.Length,
101-
CRC = null,
102-
Status = CacheAssetStatus.Unused,
97+
BasePath = Path.GetDirectoryName(fileInfo.FullName),
98+
N = Path.GetFileName(fileInfo.FullName),
99+
DataType = CacheAssetType.Unused,
100+
CS = fileInfo.Length,
101+
CRC = null,
102+
Status = CacheAssetStatus.Unused,
103103
IsUseLocalPath = true
104104
};
105105
returnAsset!.Add(asset);
@@ -193,4 +193,4 @@ private void AddGenericCheckAsset(CacheAsset asset, CacheAssetStatus assetStatus
193193
);
194194
}
195195
}
196-
}
196+
}

CollapseLauncher/Classes/CachesManagement/Honkai/Fetch.cs

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,16 @@ private async Task<List<CacheAsset>> Fetch(CancellationToken token)
3838
.SetAllowedDecompression(DecompressionMethods.None)
3939
.Create();
4040

41-
// Use a new DownloadClient for fetching
42-
DownloadClient downloadClient = DownloadClient.CreateInstance(httpClientNew);
43-
4441
// Build _gameRepoURL from loading Dispatcher and Gateway
45-
await BuildGameRepoURL(downloadClient.GetHttpClient(), token);
42+
await BuildGameRepoURL(httpClientNew, token);
4643

4744
// Iterate type and do fetch
4845
await Parallel.ForEachAsync(
4946
Enum.GetValues<CacheAssetType>(),
5047
new ParallelOptions
5148
{
5249
MaxDegreeOfParallelism = ThreadCount,
53-
CancellationToken = token
50+
CancellationToken = token
5451
},
5552
async (type, ctx) =>
5653
{
@@ -62,16 +59,16 @@ await Parallel.ForEachAsync(
6259
{
6360
// uint = Count of the assets available
6461
// long = Total size of the assets available
65-
(int, long) count = await FetchByType(type, downloadClient, returnAsset, ctx);
62+
(int, long) count = await FetchByType(type, httpClientNew, returnAsset, ctx);
6663

6764
// Write a log about the metadata
68-
LogWriteLine($"Cache Metadata [T: {type}]:", LogType.Default, true);
69-
LogWriteLine($" Cache Count = {count.Item1}", LogType.NoTag, true);
70-
LogWriteLine($" Cache Size = {SummarizeSizeSimple(count.Item2)}", LogType.NoTag, true);
65+
LogWriteLine($"Cache Metadata [T: {type}]:", LogType.Default, true);
66+
LogWriteLine($" Cache Count = {count.Item1}", LogType.NoTag, true);
67+
LogWriteLine($" Cache Size = {SummarizeSizeSimple(count.Item2)}", LogType.NoTag, true);
7168

7269
// Increment the Total Size and Count
7370
Interlocked.Add(ref ProgressAllCountTotal, count.Item1);
74-
Interlocked.Add(ref ProgressAllSizeTotal, count.Item2);
71+
Interlocked.Add(ref ProgressAllSizeTotal, count.Item2);
7572
}
7673
break;
7774
default:
@@ -83,7 +80,7 @@ await Parallel.ForEachAsync(
8380
return returnAsset;
8481
}
8582

86-
private async Task BuildGameRepoURL(HttpClient downloadClient, CancellationToken token)
83+
private async Task BuildGameRepoURL(HttpClient client, CancellationToken token)
8784
{
8885
KianaDispatch dispatch = null;
8986
Exception lastException = null;
@@ -101,10 +98,13 @@ private async Task BuildGameRepoURL(HttpClient downloadClient, CancellationToken
10198
string key = GameVersionManager.GamePreset.DispatcherKey;
10299

103100
// Try assign dispatcher
104-
dispatch = await KianaDispatch.GetDispatch(downloadClient, baseURL,
101+
dispatch = await KianaDispatch.GetDispatch(client,
102+
baseURL,
105103
GameVersionManager.GamePreset.GameDispatchURLTemplate,
106104
GameVersionManager.GamePreset.GameDispatchChannelName,
107-
key, GameVersion.VersionArray, token);
105+
key,
106+
GameVersion.VersionArray,
107+
token);
108108
lastException = null;
109109
break;
110110
}
@@ -119,13 +119,13 @@ private async Task BuildGameRepoURL(HttpClient downloadClient, CancellationToken
119119

120120
// Get gatewayURl and fetch the gateway
121121
GameGateway =
122-
await KianaDispatch.GetGameserver(downloadClient, dispatch!, GameVersionManager.GamePreset.GameGatewayDefault!, token);
122+
await KianaDispatch.GetGameserver(client, dispatch!, GameVersionManager.GamePreset.GameGatewayDefault!, token);
123123
GameRepoURL = BuildAssetBundleURL(GameGateway);
124124
}
125125

126126
private static string BuildAssetBundleURL(KianaDispatch gateway) => CombineURLFromString(gateway!.AssetBundleUrls![0], "/{0}/editor_compressed/");
127127

128-
private async Task<(int, long)> FetchByType(CacheAssetType type, DownloadClient downloadClient, List<CacheAsset> assetIndex, CancellationToken token)
128+
private async Task<(int, long)> FetchByType(CacheAssetType type, HttpClient client, List<CacheAsset> assetIndex, CancellationToken token)
129129
{
130130
// Set total activity string as "Fetching Caches Type: <type>"
131131
Status.ActivityStatus = string.Format(Lang!._CachesPage!.CachesStatusFetchingType!, type);
@@ -143,9 +143,7 @@ private async Task BuildGameRepoURL(HttpClient downloadClient, CancellationToken
143143
#endif
144144

145145
// Get a direct HTTP Stream
146-
await using HttpResponseInputStream remoteStream = await HttpResponseInputStream.CreateStreamAsync(
147-
downloadClient.GetHttpClient(), assetIndexURL, null, null, null, null, null, token);
148-
146+
await using Stream remoteStream = (await client.TryGetCachedStreamFrom(assetIndexURL, token: token)).Stream;
149147
await using XORStream stream = new XORStream(remoteStream);
150148

151149
// Build the asset index and return the count and size of each type
@@ -233,7 +231,7 @@ private IEnumerable<CacheAsset> EnumerateCacheTextAsset(CacheAssetType type, IEn
233231
}
234232

235233
// Set base URL and Path and add it to asset index
236-
content.BaseURL = baseUrl;
234+
content.BaseURL = baseUrl;
237235
content.DataType = type;
238236
content.BasePath = GetAssetBasePathByType(type);
239237

@@ -249,7 +247,7 @@ private async ValueTask<ValueTuple<int, long>> BuildAssetIndex(CacheAssetType ty
249247

250248
// Set isFirst flag as true if type is Data and
251249
// also convert type as lowered string.
252-
250+
253251
// Unused as of Aug 4th 2024, bonk @bagusnl if not true
254252
// bool isFirst = type == CacheAssetType.Data;
255253
// bool isNeedReadLuckyNumber = type == CacheAssetType.Data;
@@ -347,17 +345,16 @@ private static bool IsValidRegionFile(string input, string lang)
347345

348346
public KianaDispatch GetCurrentGateway() => GameGateway;
349347

350-
public async Task<(List<CacheAsset>, string, string, int)> GetCacheAssetList(
351-
DownloadClient downloadClient, CacheAssetType type, CancellationToken token)
348+
public async Task<(List<CacheAsset>, string, string, int)> GetCacheAssetList(HttpClient client, CacheAssetType type, CancellationToken token)
352349
{
353350
// Initialize asset index for the return
354351
List<CacheAsset> returnAsset = [];
355352

356353
// Build _gameRepoURL from loading Dispatcher and Gateway
357-
await BuildGameRepoURL(downloadClient.GetHttpClient(), token);
354+
await BuildGameRepoURL(client, token);
358355

359356
// Fetch the progress
360-
_ = await FetchByType(type, downloadClient, returnAsset, token);
357+
_ = await FetchByType(type, client, returnAsset, token);
361358

362359
// Return the list and base asset bundle repo URL
363360
return (returnAsset, GameGateway!.ExternalAssetUrls!.FirstOrDefault(), BuildAssetBundleURL(GameGateway),

CollapseLauncher/Classes/CachesManagement/Honkai/HonkaiCache.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ internal partial class HonkaiCache : ProgressBase<CacheAsset>, ICache, ICacheBas
1414
{
1515
#region Properties
1616

17-
private const string CacheRegionalCheckName = "sprite";
18-
private string GameLang { get; }
19-
private byte[] GameSalt { get; set; }
20-
private KianaDispatch GameGateway { get; set; }
21-
private List<CacheAsset> UpdateAssetIndex { get; set; }
22-
private int LuckyNumber { get; set; }
17+
private const string CacheRegionalCheckName = "sprite";
18+
private string GameLang { get; }
19+
private byte[] GameSalt { get; set; }
20+
private KianaDispatch GameGateway { get; set; }
21+
private List<CacheAsset> UpdateAssetIndex { get; set; }
22+
private int LuckyNumber { get; set; }
2323
#endregion
2424

2525
public HonkaiCache(UIElement parentUI, IGameVersion gameVersionManager)
@@ -112,4 +112,4 @@ public void Dispose()
112112
GC.SuppressFinalize(this);
113113
}
114114
}
115-
}
115+
}

CollapseLauncher/Classes/CachesManagement/Honkai/Update.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using CollapseLauncher.Helper.StreamUtility;
21
using CollapseLauncher.Helper;
2+
using CollapseLauncher.Helper.StreamUtility;
33
using CollapseLauncher.Interfaces;
44
using Hi3Helper;
55
using Hi3Helper.Http;
@@ -24,7 +24,7 @@ internal partial class HonkaiCache
2424
private async Task<bool> Update(List<CacheAsset> updateAssetIndex, List<CacheAsset> assetIndex, CancellationToken token)
2525
{
2626
// Initialize new proxy-aware HttpClient
27-
using HttpClient client = new HttpClientBuilder<SocketsHttpHandler>()
27+
using HttpClient client = new HttpClientBuilder()
2828
.UseLauncherConfig(DownloadThreadWithReservedCount)
2929
.SetUserAgent(UserAgent)
3030
.SetAllowedDecompression(DecompressionMethods.None)
@@ -39,7 +39,7 @@ private async Task<bool> Update(List<CacheAsset> updateAssetIndex, List<CacheAss
3939
UpdateStatus();
4040

4141
// Iterate the asset index and do update operation
42-
ObservableCollection<IAssetProperty> assetProperty = [.. AssetEntry];
42+
ObservableCollection<IAssetProperty> assetProperty = [.. AssetEntry];
4343

4444
ConcurrentDictionary<(CacheAsset, IAssetProperty), byte> runningTask = new();
4545
if (IsBurstDownloadEnabled)
@@ -105,7 +105,7 @@ private void UpdateCacheVerifyList(List<CacheAsset> assetIndex)
105105
string listFile = Path.Combine(GamePath!, "Data", "Verify.txt");
106106

107107
// Initialize listFile File Stream
108-
using FileStream fs = new FileStream(listFile, FileMode.Create, FileAccess.Write);
108+
using FileStream fs = new FileStream(listFile, FileMode.Create, FileAccess.Write);
109109
using StreamWriter sw = new StreamWriter(fs);
110110
// Iterate asset index and generate the path for the cache path
111111
for (var index = 0; index < assetIndex!.Count; index++)
@@ -114,7 +114,7 @@ private void UpdateCacheVerifyList(List<CacheAsset> assetIndex)
114114
// Yes, the path is written in this way. Idk why miHoYo did this...
115115
// Update 6.8: They finally notices that they use "//" instead of "/"
116116
string basePath = GetAssetBasePathByType(asset!.DataType)!.Replace('\\', '/');
117-
string path = basePath + "/" + asset.ConcatN;
117+
string path = basePath + "/" + asset.ConcatN;
118118
sw.WriteLine(path);
119119
}
120120
}
@@ -141,19 +141,19 @@ private async Task UpdateCacheAsset((CacheAsset AssetIndex, IAssetProperty Asset
141141
// Other than unused file, do this action
142142
else
143143
{
144-
#if DEBUG
144+
#if DEBUG
145145
LogWriteLine($"Downloading cache [T: {asset.AssetIndex.DataType}]: {asset.AssetIndex.N} at URL: {asset.AssetIndex.ConcatURL}", LogType.Debug, true);
146-
#endif
146+
#endif
147147

148148
await RunDownloadTask(asset.AssetIndex.CS, fileInfo, asset.AssetIndex.ConcatURL, downloadClient, downloadProgress, token);
149149

150-
#if !DEBUG
150+
#if !DEBUG
151151
LogWriteLine($"Downloaded cache [T: {asset.AssetIndex.DataType}]: {asset.AssetIndex.N}", LogType.Default, true);
152-
#endif
152+
#endif
153153
}
154154

155155
// Remove Asset Entry display
156156
PopRepairAssetEntry(asset.AssetProperty);
157157
}
158158
}
159-
}
159+
}

CollapseLauncher/Classes/Extension/TaskExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,17 @@ internal static async Task<TResult?>
8787

8888
throw new TimeoutException("The operation has timed out!");
8989
}
90+
91+
internal static async Task GetResultFromAction<T>(this Task<T> task, Action<T> getResultAction)
92+
{
93+
T result = await task;
94+
getResultAction(result);
95+
}
96+
97+
internal static async Task GetResultFromAction<T>(this Task<T> task, Func<T, Task> getResultAction)
98+
{
99+
T result = await task;
100+
await getResultAction(result);
101+
}
90102
}
91103
}

CollapseLauncher/Classes/GameManagement/GameSettings/Honkai/RegistryClass/PersonalAudioSetting.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace CollapseLauncher.GameSettings.Honkai
2222
internal class PersonalAudioSetting : IGameSettingsValue<PersonalAudioSetting>
2323
{
2424
#region Fields
25-
private const string ValueName = "GENERAL_DATA_V2_PersonalAudioSetting_h3869048096";
25+
internal const string ValueName = "GENERAL_DATA_V2_PersonalAudioSetting_h3869048096";
2626
private readonly PersonalAudioSettingVolume _volumeValue = PersonalAudioSettingVolume.Load();
2727

2828
#endregion

CollapseLauncher/Classes/GamePresetProperty.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,12 @@ internal GamePresetProperty(UIElement uiElementParent, RegionResourceProp apiRes
4949
switch (gamePreset.GameType)
5050
{
5151
case GameNameType.Honkai:
52-
GameVersion = new GameTypeHonkaiVersion(ApiResourceProp, gameName, gameRegion);
52+
GameVersion = new GameTypeHonkaiVersion(apiResourceProp, gameName, gameRegion);
5353
GameSettings = new HonkaiSettings(GameVersion);
54-
GameCache = new HonkaiCache(uiElementParent, GameVersion);
55-
GameRepair = new HonkaiRepair(uiElementParent, GameVersion, GameCache, GameSettings);
56-
GameInstall = new HonkaiInstall(uiElementParent, GameVersion, GameCache);
54+
GameCache = new HonkaiCache(uiElementParent, GameVersion);
55+
// GameRepair = new HonkaiRepair(uiElementParent, GameVersion, GameCache, GameSettings);
56+
GameRepair = new HonkaiRepairV2(uiElementParent, GameVersion);
57+
GameInstall = new HonkaiInstall(uiElementParent, GameVersion, GameCache);
5758
break;
5859
case GameNameType.StarRail:
5960
GameVersion = new GameTypeStarRailVersion(ApiResourceProp, gameName, gameRegion);

CollapseLauncher/Classes/Helper/FileUtility.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,5 +125,23 @@ public static int GetFileStreamBufferSize(this long fileSize)
125125
<= 100 << 20 => 512 << 10,
126126
_ => 1 << 20
127127
};
128+
129+
public static int GetFileStreamBufferSize(this int fileSize) => GetFileStreamBufferSize((long)fileSize);
130+
131+
public static int GetFileStreamBufferSize(this ulong fileSize)
132+
=> fileSize switch
133+
{
134+
// 128 KiB
135+
<= 128 << 10 => 4 << 10,
136+
// 1 MiB
137+
<= 1 << 20 => 64 << 10,
138+
// 32 MiB
139+
<= 32 << 20 => 128 << 10,
140+
// 100 MiB
141+
<= 100 << 20 => 512 << 10,
142+
_ => 1 << 20
143+
};
144+
145+
public static int GetFileStreamBufferSize(this uint fileSize) => GetFileStreamBufferSize((ulong)fileSize);
128146
}
129147
}

CollapseLauncher/Classes/Helper/HttpClientBuilder.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ private static string GetDefaultUserAgent()
5454
+ $"WinAppSDK/{LauncherConfig.WindowsAppSdkVersion}";
5555
}
5656

57+
public static HttpClient CreateDefaultClient(int maxConnection = 32, bool isSkipDnsInit = false)
58+
=> new HttpClientBuilder()
59+
.UseLauncherConfig()
60+
.Create();
61+
5762
public HttpClientBuilder<THandler> UseExternalProxy(string host, string? username = null, SecureString? password = null)
5863
{
5964
// Try to create the Uri

CollapseLauncher/Classes/Helper/JsonConverter/ServeV3Converter.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,51 @@ public override void Write(
7070
throw new JsonException("Serializing is not supported!");
7171
}
7272
}
73+
74+
public class ServeV3StringArrayConverter : JsonConverter<string[]>
75+
{
76+
public override bool CanConvert(Type type) => true;
77+
78+
public override string[] Read(
79+
ref Utf8JsonReader reader,
80+
Type typeToConvert,
81+
JsonSerializerOptions options)
82+
{
83+
// Initialize and check if the token is a start of an array
84+
List<string> returnValue = [];
85+
if (reader.TokenType != JsonTokenType.StartArray) // Throw if it's not
86+
throw new JsonException("The start token of the JSON field is not a start of an array!");
87+
88+
// Read the next value or token
89+
reader.Read();
90+
91+
// If the token is a string, initialize the list
92+
if (reader.TokenType == JsonTokenType.String)
93+
returnValue = [];
94+
95+
// Loop and read the value if the token is currently a string
96+
while (reader.TokenType == JsonTokenType.String)
97+
{
98+
// Try retrieve the data if it's a raw string or a ServeV3 string
99+
string returnString = Extension.GetServeV3String(reader);
100+
returnValue.Add(returnString); // Add the string
101+
reader.Read(); // Read the next token
102+
}
103+
104+
// If the token is not an end of an array, then throw
105+
if (reader.TokenType != JsonTokenType.EndArray)
106+
throw new JsonException("The end token of the JSON field is not an end of an array!");
107+
108+
// Return the list
109+
return returnValue.ToArray();
110+
}
111+
112+
public override void Write(
113+
Utf8JsonWriter writer,
114+
string[]? baseType,
115+
JsonSerializerOptions options)
116+
{
117+
throw new JsonException("Serializing is not supported!");
118+
}
119+
}
73120
}

0 commit comments

Comments
 (0)