Skip to content

Commit 541ece3

Browse files
committed
[Genshin Repair] Rewrite File Check Pipeline
The code now should follow exactly how the game behaves with some enforcement to StreamingAssets files if some duplicates are found. But instead of overwriting it, it will store the data to Persistent folder
1 parent 3af1e3f commit 541ece3

File tree

8 files changed

+614
-594
lines changed

8 files changed

+614
-594
lines changed
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
using Hi3Helper.Http;
2+
using System;
3+
using System.Buffers;
4+
using System.IO;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
8+
#nullable enable
9+
namespace CollapseLauncher.Helper.StreamUtility
10+
{
11+
internal sealed class CopyToStream(
12+
Stream sourceStream,
13+
Stream destinationStream,
14+
DownloadProgressDelegate? readDelegate = null,
15+
bool isDisposeStream = false)
16+
: Stream
17+
{
18+
private readonly DownloadProgress _readProperty = new()
19+
{
20+
BytesDownloaded = 0,
21+
BytesTotal = sourceStream.Length
22+
};
23+
24+
public override bool CanRead => sourceStream.CanRead;
25+
26+
public override bool CanSeek => sourceStream.CanSeek;
27+
28+
public override bool CanWrite => sourceStream.CanWrite;
29+
30+
public override long Length => sourceStream.Length;
31+
32+
public override long Position { get => sourceStream.Position; set => Seek(value, SeekOrigin.Begin); }
33+
34+
~CopyToStream() => Dispose(false);
35+
36+
public override int Read(byte[] buffer, int offset, int count)
37+
=> Read(buffer.AsSpan(offset, count));
38+
39+
public override int Read(Span<byte> buffer)
40+
{
41+
int read = sourceStream.Read(buffer);
42+
if (read <= 0)
43+
{
44+
return read;
45+
}
46+
47+
destinationStream.Write(buffer[..read]);
48+
Interlocked.Add(ref _readProperty.BytesDownloaded, read);
49+
readDelegate?.Invoke(read, _readProperty);
50+
return read;
51+
}
52+
53+
public override int ReadByte()
54+
{
55+
int readByte = sourceStream.ReadByte();
56+
destinationStream.WriteByte((byte)readByte);
57+
58+
return readByte;
59+
}
60+
61+
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
62+
=> await ReadAsync(buffer.AsMemory(offset, count), cancellationToken).ConfigureAwait(false);
63+
64+
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
65+
{
66+
int read = await sourceStream.ReadAsync(buffer, cancellationToken);
67+
if (read <= 0)
68+
{
69+
return read;
70+
}
71+
72+
await destinationStream.WriteAsync(buffer[..read], cancellationToken);
73+
Interlocked.Add(ref _readProperty.BytesDownloaded, read);
74+
readDelegate?.Invoke(read, _readProperty);
75+
return read;
76+
}
77+
78+
public override void Write(byte[] buffer, int offset, int count)
79+
=> Write(buffer.AsSpan(offset, count));
80+
81+
public override void Write(ReadOnlySpan<byte> buffer)
82+
{
83+
sourceStream.Write(buffer);
84+
destinationStream.Write(buffer);
85+
}
86+
87+
public override void WriteByte(byte value)
88+
{
89+
sourceStream.WriteByte(value);
90+
destinationStream.WriteByte(value);
91+
}
92+
93+
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
94+
=> await WriteAsync(buffer.AsMemory(offset, count), cancellationToken).ConfigureAwait(false);
95+
96+
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
97+
{
98+
await sourceStream.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);
99+
await destinationStream.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);
100+
}
101+
102+
public override long Seek(long offset, SeekOrigin origin)
103+
{
104+
long seek = sourceStream.Seek(offset, origin);
105+
_ = destinationStream.Seek(offset, origin);
106+
107+
return seek;
108+
}
109+
110+
public override void SetLength(long value)
111+
{
112+
sourceStream.SetLength(value);
113+
destinationStream.SetLength(value);
114+
}
115+
116+
public override async Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
117+
{
118+
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
119+
120+
try
121+
{
122+
int read;
123+
while ((read = await sourceStream.ReadAsync(buffer, cancellationToken)) > 0)
124+
{
125+
await destination.WriteAsync(buffer.AsMemory(0, read), cancellationToken);
126+
await destinationStream.WriteAsync(buffer.AsMemory(0, read), cancellationToken);
127+
}
128+
}
129+
finally
130+
{
131+
ArrayPool<byte>.Shared.Return(buffer);
132+
}
133+
}
134+
135+
public override void CopyTo(Stream destination, int bufferSize)
136+
{
137+
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
138+
139+
try
140+
{
141+
int read;
142+
while ((read = sourceStream.Read(buffer)) > 0)
143+
{
144+
destination.Write(buffer, 0, read);
145+
destinationStream.Write(buffer, 0, read);
146+
}
147+
}
148+
finally
149+
{
150+
ArrayPool<byte>.Shared.Return(buffer);
151+
}
152+
}
153+
154+
public override void Close()
155+
{
156+
sourceStream.Close();
157+
destinationStream.Close();
158+
}
159+
160+
public override void Flush()
161+
{
162+
sourceStream.Flush();
163+
destinationStream.Flush();
164+
}
165+
166+
public override async Task FlushAsync(CancellationToken cancellationToken)
167+
{
168+
await sourceStream.FlushAsync(cancellationToken);
169+
await destinationStream.FlushAsync(cancellationToken);
170+
}
171+
172+
protected override void Dispose(bool disposing)
173+
{
174+
if (!disposing || !isDisposeStream)
175+
{
176+
return;
177+
}
178+
179+
sourceStream.Dispose();
180+
destinationStream.Dispose();
181+
}
182+
183+
public override async ValueTask DisposeAsync()
184+
{
185+
await sourceStream.DisposeAsync();
186+
await destinationStream.DisposeAsync();
187+
188+
GC.SuppressFinalize(this);
189+
}
190+
}
191+
}

CollapseLauncher/Classes/Interfaces/Class/Structs.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,9 @@ public class AssetProperty<T>(
250250
byte[] localCrcByte,
251251
byte[] remoteCrcByte)
252252
: IAssetProperty
253+
where T : struct, Enum
253254
{
254-
public string AssetTypeString { get => Enum.GetName(typeof(T), AssetType); }
255+
public string AssetTypeString { get => Enum.GetName(AssetType); }
255256
public string Name { get; } = name;
256257
public T AssetType { get; } = assetType;
257258
public string Source { get; } = '\\' + source;

0 commit comments

Comments
 (0)