Skip to content

Commit

Permalink
Preview 1.82.18 Hotfix (#690)
Browse files Browse the repository at this point in the history
# What's changed? - 1.82.18
- **[Fix]** Launcher crashing when the main game thread unexpectedly
closes, by @neon-nyan
- **[Fix]** Taskbar progress not reset after game install/update, by
@shatyuka
- **[Fix]** Ensures temporary files availability, by @neon-nyan 
- **[Fix]** 7z COMException errors, by @neon-nyan 
- **[Fix]** Genshin's repair missing a few files, by @neon-nyan
  • Loading branch information
Cryotechnic authored Feb 19, 2025
2 parents 3260e8e + dd37df8 commit cddd41b
Show file tree
Hide file tree
Showing 16 changed files with 523 additions and 317 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ on:

env:
DOTNET_INSTALL_DIR: '.\.dotnet'
DOTNET_VERSION: '9.x'
DOTNET_VERSION: '9.0.1xx'
DOTNET_QUALITY: 'ga'
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/qodana-scan-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
Configuration: ${{ matrix.configuration }}
Platform: ${{ matrix.platform }}
DOTNET_INSTALL_DIR: '.\.dotnet'
DOTNET_VERSION: '9.x'
DOTNET_VERSION: '9.0.1xx'
DOTNET_QUALITY: 'ga'
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/qodana-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
Configuration: ${{ matrix.configuration }}
Platform: ${{ matrix.platform }}
DOTNET_INSTALL_DIR: '.\.dotnet'
DOTNET_VERSION: '9.x'
DOTNET_VERSION: '9.0.1xx'
DOTNET_QUALITY: 'ga'
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
permissions:
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/vt-scan-releases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ on:
jobs:
virustotal:
runs-on: ubuntu-latest
permissions:
actions: read
contents: write
pull-requests: write
checks: write
security-events: write
deployments: write
packages: write
statuses: write

steps:
- name: VirusTotal Scan Executables
uses: crazy-max/ghaction-virustotal@v4
Expand Down
91 changes: 49 additions & 42 deletions CollapseLauncher/Classes/GameManagement/GamePlaytime/Playtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,63 +81,70 @@ public void Reset()

public async void StartSession(Process proc, DateTime? begin = null)
{
int hashId = _gameVersionManager.GamePreset.HashID;
try
{
int hashId = _gameVersionManager.GamePreset.HashID;

// If a playtime HashSet has already tracked, then return (do not track the playtime more than once)
// Otherwise, add it to track list
if (!ActiveSessions.Add(hashId)) return;
// If a playtime HashSet has already tracked, then return (do not track the playtime more than once)
// Otherwise, add it to track list
if (!ActiveSessions.Add(hashId)) return;

begin ??= DateTime.Now;
begin ??= DateTime.Now;

TimeSpan initialTimeSpan = CollapsePlaytime.TotalPlaytime;
TimeSpan initialTimeSpan = CollapsePlaytime.TotalPlaytime;

CollapsePlaytime.LastPlayed = begin;
CollapsePlaytime.LastSession = TimeSpan.Zero;
CollapsePlaytime.Save();
PlaytimeUpdated?.Invoke(this, CollapsePlaytime);
CollapsePlaytime.LastPlayed = begin;
CollapsePlaytime.LastSession = TimeSpan.Zero;
CollapsePlaytime.Save();
PlaytimeUpdated?.Invoke(this, CollapsePlaytime);

#if DEBUG
LogWriteLine($"{_gameVersionManager.GamePreset.ProfileName} - Started session at {begin.Value.ToLongTimeString()}.");
LogWriteLine($"{_gameVersionManager.GamePreset.ProfileName} - Started session at {begin.Value.ToLongTimeString()}.");
#endif
int elapsedSeconds = 0;
int elapsedSeconds = 0;

using (var inGameTimer = new Timer())
{
inGameTimer.Interval = 60000;
inGameTimer.Elapsed += (_, _) =>
using (var inGameTimer = new Timer())
{
elapsedSeconds += 60;
DateTime now = DateTime.Now;

CollapsePlaytime.AddMinute();
PlaytimeUpdated?.Invoke(this, CollapsePlaytime);
inGameTimer.Interval = 60000;
inGameTimer.Elapsed += (_, _) =>
{
elapsedSeconds += 60;
DateTime now = DateTime.Now;

CollapsePlaytime.AddMinute();
PlaytimeUpdated?.Invoke(this, CollapsePlaytime);
#if DEBUG
LogWriteLine($"{_gameVersionManager.GamePreset.ProfileName} - {elapsedSeconds}s elapsed. ({now.ToLongTimeString()})");
LogWriteLine($"{_gameVersionManager.GamePreset.ProfileName} - {elapsedSeconds}s elapsed. ({now.ToLongTimeString()})");
#endif
};
};

inGameTimer.Start();
await proc.WaitForExitAsync(_token.Token);
inGameTimer.Stop();
}
inGameTimer.Start();
await proc.WaitForExitAsync(_token.Token);
inGameTimer.Stop();
}

DateTime end = DateTime.Now;
double totalElapsedSeconds = (end - begin.Value).TotalSeconds;
if (totalElapsedSeconds < 0)
{
LogWriteLine($"[HomePage::StartPlaytimeCounter] Date difference cannot be lower than 0. ({totalElapsedSeconds}s)", LogType.Error);
Dialog_InvalidPlaytime(elapsedSeconds);
totalElapsedSeconds = elapsedSeconds;
}
DateTime end = DateTime.Now;
double totalElapsedSeconds = (end - begin.Value).TotalSeconds;
if (totalElapsedSeconds < 0)
{
LogWriteLine($"[HomePage::StartPlaytimeCounter] Date difference cannot be lower than 0. ({totalElapsedSeconds}s)", LogType.Error);
Dialog_InvalidPlaytime(elapsedSeconds);
totalElapsedSeconds = elapsedSeconds;
}

TimeSpan totalTimeSpan = TimeSpan.FromSeconds(totalElapsedSeconds);
LogWriteLine($"Added {totalElapsedSeconds}s [{totalTimeSpan.Hours}h {totalTimeSpan.Minutes}m {totalTimeSpan.Seconds}s] " +
$"to {_gameVersionManager.GamePreset.ProfileName} playtime.", LogType.Default, true);
CollapsePlaytime.Update(initialTimeSpan.Add(totalTimeSpan), false, true);
PlaytimeUpdated?.Invoke(this, CollapsePlaytime);
TimeSpan totalTimeSpan = TimeSpan.FromSeconds(totalElapsedSeconds);
LogWriteLine($"Added {totalElapsedSeconds}s [{totalTimeSpan.Hours}h {totalTimeSpan.Minutes}m {totalTimeSpan.Seconds}s] " +
$"to {_gameVersionManager.GamePreset.ProfileName} playtime.", LogType.Default, true);

CollapsePlaytime.Update(initialTimeSpan.Add(totalTimeSpan), false, true);
PlaytimeUpdated?.Invoke(this, CollapsePlaytime);

ActiveSessions.Remove(hashId);
ActiveSessions.Remove(hashId);
}
catch
{
// ignored
}
}

private static string TimeSpanToString(TimeSpan timeSpan) => $"{timeSpan.Days * 24 + timeSpan.Hours}h {timeSpan.Minutes}m";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -771,9 +771,43 @@ private long GetAssetIndexTotalUncompressSize(List<GameInstallPackage> assetInde

private long GetSingleOrSegmentedUncompressedSize(GameInstallPackage asset)
{
using Stream stream = GetSingleOrSegmentedDownloadStream(asset);
using ArchiveFile archiveFile = ArchiveFile.Create(stream, true);
return archiveFile.Entries.Sum(x => (long)x!.Size);
using Stream stream = GetSingleOrSegmentedDownloadStream(asset);

#if USENEWZIPDECOMPRESS
Func<Stream, long> summaryDelegate;
if (LauncherConfig.IsEnforceToUse7zipOnExtract)
{
summaryDelegate = GetArchiveUncompressedSizeNative7zip;
}
else if ((asset.PathOutput.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) ||
asset.PathOutput.EndsWith(".zip.001", StringComparison.OrdinalIgnoreCase)) &&
!_isAllowExtractCorruptZip)
{
summaryDelegate = GetArchiveUncompressedSizeManaged;
}
else
{
summaryDelegate = GetArchiveUncompressedSizeNative7zip;
}
#else
Func<Stream, long> summaryDelegate = GetArchiveUncompressedSizeNative7zip;
#endif

return summaryDelegate(stream);
}

#if USENEWZIPDECOMPRESS
private long GetArchiveUncompressedSizeManaged(Stream archiveStream)
{
using ZipArchive archive = ZipArchive.Open(archiveStream);
return archive.Entries.Select(x => x.Size).ToArray().Sum();
}
#endif

private long GetArchiveUncompressedSizeNative7zip(Stream archiveStream)
{
using ArchiveFile archiveFile = ArchiveFile.Create(archiveStream, true);
return archiveFile.Entries.Select(x => (long)x.Size).ToArray().Sum();
}

private Stream GetSingleOrSegmentedDownloadStream(GameInstallPackage asset)
Expand Down Expand Up @@ -869,20 +903,20 @@ protected virtual async Task StartPackageInstallationInner(List<GameInstallPacka
InstallPackageExtractorDelegate installTaskDelegate;
if (LauncherConfig.IsEnforceToUse7zipOnExtract)
{
installTaskDelegate = ExtractUsing7zip;
installTaskDelegate = ExtractUsingNative7zip;
}
else if ((asset!.PathOutput.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)
|| asset!.PathOutput.EndsWith(".zip.001", StringComparison.OrdinalIgnoreCase))
&& !_isAllowExtractCorruptZip)
{
installTaskDelegate = ExtractUsingNativeZip;
installTaskDelegate = ExtractUsingManagedZip;
}
else
{
installTaskDelegate = ExtractUsing7zip;
installTaskDelegate = ExtractUsingNative7zip;
}
#else
InstallPackageExtractorDelegate installTaskDelegate = ExtractUsing7zip;
InstallPackageExtractorDelegate installTaskDelegate = ExtractUsingNative7zip;
#endif

// Execute method delegate for the extractor
Expand Down Expand Up @@ -1018,7 +1052,7 @@ protected virtual async Task StartPackageInstallationInner(List<GameInstallPacka
}

#if USENEWZIPDECOMPRESS
private async Task ExtractUsingNativeZip(GameInstallPackage asset)
private async Task ExtractUsingManagedZip(GameInstallPackage asset)
{
int threadCounts = ThreadCount;

Expand All @@ -1037,8 +1071,7 @@ private async Task ExtractUsingNativeZip(GameInstallPackage asset)
IEnumerable<IEnumerable<int>> zipEntriesChunks = zipEntries.Chunk(entriesChunk);

// Run the workers
await Parallel.ForEachAsync(
zipEntriesChunks, new ParallelOptions
await Parallel.ForEachAsync(zipEntriesChunks, new ParallelOptions
{
CancellationToken = Token.Token
},
Expand All @@ -1047,12 +1080,12 @@ await Parallel.ForEachAsync(
await using Stream fs = GetSingleOrSegmentedDownloadStream(asset);
using var zipArchive = ZipArchive.Open(fs);
List<ZipArchiveEntry> entries = zipArchive.Entries.ToList();
await ExtractUsingNativeZipWorker(entry, entries, token);
await ExtractUsingManagedZipWorker(entry, entries, token);
});
}

private async Task ExtractUsingNativeZipWorker(IEnumerable<int> entriesIndex, List<ZipArchiveEntry> entries,
CancellationToken cancellationToken)
private async Task ExtractUsingManagedZipWorker(IEnumerable<int> entriesIndex, List<ZipArchiveEntry> entries,
CancellationToken cancellationToken)
{
byte[] buffer = GC.AllocateUninitializedArray<byte>(BufferBigLength);

Expand Down Expand Up @@ -1139,7 +1172,7 @@ void StartWriteInner(byte[] bufferInner, FileStream outputStream, Stream entrySt
}
#endif

private async Task ExtractUsing7zip(GameInstallPackage asset)
private async Task ExtractUsingNative7zip(GameInstallPackage asset)
{
// Start Async Thread
// Since the ArchiveFile (especially with the callbacks) can't run under
Expand Down
12 changes: 6 additions & 6 deletions CollapseLauncher/Classes/Interfaces/Class/ProgressBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ protected void UpdateSophonFileTotalProgress(long read)
ProgressChanged?.Invoke(this, SophonProgress);

// Update taskbar progress
if (Status.IsCanceled)
if (Status.IsCanceled || Status.IsCompleted)
{
WindowUtility.SetTaskBarState(TaskbarState.NoProgress);
}
Expand Down Expand Up @@ -1041,7 +1041,7 @@ protected virtual ConfiguredTaskAwaitable<byte[]> GetCryptoHashAsync<T>(
Hash.GetCryptoHashAsync<T>(fileInfo,
hmacKey,
read => UpdateHashReadProgress(read, updateProgress, updateTotalProgress),
fileInfo is { Exists: true, Length: > 100 << 20 },
fileInfo is { Exists: true, Length: > 1024 << 20 },
token);

protected virtual ConfiguredTaskAwaitable<byte[]> GetCryptoHashAsync<T>(
Expand All @@ -1054,7 +1054,7 @@ protected virtual ConfiguredTaskAwaitable<byte[]> GetCryptoHashAsync<T>(
Hash.GetCryptoHashAsync<T>(stream,
hmacKey,
read => UpdateHashReadProgress(read, updateProgress, updateTotalProgress),
stream is { Length: > 100 << 20 },
stream is { Length: > 1024 << 20 },
token);

protected virtual byte[] GetCryptoHash<T>(
Expand Down Expand Up @@ -1112,7 +1112,7 @@ protected virtual ConfiguredTaskAwaitable<byte[]> GetHashAsync<T>(
where T : NonCryptographicHashAlgorithm, new() =>
Hash.GetHashAsync<T>(fileInfo,
read => UpdateHashReadProgress(read, updateProgress, updateTotalProgress),
fileInfo is { Exists: true, Length: > 100 << 20 },
fileInfo is { Exists: true, Length: > 1024 << 20 },
token);

protected virtual ConfiguredTaskAwaitable<byte[]> GetHashAsync<T>(
Expand All @@ -1123,7 +1123,7 @@ protected virtual ConfiguredTaskAwaitable<byte[]> GetHashAsync<T>(
where T : NonCryptographicHashAlgorithm, new() =>
Hash.GetHashAsync<T>(stream,
read => UpdateHashReadProgress(read, updateProgress, updateTotalProgress),
stream is { Length: > 100 << 20 },
stream is { Length: > 1024 << 20 },
token);

protected virtual byte[] GetHash<T>(
Expand Down Expand Up @@ -1414,7 +1414,7 @@ protected virtual void UpdateStatus()
{
StatusChanged?.Invoke(this, Status);

if (Status.IsCanceled)
if (Status.IsCanceled || Status.IsCompleted)
{
WindowUtility.SetTaskBarState(TaskbarState.NoProgress);
}
Expand Down
Loading

0 comments on commit cddd41b

Please sign in to comment.