Skip to content

Commit

Permalink
Sync base
Browse files Browse the repository at this point in the history
  • Loading branch information
bagusnl committed Oct 20, 2024
2 parents bf2491d + d4bb74e commit 81fc20d
Show file tree
Hide file tree
Showing 32 changed files with 1,762 additions and 138 deletions.
19 changes: 19 additions & 0 deletions CollapseLauncher/Classes/CachesManagement/Zenless/ZenlessCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using CollapseLauncher.GameSettings.Zenless;
using CollapseLauncher.Interfaces;
using Microsoft.UI.Xaml;
using System.Threading.Tasks;

namespace CollapseLauncher
{
internal class ZenlessCache : ZenlessRepair, ICache, ICacheBase<ZenlessCache>
{
public ZenlessCache(UIElement parentUI, IGameVersionCheck gameVersionManager, ZenlessSettings gameSettings)
: base(parentUI, gameVersionManager, gameSettings, false, null, true)
{ }

public ZenlessCache AsBaseType() => this;

public async Task StartUpdateRoutine(bool showInteractivePrompt = false)
=> await StartRepairRoutine(showInteractivePrompt);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,124 @@
using CollapseLauncher.Helper.Metadata;
using Hi3Helper;
using Microsoft.UI.Xaml;
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Buffers.Text;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;

namespace CollapseLauncher.GameVersioning
{
internal sealed class GameTypeZenlessVersion : GameVersionBase
{
#region Properties
internal RSA SleepyInstance { get; set; }
internal string SleepyIdentity { get; set; }
internal string SleepyArea { get; set; }
#endregion

public GameTypeZenlessVersion(UIElement parentUIElement, RegionResourceProp gameRegionProp, string gameName, string gameRegion)
#region Initialize Sleepy
private void InitializeSleepy(PresetConfig gamePreset)
{
// Go YEET
SleepyInstance = RSA.Create();
goto StartCheck;

// Go to the DOOM
QuitFail:
DisableRepairAndCacheInstance(gamePreset);
return;

StartCheck:
// Check if the thing does not have thing, then DOOMED
if (gamePreset.DispatcherKey == null)
goto QuitFail;

// We cannot pay the house so rent.
byte[] keyUtf8Base64 = ArrayPool<byte>.Shared.Rent(gamePreset.DispatcherKey.Length * 2);

try
{
// Check if the data is an impostor, then eject (basically DOOMED)
if (!Encoding.UTF8.TryGetBytes(gamePreset.DispatcherKey, keyUtf8Base64, out int keyWrittenLen))
goto QuitFail;

// Also if the data is not a crew, then YEET.
OperationStatus base64DecodeStatus = Base64.DecodeFromUtf8InPlace(keyUtf8Base64.AsSpan(0, keyWrittenLen), out int keyFromBase64Len);
if (OperationStatus.Done != base64DecodeStatus)
{
Logger.LogWriteLine($"OOF, we cannot go to sleep as the bed is collapsing! :( Operation Status: {base64DecodeStatus}", LogType.Error, true);
goto QuitFail;
}

// Try serve a dinner and if it fails, then GET OUT!
if (!DataCooker.IsServeV3Data(keyUtf8Base64))
goto QuitFail;

// Enjoy the meal (i guess?)
DataCooker.GetServeV3DataSize(keyUtf8Base64, out long servedCompressedSize, out long servedDecompressedSize);
Span<byte> outServeData = keyUtf8Base64.AsSpan(keyFromBase64Len, (int)servedDecompressedSize);
DataCooker.ServeV3Data(keyUtf8Base64.AsSpan(0, keyFromBase64Len), outServeData, (int)servedCompressedSize, (int)servedDecompressedSize, out int dataWritten);

// Time for dessert!!!
ReadOnlySpan<byte> cheeseCake = outServeData.Slice(0, dataWritten);
int identityN = BinaryPrimitives.ReadInt16LittleEndian(cheeseCake.Slice(dataWritten - 4));
int identityN2 = identityN * 2;
int areaN = BinaryPrimitives.ReadInt16LittleEndian(cheeseCake.Slice(dataWritten - 2));
int areaN2 = areaN * 2;

int nInBite = identityN2 + areaN2;
int wine = dataWritten - (4 + nInBite);
Span<byte> applePie = outServeData.Slice(wine, nInBite);

// And eat good
int len = applePie.Length;
int i = 0;
NomNom:
int pos = wine % ((len - i) & unchecked((int)0xFFFFFFFF));
applePie[i] ^= outServeData[0x10 | pos];
if (++i < len) goto NomNom;

// Then sleep
SleepyIdentity = MemoryMarshal.Cast<byte, char>(applePie.Slice(0, identityN2)).ToString();
SleepyArea = MemoryMarshal.Cast<byte, char>(applePie.Slice(identityN2, areaN2)).ToString();

// Load the load
SleepyInstance.ImportRSAPrivateKey(outServeData.Slice(0, dataWritten), out int bytesRead);

// If you felt food poisoned since last night's dinner, then go to the hospital
if (0 == bytesRead)
goto QuitFail;

// Uh, what else? nothing to do? then go to sleep :amimir:
}
finally
{
// After you wake up, get out from the rent and pay for it.
ArrayPool<byte>.Shared.Return(keyUtf8Base64, true);
}

return;

// Close the door
void DisableRepairAndCacheInstance(PresetConfig config)
{
#if !DEBUG
config.IsRepairEnabled = false;
config.IsCacheUpdateEnabled = false;
#endif
}
}
#endregion

public GameTypeZenlessVersion(UIElement parentUIElement, RegionResourceProp gameRegionProp, PresetConfig gamePreset, string gameName, string gameRegion)
: base(parentUIElement, gameRegionProp, gameName, gameRegion)
{
// Try check for reinitializing game version.
TryReinitializeGameVersion();
InitializeSleepy(gamePreset);
}

public override bool IsGameHasDeltaPatch() => false;
Expand Down
82 changes: 43 additions & 39 deletions CollapseLauncher/Classes/GamePropertyVault.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,49 +26,53 @@ namespace CollapseLauncher.Statics
{
internal class GamePresetProperty : IDisposable
{
internal GamePresetProperty(UIElement UIElementParent, RegionResourceProp APIResouceProp, string GameName, string GameRegion)
internal GamePresetProperty(UIElement uiElementParent, RegionResourceProp apiResourceProp, string gameName, string gameRegion)
{
if (LauncherMetadataHelper.LauncherMetadataConfig != null)
if (LauncherMetadataHelper.LauncherMetadataConfig == null)
{
PresetConfig GamePreset = LauncherMetadataHelper.LauncherMetadataConfig[GameName][GameRegion];
return;
}

_APIResouceProp = APIResouceProp!.Copy();
switch (GamePreset!.GameType)
{
case GameNameType.Honkai:
_GameVersion = new GameTypeHonkaiVersion(UIElementParent, _APIResouceProp, GameName, GameRegion);
_GameSettings = new HonkaiSettings(_GameVersion);
_GameCache = new HonkaiCache(UIElementParent, _GameVersion);
_GameRepair = new HonkaiRepair(UIElementParent, _GameVersion, _GameCache, _GameSettings);
_GameInstall = new HonkaiInstall(UIElementParent, _GameVersion, _GameCache, _GameSettings);
break;
case GameNameType.StarRail:
_GameVersion = new GameTypeStarRailVersion(UIElementParent, _APIResouceProp, GameName, GameRegion);
_GameSettings = new StarRailSettings(_GameVersion);
_GameCache = new StarRailCache(UIElementParent, _GameVersion);
_GameRepair = new StarRailRepair(UIElementParent, _GameVersion);
_GameInstall = new StarRailInstall(UIElementParent, _GameVersion);
break;
case GameNameType.Genshin:
_GameVersion = new GameTypeGenshinVersion(UIElementParent, _APIResouceProp, GameName, GameRegion);
_GameSettings = new GenshinSettings(_GameVersion);
_GameCache = null;
_GameRepair = new GenshinRepair(UIElementParent, _GameVersion, _GameVersion.GameAPIProp!.data!.game!.latest!.decompressed_path);
_GameInstall = new GenshinInstall(UIElementParent, _GameVersion);
break;
case GameNameType.Zenless:
_GameVersion = new GameTypeZenlessVersion(UIElementParent, _APIResouceProp, GameName, GameRegion);
_GameSettings = new ZenlessSettings(_GameVersion);
_GameCache = null;
_GameRepair = null;
_GameInstall = new ZenlessInstall(UIElementParent, _GameVersion, _GameSettings as ZenlessSettings);
break;
default:
throw new NotSupportedException($"[GamePresetProperty.Ctor] Game type: {GamePreset.GameType} ({GamePreset.ProfileName} - {GamePreset.ZoneName}) is not supported!");
}

_GamePlaytime = new Playtime(_GameVersion, _GameSettings);
PresetConfig gamePreset = LauncherMetadataHelper.LauncherMetadataConfig[gameName][gameRegion];

_APIResouceProp = apiResourceProp!.Copy();
switch (gamePreset!.GameType)
{
case GameNameType.Honkai:
_GameVersion = new GameTypeHonkaiVersion(uiElementParent, _APIResouceProp, gameName, gameRegion);
_GameSettings = new HonkaiSettings(_GameVersion);
_GameCache = new HonkaiCache(uiElementParent, _GameVersion);
_GameRepair = new HonkaiRepair(uiElementParent, _GameVersion, _GameCache, _GameSettings);
_GameInstall = new HonkaiInstall(uiElementParent, _GameVersion, _GameCache, _GameSettings);
break;
case GameNameType.StarRail:
_GameVersion = new GameTypeStarRailVersion(uiElementParent, _APIResouceProp, gameName, gameRegion);
_GameSettings = new StarRailSettings(_GameVersion);
_GameCache = new StarRailCache(uiElementParent, _GameVersion);
_GameRepair = new StarRailRepair(uiElementParent, _GameVersion);
_GameInstall = new StarRailInstall(uiElementParent, _GameVersion);
break;
case GameNameType.Genshin:
_GameVersion = new GameTypeGenshinVersion(uiElementParent, _APIResouceProp, gameName, gameRegion);
_GameSettings = new GenshinSettings(_GameVersion);
_GameCache = null;
_GameRepair = new GenshinRepair(uiElementParent, _GameVersion, _GameVersion.GameAPIProp!.data!.game!.latest!.decompressed_path);
_GameInstall = new GenshinInstall(uiElementParent, _GameVersion);
break;
case GameNameType.Zenless:
_GameVersion = new GameTypeZenlessVersion(uiElementParent, _APIResouceProp, gamePreset, gameName, gameRegion);
ZenlessSettings gameSettings = new ZenlessSettings(_GameVersion);
_GameSettings = gameSettings;
_GameCache = new ZenlessCache(uiElementParent, _GameVersion, gameSettings);
_GameRepair = new ZenlessRepair(uiElementParent, _GameVersion, gameSettings);
_GameInstall = new ZenlessInstall(uiElementParent, _GameVersion, gameSettings);
break;
case GameNameType.Unknown:
default:
throw new NotSupportedException($"[GamePresetProperty.Ctor] Game type: {gamePreset.GameType} ({gamePreset.ProfileName} - {gamePreset.ZoneName}) is not supported!");
}

_GamePlaytime = new Playtime(_GameVersion, _GameSettings);
}

internal RegionResourceProp _APIResouceProp { get; set; }
Expand Down
82 changes: 60 additions & 22 deletions CollapseLauncher/Classes/Helper/Metadata/DataCooker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@
using System;
using System.Buffers;
using System.Buffers.Text;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;

using ZstdDecompressStream = ZstdNet.DecompressionStream;

namespace CollapseLauncher.Helper.Metadata
{
internal enum CompressionType : byte
{
None,
Brotli
Brotli,
Zstd
}

internal static class DataCooker
Expand Down Expand Up @@ -150,27 +154,10 @@ internal static void ServeV3Data(ReadOnlySpan<byte> data, Span<byte>
dataWritten = decompressedSize;
break;
case CompressionType.Brotli:
{
Span<byte> dataDecompressed = outData;
BrotliDecoder decoder = new BrotliDecoder();

int offset = 0;
int decompressedWritten = 0;
while (offset < compressedSize)
{
decoder.Decompress(dataRawBuffer.Slice(offset), dataDecompressed.Slice(decompressedWritten),
out int dataConsumedWritten, out int dataDecodedWritten);
decompressedWritten += dataDecodedWritten;
offset += dataConsumedWritten;
}

if (decompressedSize != decompressedWritten)
{
throw new DataMisalignedException("Decompressed data is misaligned!");
}

dataWritten = decompressedWritten;
}
dataWritten = DecompressDataFromBrotli(outData, compressedSize, decompressedSize, dataRawBuffer);
break;
case CompressionType.Zstd:
dataWritten = DecompressDataFromZstd(outData, compressedSize, decompressedSize, dataRawBuffer);
break;
default:
throw new FormatException($"Decompression format is not supported! ({compressionType})");
Expand All @@ -189,5 +176,56 @@ internal static void ServeV3Data(ReadOnlySpan<byte> data, Span<byte>
}
}
}

private static int DecompressDataFromBrotli(Span<byte> outData, int compressedSize, int decompressedSize, ReadOnlySpan<byte> dataRawBuffer)
{
BrotliDecoder decoder = new BrotliDecoder();

int offset = 0;
int decompressedWritten = 0;
while (offset < compressedSize)
{
decoder.Decompress(dataRawBuffer.Slice(offset), outData.Slice(decompressedWritten),
out int dataConsumedWritten, out int dataDecodedWritten);
decompressedWritten += dataDecodedWritten;
offset += dataConsumedWritten;
}

if (decompressedSize != decompressedWritten)
{
throw new DataMisalignedException("Decompressed data is misaligned!");
}

return decompressedWritten;
}

private static unsafe int DecompressDataFromZstd(Span<byte> outData, int compressedSize, int decompressedSize, ReadOnlySpan<byte> dataRawBuffer)
{
fixed (byte* inputBuffer = &dataRawBuffer[0])
fixed (byte* outputBuffer = &outData[0])
{
int decompressedWritten = 0;

byte[] buffer = new byte[4 << 10];

using UnmanagedMemoryStream inputStream = new UnmanagedMemoryStream(inputBuffer, dataRawBuffer.Length);
using UnmanagedMemoryStream outputStream = new UnmanagedMemoryStream(outputBuffer, outData.Length);
using ZstdDecompressStream decompStream = new ZstdDecompressStream(inputStream);

int read;
while ((read = decompStream.Read(buffer)) > 0)
{
outputStream.Write(buffer, 0, read);
decompressedWritten += read;
}

if (decompressedSize != decompressedWritten)
{
throw new DataMisalignedException("Decompressed data is misaligned!");
}

return decompressedWritten;
}
}
}
}
4 changes: 2 additions & 2 deletions CollapseLauncher/Classes/Helper/Metadata/PresetConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -425,8 +425,8 @@ public SophonChunkUrls? LauncherResourceChunksURL
public bool? IsHideSocMedDesc { get; init; } = true;

#if !DEBUG
public bool? IsRepairEnabled { get; init; }
public bool? IsCacheUpdateEnabled { get; init; }
public bool? IsRepairEnabled { get; set; }
public bool? IsCacheUpdateEnabled { get; set; }
#else
public bool? IsRepairEnabled = true;
public bool? IsCacheUpdateEnabled = true;
Expand Down
1 change: 0 additions & 1 deletion CollapseLauncher/Classes/Helper/SimpleProtectData.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Hi3Helper;
using System;
using System.Buffers.Text;
using System.Security;
using System.Security.Cryptography;
using System.Text;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ private List<FileProperties> BuildManifest(List<FilePropertiesRemote> FileRemote
});
}
break;
case FileType.Blocks:
case FileType.Block:
{
_out.AddRange(BuildBlockManifest(Entry.BlkC, Entry.N));
}
Expand Down
Loading

0 comments on commit 81fc20d

Please sign in to comment.