Skip to content

Commit 17bc493

Browse files
committed
[ZZZ] Add ability on Game Install/Update to skip excluded assets
1 parent fdbb2b6 commit 17bc493

File tree

3 files changed

+148
-1
lines changed

3 files changed

+148
-1
lines changed

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ await GetAlterSophonPatchAssets(httpClient,
117117
downloadSpeedLimiter,
118118
Token.Token);
119119

120+
// Filter asset list based on
121+
await FilterSophonPatchAssetList(patchAssets.AssetList, Token.Token);
122+
120123
// Start the patch pipeline
121124
await StartAlterSophonPatch(httpClient,
122125
isPreloadMode,
@@ -130,6 +133,12 @@ await StartAlterSophonPatch(httpClient,
130133
return true;
131134
}
132135

136+
protected virtual Task FilterSophonPatchAssetList(List<SophonPatchAsset> itemList, CancellationToken token)
137+
{
138+
// NOP
139+
return Task.CompletedTask;
140+
}
141+
133142
protected virtual async Task ConfirmAdditionalPatchDataPackageFiles(SophonChunkManifestInfoPair patchManifest,
134143
List<string> matchingFieldsList,
135144
CancellationToken token)
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
using Hi3Helper.Sophon;
2+
using Hi3Helper.Sophon.Infos;
3+
using System;
4+
using System.Buffers;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Runtime.CompilerServices;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
// ReSharper disable CheckNamespace
11+
12+
#nullable enable
13+
namespace CollapseLauncher.InstallManager.Zenless
14+
{
15+
internal partial class ZenlessInstall
16+
{
17+
// ReSharper disable once StringLiteralTypo
18+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<SophonChunksInfo>k__BackingField")]
19+
private static extern ref SophonChunksInfo GetChunkAssetChunksInfo(SophonAsset element);
20+
21+
// ReSharper disable once StringLiteralTypo
22+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<SophonChunksInfoAlt>k__BackingField")]
23+
private static extern ref SophonChunksInfo GetChunkAssetChunksInfoAlt(SophonAsset element);
24+
25+
protected override async Task FilterSophonPatchAssetList(List<SophonPatchAsset> itemList, CancellationToken token)
26+
{
27+
const StringSplitOptions splitOptions = StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries;
28+
29+
string gameExecDataName =
30+
Path.GetFileNameWithoutExtension(GameVersionManager.GamePreset.GameExecutableName) ?? "ZenlessZoneZero";
31+
string gameExecDataPath = $"{gameExecDataName}_Data";
32+
string gamePersistentDataPath = Path.Combine(GamePath, gameExecDataPath, "Persistent");
33+
string gameExceptMatchFieldFile = Path.Combine(gamePersistentDataPath, "KDelResource");
34+
35+
if (!File.Exists(gameExceptMatchFieldFile))
36+
{
37+
return;
38+
}
39+
40+
string exceptMatchFieldContent = await File.ReadAllTextAsync(gameExceptMatchFieldFile, token);
41+
HashSet<string> exceptMatchFieldHashSet = CreateHashSet();
42+
43+
if (exceptMatchFieldHashSet.Count == 0)
44+
{
45+
return;
46+
}
47+
48+
FilterAsset();
49+
50+
return;
51+
52+
void FilterAsset()
53+
{
54+
const string separators = "/\\";
55+
scoped Span<Range> urlPathRanges = stackalloc Range[32];
56+
57+
HashSet<string>.AlternateLookup<ReadOnlySpan<char>> alternateLookup =
58+
exceptMatchFieldHashSet.GetAlternateLookup<ReadOnlySpan<char>>();
59+
60+
List<SophonPatchAsset> filteredList = [];
61+
foreach (SophonPatchAsset asset in itemList)
62+
{
63+
token.ThrowIfCancellationRequested();
64+
ref SophonChunksInfo chunkInfo = ref asset.MainAssetInfo == null
65+
? ref Unsafe.NullRef<SophonChunksInfo>()
66+
: ref GetChunkAssetChunksInfo(asset.MainAssetInfo);
67+
68+
if (asset.MainAssetInfo != null && Unsafe.IsNullRef(ref chunkInfo))
69+
{
70+
chunkInfo = ref GetChunkAssetChunksInfoAlt(asset.MainAssetInfo);
71+
}
72+
73+
if (Unsafe.IsNullRef(ref chunkInfo))
74+
{
75+
filteredList.Add(asset);
76+
continue;
77+
}
78+
79+
ReadOnlySpan<char> manifestUrl = chunkInfo.ChunksBaseUrl;
80+
int rangeLen = manifestUrl.SplitAny(urlPathRanges, separators, splitOptions);
81+
82+
if (rangeLen <= 0)
83+
{
84+
continue;
85+
}
86+
87+
ReadOnlySpan<char> manifestStr = manifestUrl[urlPathRanges[rangeLen - 1]];
88+
if (alternateLookup.Contains(manifestStr))
89+
{
90+
continue;
91+
}
92+
93+
filteredList.Add(asset);
94+
}
95+
96+
if (filteredList.Count == 0)
97+
{
98+
return;
99+
}
100+
101+
itemList.Clear();
102+
itemList.AddRange(filteredList);
103+
}
104+
105+
HashSet<string> CreateHashSet()
106+
{
107+
const string lineFeedSeparators = "\r\n";
108+
HashSet<string> hashSetReturn = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
109+
scoped Span<Range> contentLineRange = stackalloc Range[2];
110+
111+
ReadOnlySpan<char> contentSpan = exceptMatchFieldContent.AsSpan();
112+
int contentLineLen = contentSpan.SplitAny(contentLineRange, lineFeedSeparators, splitOptions);
113+
114+
if (contentLineLen == 0)
115+
{
116+
return hashSetReturn;
117+
}
118+
119+
contentSpan = contentSpan[contentLineRange[0]];
120+
const string separatorsChars = "|;,$#@+ ";
121+
SearchValues<char> separators = SearchValues.Create(separatorsChars);
122+
123+
foreach (Range contentMatchRange in contentSpan.SplitAny(separators))
124+
{
125+
if (contentMatchRange.End.Value - contentMatchRange.Start.Value <= 0)
126+
{
127+
continue;
128+
}
129+
130+
ReadOnlySpan<char> contentMatch = contentSpan[contentMatchRange].Trim(separatorsChars);
131+
hashSetReturn.Add(contentMatch.ToString());
132+
}
133+
134+
return hashSetReturn;
135+
}
136+
}
137+
}
138+
}

CollapseLauncher/Classes/InstallManagement/Zenless/ZenlessInstall.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#nullable enable
2222
namespace CollapseLauncher.InstallManager.Zenless
2323
{
24-
internal sealed class ZenlessInstall : InstallManagerBase
24+
internal sealed partial class ZenlessInstall : InstallManagerBase
2525
{
2626
#region Private Properties
2727
private ZenlessSettings? ZenlessSettings { get; }

0 commit comments

Comments
 (0)