Skip to content

Commit

Permalink
Fix broken HSR game repair and cache (Issue: #206)
Browse files Browse the repository at this point in the history
  • Loading branch information
neon-nyan committed Jul 21, 2023
1 parent 98c9935 commit 7d40207
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 22 deletions.
37 changes: 35 additions & 2 deletions CollapseLauncher/Classes/RepairManagement/StarRail/Check.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,29 @@ private void CheckAssetType(FilePropertiesRemote asset, List<FilePropertiesRemot
asset.N = UsePersistent ? fileInfoPersistent.FullName : fileInfoStreaming.FullName;

// If the file has Hash Mark, then create the hash mark file
if (asset.IsHasHashMark) CreateHashMarkFile(asset.N, asset.CRC);
if (asset.IsHasHashMark && UsePersistent) CreateHashMarkFile(asset.N, asset.CRC);

// Check if the file exist on both persistent and streaming path, then mark the
// streaming path as redundant (unused)
if (IsPersistentExist && IsStreamingExist)
{
// Add the count and asset. Mark the type as "RepairAssetType.Unused"
_progressTotalCountFound++;

Dispatch(() => AssetEntry.Add(
new AssetProperty<RepairAssetType>(
Path.GetFileName(fileInfoStreaming.FullName),
RepairAssetType.Unused,
Path.GetDirectoryName(fileInfoStreaming.FullName),
asset.S,
null,
null
)
));
targetAssetIndex.Add(asset);

LogWriteLine($"File [T: {asset.FT}]: {asset.N} is redundant (exist both on persistent and streaming)", LogType.Warning, true);
}

// Check if both location has the file exist or has the size right
if (UsePersistent && !IsPersistentExist && !IsStreamingExist)
Expand Down Expand Up @@ -176,10 +198,21 @@ private void CheckAssetType(FilePropertiesRemote asset, List<FilePropertiesRemot

private void CreateHashMarkFile(string filePath, string hash)
{
// Get the base path and name
string basePath = Path.GetDirectoryName(filePath);
string baseName = Path.GetFileNameWithoutExtension(filePath);

// Create base path if not exist
if (!Directory.Exists(basePath)) Directory.CreateDirectory(basePath);
string toName = Path.Combine(basePath, baseName + $"_{hash}.hash");

// Enumerate any possible existing hash path and delete it
foreach (string existingPath in Directory.EnumerateFiles(basePath, $"{baseName}_*.hash"))
{
File.Delete(existingPath);
}

// Re-create the hash file
string toName = Path.Combine(basePath, $"{baseName}_{hash}.hash");
File.Create(toName).Dispose();
}
#endregion
Expand Down
62 changes: 46 additions & 16 deletions CollapseLauncher/Classes/RepairManagement/StarRail/Fetch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ private async Task Fetch(List<FilePropertiesRemote> assetIndex, CancellationToke

// Read Audio metadata and convert to FilePropertiesRemote
await _gameVersionManager.StarRailMetadataTool.ReadAudioMetadataInformation(token);
ConvertSRMetadataToAssetIndex(_gameVersionManager.StarRailMetadataTool.MetadataAudio, assetIndex);
ConvertSRMetadataToAssetIndex(_gameVersionManager.StarRailMetadataTool.MetadataAudio, assetIndex, true);

// Read Video metadata and convert to FilePropertiesRemote
await _gameVersionManager.StarRailMetadataTool.ReadVideoMetadataInformation(token);
Expand All @@ -56,37 +56,57 @@ private async Task Fetch(List<FilePropertiesRemote> assetIndex, CancellationToke
private unsafe string GetExistingGameRegionID()
{
#nullable enable
// Try get the value as nullable object
object? value = GameSettings.Statics.RegistryRoot?.GetValue("App_LastServerName_h2577443795", null);
// Check if the value is null, then return the default name
if (value == null)
{
// Return the dispatch default name. If none, then throw
return _gamePreset.GameDispatchDefaultName ?? throw new KeyNotFoundException("Default dispatcher name in metadata is not exist!");
}
#nullable disable

ReadOnlySpan<byte> span = (value as byte[]).AsSpan();
fixed (byte* valueSpan = span)
{
string name = Encoding.UTF8.GetString(valueSpan, span.Length - 1);
return name;
}
// Cast the value as byte span
ReadOnlySpan<byte> span = ((byte[])value).AsSpan();
// Get the name from the span and trim the \0 character at the end
string name = Encoding.UTF8.GetString(span.Slice(0, span.Length - 1));
return name;
}

private void ConvertSRMetadataToAssetIndex(SRMetadataBase metadata, List<FilePropertiesRemote> assetIndex)
private void ConvertSRMetadataToAssetIndex(SRMetadataBase metadata, List<FilePropertiesRemote> assetIndex, bool writeAudioLangRedord = false)
{
// Get the voice Lang ID
int voLangID = _gamePreset.GetVoiceLanguageID();
// Get the voice Lang name by ID
string voLangName = _gamePreset.GetStarRailVoiceLanguageFullNameByID(voLangID);

IEnumerable<SRAsset> srAssetEnumerateFiltered = metadata.GetAssets().AssetList;
// If prompt to write Redord file
if (writeAudioLangRedord)
{
// Get game executable name, directory and file path
string execName = Path.GetFileNameWithoutExtension(_gamePreset.GameExecutableName);
string audioRedordDir = Path.Combine(_gamePath, @$"{execName}_Data\Persistent\Audio\AudioPackage\Windows");
string audioRedordPath = Path.Combine(audioRedordDir, "AudioLangRedord.txt");

// Create the directory if not exist
if (!Directory.Exists(audioRedordDir)) Directory.CreateDirectory(audioRedordDir);
// Then write the Redord file content
File.WriteAllText(audioRedordPath, "{\"AudioLang\":\"" + voLangName + "\"}");
}

int count = 0;
long countSize = 0;

foreach (SRAsset asset in srAssetEnumerateFiltered)
// Enumerate the Asset List
foreach (SRAsset asset in metadata.EnumerateAssets())
{
if (IsAudioLangFile(asset, voLangName, out bool isHasHashMark))
{
string hash = HexTool.BytesToHexUnsafe(asset.Hash);
// Get the hash by bytes
string hash = HexTool.BytesToHexUnsafe(asset.Hash);

// Filter only current audio language file and other assets
if (FilterCurrentAudioLangFile(asset, voLangName, out bool IsHasHashMark))
{
// Convert and add the asset as FilePropertiesRemote to assetIndex
assetIndex.Add(new FilePropertiesRemote
{
N = asset.LocalName,
Expand All @@ -95,7 +115,7 @@ private void ConvertSRMetadataToAssetIndex(SRMetadataBase metadata, List<FilePro
FT = ConvertFileTypeEnum(asset.AssetType),
S = asset.Size,
IsPatchApplicable = asset.IsPatch,
IsHasHashMark = isHasHashMark
IsHasHashMark = IsHasHashMark
});
count++;
countSize += asset.Size;
Expand All @@ -109,19 +129,29 @@ private void ConvertSRMetadataToAssetIndex(SRMetadataBase metadata, List<FilePro
LogWriteLine($"Added {count} assets with {SummarizeSizeSimple(countSize)}/{countSize} bytes in size", LogType.Default, true);
}

private bool IsAudioLangFile(SRAsset asset, string langName, out bool isHasHashMark)
private bool FilterCurrentAudioLangFile(SRAsset asset, string langName, out bool isHasHashMark)
{
// Set output value as false
isHasHashMark = false;
switch (asset.AssetType)
{
// In case if the type is SRAssetType.Audio, then do filtering
case SRAssetType.Audio:
// Set isHasHashMark to true
isHasHashMark = true;
// Split the name definition from LocalName
string[] nameDef = asset.LocalName.Split('/');
// If the name definition array length > 1, then start do filtering
if (nameDef.Length > 1)
{
return (isHasHashMark = nameDef[0] == langName) || nameDef[0] == "SFX";
// Compare if the first name definition is equal to target langName.
// Also return if the file is an audio language file if it is a SFX file or not.
return nameDef[0] == langName || nameDef[0] == "SFX";
}
// If it's not in criteria of name definition, then return true as "normal asset"
return true;
default:
// return true as "normal asset"
return true;
}
}
Expand Down
20 changes: 17 additions & 3 deletions CollapseLauncher/Classes/RepairManagement/StarRail/Repair.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,23 @@ private async Task RepairAssetTypeGeneric(FilePropertiesRemote asset, Http _http
string.Format(Lang._GameRepairPage.PerProgressSubtitle2, ConverterTool.SummarizeSizeSimple(_progressTotalSizeCurrent), ConverterTool.SummarizeSizeSimple(_progressTotalSize)),
true);

// Start asset download task
await RunDownloadTask(asset.S, asset.N, asset.RN, _httpClient, token);
LogWriteLine($"File [T: {asset.FT}] {(asset.FT == FileType.Blocks ? asset.CRC : asset.N)} has been downloaded!", LogType.Default, true);
// If asset type is unused, then delete it
if (asset.FT == FileType.Unused)
{
FileInfo fileInfo = new FileInfo(asset.N);
if (fileInfo.Exists)
{
fileInfo.IsReadOnly = false;
fileInfo.Delete();
LogWriteLine($"File [T: {asset.FT}] {(asset.FT == FileType.Blocks ? asset.CRC : asset.N)} deleted!", LogType.Default, true);
}
}
else
{
// Start asset download task
await RunDownloadTask(asset.S, asset.N, asset.RN, _httpClient, token);
LogWriteLine($"File [T: {asset.FT}] {(asset.FT == FileType.Blocks ? asset.CRC : asset.N)} has been downloaded!", LogType.Default, true);
}

// Pop repair asset display entry
PopRepairAssetEntry();
Expand Down
2 changes: 1 addition & 1 deletion Hi3Helper.EncTool

0 comments on commit 7d40207

Please sign in to comment.