removed empty paks + fixed backups and loading modes + improved speed

This commit is contained in:
iAmAsval 2020-10-30 11:51:13 +01:00
parent 220ed024cd
commit 319a3d52b3
15 changed files with 283 additions and 133 deletions

View File

@ -1,7 +1,6 @@
using FModel.Utils;
using SkiaSharp;
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using FModel.PakReader;
using FModel.PakReader.IO;
@ -16,11 +15,10 @@ namespace FModel.Creator
{
foreach (var ioStore in Globals.CachedIoStores.Values)
{
if (ioStore.IsInitialized)
if (ioStore.Chunks.TryGetValue(id.Id, out string path))
{
var entry = ioStore.Files.FirstOrDefault(it => it.Value.ChunkId.ChunkId == id.Id).Value;
if (entry != null)
return ioStore.MountPoint + entry.Name;
if (ioStore.Files.TryGetValue(ioStore.MountPoint + path.Substring(0, path.LastIndexOf(".")), out FIoStoreEntry value))
return ioStore.MountPoint + value.Name;
}
}
@ -62,7 +60,7 @@ namespace FModel.Creator
string mount = path.Substring(0, path.Length - entry.Name.Substring(0, entry.Name.LastIndexOf('.')).Length);
return Assets.GetPackage(entry, mount);
}
return null;
return default;
}
public static ArraySegment<byte>[] GetPropertyArraySegmentByte(string value)

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
@ -21,7 +22,7 @@ namespace FModel.Grabber.Paks
{
static class PaksGrabber
{
private static readonly Regex _pakFileRegex = new Regex(@"^FortniteGame/Content/Paks/pakchunk(?:0|10.*|\w+)-WindowsClient\.pak$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
private static readonly Regex _pakFileRegex = new Regex(@"^FortniteGame/Content/Paks/pakchunk(?:0|10.*|\w+)-WindowsClient\.(pak|utoc|ucas)$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
public static async Task PopulateMenu()
{
@ -81,26 +82,44 @@ namespace FModel.Grabber.Paks
continue;
}
var pakStream = fileManifest.GetStream();
if (pakStream.Length == 365) continue;
var pakFileName = fileManifest.Name.Replace('/', '\\');
PakFileReader pakFile = new PakFileReader(pakFileName, fileManifest.GetStream());
if (pakFiles++ == 0)
if (pakFileName.EndsWith(".pak"))
{
// define the current game thank to the pak path
Folders.SetGameName(pakFileName);
Globals.Game.Version = pakFile.Info.Version;
Globals.Game.SubVersion = pakFile.Info.SubVersion;
}
await Application.Current.Dispatcher.InvokeAsync(delegate
{
MenuItems.pakFiles.Add(new PakMenuItemViewModel
PakFileReader pakFile = new PakFileReader(pakFileName, pakStream);
if (pakFiles++ == 0)
{
PakFile = pakFile,
IsEnabled = false
// define the current game thank to the pak path
Folders.SetGameName(pakFileName);
Globals.Game.Version = pakFile.Info.Version;
Globals.Game.SubVersion = pakFile.Info.SubVersion;
}
await Application.Current.Dispatcher.InvokeAsync(delegate
{
MenuItems.pakFiles.Add(new PakMenuItemViewModel
{
PakFile = pakFile,
IsEnabled = false
});
});
});
}
else if (pakFileName.EndsWith(".ucas"))
{
var utocStream = manifest.FileManifests.FirstOrDefault(x => x.Name.Equals(fileManifest.Name.Replace(".ucas", ".utoc")));
var ioStore = new FFileIoStoreReader(pakFileName.SubstringAfterLast('\\'), utocStream.GetStream(), pakStream);
await Application.Current.Dispatcher.InvokeAsync(delegate
{
MenuItems.pakFiles.Add(new PakMenuItemViewModel
{
IoStore = ioStore,
IsEnabled = false
});
});
}
}
}
else if (Properties.Settings.Default.PakPath.EndsWith("-val.manifest"))
@ -147,7 +166,13 @@ namespace FModel.Grabber.Paks
string[] paks = Directory.GetFiles(Properties.Settings.Default.PakPath, "*.pak");
for (int i = 0; i < paks.Length; i++)
{
if (!Utils.Paks.IsFileReadLocked(new FileInfo(paks[i])))
var pakInfo = new FileInfo(paks[i]);
if (pakInfo.Length == 365)
{
continue;
}
if (!Utils.Paks.IsFileReadLocked(pakInfo))
{
PakFileReader pakFile = new PakFileReader(paks[i]);
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Registering]", $"{pakFile.FileName} with GUID {pakFile.Info.EncryptionKeyGuid.Hex}");
@ -184,6 +209,7 @@ namespace FModel.Grabber.Paks
var ucasStream = File.OpenRead(ucas);
var ioStore = new FFileIoStoreReader(ucas.SubstringAfterLast('\\'), utocStream, ucasStream);
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[IO Store]", "[Registering]", $"{ioStore.FileName} with GUID {ioStore.TocResource.Header.EncryptionKeyGuid.Hex}");
await Application.Current.Dispatcher.InvokeAsync(delegate
{
MenuItems.pakFiles.Add(new PakMenuItemViewModel
@ -198,7 +224,7 @@ namespace FModel.Grabber.Paks
FConsole.AppendText(string.Format(Properties.Resources.PakFileLocked, Path.GetFileNameWithoutExtension(utoc)), FColors.Red, true);
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[IO Store]", "[Locked]", utoc);
}
}
}
}
});
}

View File

@ -119,11 +119,11 @@ namespace FModel
catch
{
rawMappings ??= await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_TYPE_MAPPINGS);
rawEnumMappings ??= await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_ENUM_MAPPINGS);
rawEnumMappings ??= await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_ENUM_MAPPINGS);
}
#else
var rawMappings = await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_TYPE_MAPPINGS);
var rawEnumMappings = await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_ENUM_MAPPINGS);
var rawMappings = await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_TYPE_MAPPINGS);
var rawEnumMappings = await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_ENUM_MAPPINGS);
#endif
var serializerSettings = new JsonSerializerSettings
{
@ -148,6 +148,7 @@ namespace FModel
public void ReloadMappings(object sender, RoutedEventArgs e)
{
LoadMappings();
Globals.gNotifier.ShowCustomMessage("Mappings", "Reloaded successfully");
}
private void AeConfiguration()
@ -161,7 +162,7 @@ namespace FModel
CommandBindings.Add(Frm.FindBinding);
}
#region MENU ITEMS
#region MENU ITEMS
private void OnAutoShortcutPressed(object sender, RoutedEventArgs e)
{
@ -388,9 +389,9 @@ namespace FModel
}
}
#endregion
#endregion
#region TREEVIEW
#region TREEVIEW
private void OnSelectedPathChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
@ -418,9 +419,9 @@ namespace FModel
}
}
#endregion
#endregion
#region LISTBOX
#region LISTBOX
private void OnSelectedItemChanged(object sender, SelectionChangedEventArgs e)
{
@ -496,9 +497,9 @@ namespace FModel
}
}
#endregion
#endregion
#region BUTTONS
#region BUTTONS
private void OnImageOpenClick(object sender, RoutedEventArgs e) => ImageBoxVm.imageBoxViewModel.OpenImage();
@ -517,9 +518,9 @@ namespace FModel
await Assets.GetUserSelection(FModel_AssetsList.SelectedItems);
}
#endregion
#endregion
#region RIGHT CLICK MENUS
#region RIGHT CLICK MENUS
private async void FModel_MI_Directory_Extract_Click(object sender, RoutedEventArgs e)
{
@ -593,6 +594,6 @@ namespace FModel
Assets.Copy(FModel_AssetsList.SelectedItems, ECopy.FileNoExt);
}
#endregion
#endregion
}
}

View File

@ -44,6 +44,7 @@ namespace FModel.PakReader.IO
public bool IsEncrypted => ContainerFile.ContainerFlags.HasAnyFlags(EIoContainerFlags.Encrypted);
public Dictionary<string, FIoStoreEntry> Files;
public Dictionary<ulong, string> Chunks;
public FIoDirectoryIndexResource _directoryIndex;
private byte[] _directoryIndexBuffer;
@ -107,7 +108,8 @@ namespace FModel.PakReader.IO
var firstEntry = GetChildDirectory(FIoDirectoryIndexHandle.Root);
var tempFiles = new Dictionary<string, FIoStoreEntry>();
ReadIndex("", firstEntry, tempFiles);
Chunks = new Dictionary<ulong, string>();
ReadIndex("", firstEntry, tempFiles, Chunks);
Paks.Merge(tempFiles, out Files, _directoryIndex.MountPoint);
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[FFileIoStoreReader]", "[ReadDirectoryIndex]", $"{FileName} contains {Files.Count} files, mount point: \"{MountPoint}\", version: {(int)TocResource.Header.Version}");
@ -289,9 +291,8 @@ namespace FModel.PakReader.IO
compressionStream.Read(outData, 0, outData.Length);
}
private void ReadIndex(string directoryName, FIoDirectoryIndexHandle dir, IDictionary<string, FIoStoreEntry> outFiles)
private void ReadIndex(string directoryName, FIoDirectoryIndexHandle dir, IDictionary<string, FIoStoreEntry> outFiles, Dictionary<ulong, string> outChunks)
{
while (dir.IsValid())
{
var subDirectoryName = string.Concat(directoryName, GetDirectoryName(dir), "/");
@ -302,11 +303,13 @@ namespace FModel.PakReader.IO
var name = GetFileName(file);
var path = string.Concat(subDirectoryName, name);
var data = GetFileData(file);
outFiles[path] = new FIoStoreEntry(this, data, path, CaseSensitive);
var entry = new FIoStoreEntry(this, data, path, CaseSensitive);
outChunks[entry.ChunkId.ChunkId] = path;
outFiles[path] = entry;
file = GetNextFile(file);
}
ReadIndex(subDirectoryName, GetChildDirectory(dir), outFiles);
ReadIndex(subDirectoryName, GetChildDirectory(dir), outFiles, outChunks);
dir = GetNextDirectory(dir);
}

View File

@ -36,7 +36,7 @@ namespace FModel.PakReader.IO
return hash;
}
public override bool Equals(object? obj)
public override bool Equals(object obj)
{
if (!(obj is FIoChunkId cast))
{

View File

@ -1,16 +1,25 @@
namespace FModel.PakReader.IO
using FModel.Utils;
namespace FModel.PakReader.IO
{
public class FIoStoreEntry : ReaderEntry
{
public readonly FFileIoStoreReader ioStore;
public readonly uint UserData;
public override string ContainerName => ioStore.FileName;
public override string Name { get; }
public readonly uint UserData;
public override long Size { get; }
public override long UncompressedSize { get; }
public override int StructSize { get; }
public override uint CompressionMethodIndex { get; }
public override bool Encrypted { get; }
public FIoChunkId ChunkId => ioStore.TocResource.ChunkIds[UserData];
public FIoOffsetAndLength OffsetLength => ioStore.Toc[ChunkId];
public long Offset => (long) OffsetLength.Offset;
public long Length => (long) OffsetLength.Length;
public string CompressionMethodString => ioStore.TocResource.CompressionMethods[CompressionMethodIndex - 1];
public FIoStoreEntry(FFileIoStoreReader ioStore, uint userData, string name, bool caseSensitive)
{
@ -19,8 +28,30 @@
if (!caseSensitive)
name = name.ToLowerInvariant();
if (name.StartsWith('/'))
name = name.Substring(1);
name = name[1..];
Name = name;
StructSize = 0;
Size = 0;
UncompressedSize = 0;
var compressionBlockSize = ioStore.TocResource.Header.CompressionBlockSize;
var firstBlockIndex = (int)(Offset / compressionBlockSize);
var lastBlockIndex = (int)((BinaryHelper.Align((long)Offset + Length, compressionBlockSize) - 1) / compressionBlockSize);
for (int blockIndex = firstBlockIndex; blockIndex <= lastBlockIndex; blockIndex++)
{
var compressionBlock = ioStore.TocResource.CompressionBlocks[blockIndex];
UncompressedSize += compressionBlock.UncompressedSize;
CompressionMethodIndex = compressionBlock.CompressionMethodIndex;
var rawSize = BinaryHelper.Align(compressionBlock.CompressedSize, AESDecryptor.ALIGN);
Size += rawSize;
if (ioStore.TocResource.Header.ContainerFlags.HasAnyFlags(EIoContainerFlags.Encrypted))
{
Encrypted = true;
}
}
}
public byte[] GetData() => ioStore.Read(ChunkId);

View File

@ -108,10 +108,13 @@ namespace FModel.PakReader.Parsers
foreach (var export in package.Reader.ExportMap)
{
var realImportIndex = Array.FindIndex(ImportMap, it => it == export.GlobalImportIndex);
var nextIndex = FakeImportMap.Count;
FakeImportMap[realImportIndex] = new FObjectResource(new FName(export.ObjectName.String), new FPackageIndex(this, -(nextIndex + 1)));
var outerResource = new FObjectResource(new FName(string.Concat(package.Reader.Summary.Name.String, ".", export.ObjectName.String)), new FPackageIndex());
FakeImportMap.Add(outerResource);
if (realImportIndex > -1)
{
var nextIndex = FakeImportMap.Count;
FakeImportMap[realImportIndex] = new FObjectResource(new FName(export.ObjectName.String), new FPackageIndex(this, -(nextIndex + 1)));
var outerResource = new FObjectResource(new FName(string.Concat(package.Reader.Summary.Name.String, ".", export.ObjectName.String)), new FPackageIndex());
FakeImportMap.Add(outerResource);
}
}
}
@ -122,9 +125,16 @@ namespace FModel.PakReader.Parsers
for (var i = 0; i < ExportMap.Length; i++)
{
var exportMapEntry = ExportMap[i];
FName exportType;
FPackageObjectIndex trigger;
if (exportMapEntry.ClassIndex.IsExport)
trigger = exportMapEntry.SuperIndex;
else if (exportMapEntry.ClassIndex.IsImport)
trigger = exportMapEntry.ClassIndex;
else
throw new FileLoadException("Can't get class name");
if (GlobalData != null && GlobalData.ScriptObjectByGlobalId.TryGetValue(exportMapEntry.ClassIndex, out var scriptObject))
FName exportType;
if (GlobalData != null && GlobalData.ScriptObjectByGlobalId.TryGetValue(trigger, out var scriptObject))
{
exportType = scriptObject.Name;
}
@ -150,10 +160,12 @@ namespace FModel.PakReader.Parsers
//"AkMediaAssetData" => new UAkMediaAssetData(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize),
_ => new UObject(this, properties, type: exportType.String),
};
_dataExportTypes[i] = exportType;
_dataExportTypes[i] = exportType;
}
else
{
_dataExports[i] = null;
_dataExportTypes[i] = exportType;
#if DEBUG
var header = new FUnversionedHeader(this);
using var it = new FIterator(header);

View File

@ -10,21 +10,25 @@ namespace FModel.PakReader.Parsers.Objects
const byte Flag_Encrypted = 0x01;
const byte Flag_Deleted = 0x02;
public bool Encrypted => (Flags & Flag_Encrypted) != 0;
public override bool Encrypted => (Flags & Flag_Encrypted) != 0;
public bool Deleted => (Flags & Flag_Deleted) != 0;
public override string ContainerName { get; }
public override string Name => _name;
private readonly string _name;
public readonly long Offset;
public readonly long Size;
public readonly long UncompressedSize;
public override long Size => _size;
private readonly long _size;
public override long UncompressedSize => _uncompressedSize;
private readonly long _uncompressedSize;
public readonly FPakCompressedBlock[] CompressionBlocks;
public readonly uint CompressionBlockSize;
public readonly uint CompressionMethodIndex;
public override uint CompressionMethodIndex => _compressionMethodIndex;
private readonly uint _compressionMethodIndex;
public readonly byte Flags;
public readonly int StructSize;
public override int StructSize => _structSize;
private readonly int _structSize;
internal FPakEntry(BinaryReader reader, EPakVersion Version, int SubVersion, bool caseSensitive, string pakName)
{
@ -39,26 +43,26 @@ namespace FModel.PakReader.Parsers.Objects
var StartOffset = reader.BaseStream.Position;
Offset = reader.ReadInt64();
Size = reader.ReadInt64();
UncompressedSize = reader.ReadInt64();
_size = reader.ReadInt64();
_uncompressedSize = reader.ReadInt64();
if (Version < EPakVersion.FNAME_BASED_COMPRESSION_METHOD)
{
var LegacyCompressionMethod = reader.ReadInt32();
if (LegacyCompressionMethod == (int)ECompressionFlags.COMPRESS_None)
{
CompressionMethodIndex = 0;
_compressionMethodIndex = 0;
}
else if ((LegacyCompressionMethod & (int)ECompressionFlags.COMPRESS_ZLIB) != 0)
{
CompressionMethodIndex = 1;
_compressionMethodIndex = 1;
}
else if ((LegacyCompressionMethod & (int)ECompressionFlags.COMPRESS_GZIP) != 0)
{
CompressionMethodIndex = 2;
_compressionMethodIndex = 2;
}
else if ((LegacyCompressionMethod & (int)ECompressionFlags.COMPRESS_Custom) != 0)
{
CompressionMethodIndex = 3;
_compressionMethodIndex = 3;
}
else
{
@ -69,15 +73,15 @@ namespace FModel.PakReader.Parsers.Objects
else
{
if (Version == EPakVersion.FNAME_BASED_COMPRESSION_METHOD && SubVersion == 0)
CompressionMethodIndex = reader.ReadByte();
_compressionMethodIndex = reader.ReadByte();
else
CompressionMethodIndex = reader.ReadUInt32();
_compressionMethodIndex = reader.ReadUInt32();
}
if (Version < EPakVersion.NO_TIMESTAMPS) reader.ReadInt64(); // Timestamp
reader.ReadBytes(20); // Hash
if (Version >= EPakVersion.COMPRESSION_ENCRYPTION)
{
if (CompressionMethodIndex != 0)
if (_compressionMethodIndex != 0)
{
CompressionBlocks = reader.ReadTArray(() => new FPakCompressedBlock(reader));
}
@ -87,7 +91,7 @@ namespace FModel.PakReader.Parsers.Objects
}
// Used to seek ahead to the file data instead of parsing the entry again
StructSize = (int)(reader.BaseStream.Position - StartOffset);
_structSize = (int)(reader.BaseStream.Position - StartOffset);
}
internal FPakEntry(BinaryReader reader, bool caseSensitive, string pakName)
@ -102,11 +106,11 @@ namespace FModel.PakReader.Parsers.Objects
var StartOffset = reader.BaseStream.Position;
Offset = reader.ReadInt64();
Size = reader.ReadInt64();
UncompressedSize = reader.ReadInt64();
CompressionMethodIndex = reader.ReadUInt32();
_size = reader.ReadInt64();
_uncompressedSize = reader.ReadInt64();
_compressionMethodIndex = reader.ReadUInt32();
reader.ReadBytes(20); // Hash
if (CompressionMethodIndex != 0)
if (_compressionMethodIndex != 0)
{
CompressionBlocks = reader.ReadTArray(() => new FPakCompressedBlock(reader));
}
@ -114,7 +118,7 @@ namespace FModel.PakReader.Parsers.Objects
CompressionBlockSize = reader.ReadUInt32();
// Used to seek ahead to the file data instead of parsing the entry again
StructSize = (int)(reader.BaseStream.Position - StartOffset);
_structSize = (int)(reader.BaseStream.Position - StartOffset);
}
internal FPakEntry(string pakName, string name, long offset, long size, long uncompressedSize, FPakCompressedBlock[] compressionBlocks, uint compressionBlockSize, uint compressionMethodIndex, byte flags)
@ -122,38 +126,38 @@ namespace FModel.PakReader.Parsers.Objects
ContainerName = pakName;
_name = name;
Offset = offset;
Size = size;
UncompressedSize = uncompressedSize;
_size = size;
_uncompressedSize = uncompressedSize;
CompressionBlocks = compressionBlocks;
CompressionBlockSize = compressionBlockSize;
CompressionMethodIndex = compressionMethodIndex;
_compressionMethodIndex = compressionMethodIndex;
Flags = flags;
StructSize = (int)GetSize(EPakVersion.LATEST, compressionMethodIndex, compressionBlocks != null ? (uint)compressionBlocks.Length : 0);
_structSize = (int)GetSize(EPakVersion.LATEST, compressionMethodIndex, compressionBlocks != null ? (uint)compressionBlocks.Length : 0);
}
public ArraySegment<byte> GetData(Stream stream, byte[] key, string[] compressionMethods)
{
lock (stream)
{
if (CompressionMethodIndex == 0U)
if (_compressionMethodIndex == 0U)
{
stream.Position = Offset + StructSize;
stream.Position = Offset + _structSize;
if (Encrypted)
{
var data = new byte[(Size & 15) == 0 ? Size : (Size / 16 + 1) * 16];
var data = new byte[(_size & 15) == 0 ? _size : (_size / 16 + 1) * 16];
stream.Read(data, 0, data.Length);
return new ArraySegment<byte>(AESDecryptor.DecryptAES(data, key), 0, (int)UncompressedSize);
return new ArraySegment<byte>(AESDecryptor.DecryptAES(data, key), 0, (int)_uncompressedSize);
}
else
{
var data = new byte[UncompressedSize];
var data = new byte[_uncompressedSize];
stream.Read(data, 0, data.Length);
return new ArraySegment<byte>(data);
}
}
else
{
var data = new byte[UncompressedSize];
var data = new byte[_uncompressedSize];
Decompress(stream, key, compressionMethods, data);
return new ArraySegment<byte>(data);
}
@ -166,7 +170,7 @@ namespace FModel.PakReader.Parsers.Objects
if (compressionMethods == null || compressionMethods.Length == 0)
throw new ArgumentOutOfRangeException(nameof(compressionMethods), "CompressionMethods are null or empty");
string compressionMethod = compressionMethods[CompressionMethodIndex - 1]; // -1 because we dont have 'NAME_None' in the array
string compressionMethod = compressionMethods[_compressionMethodIndex - 1]; // -1 because we dont have 'NAME_None' in the array
int bytesRead = 0;
for (int i = 0; i < CompressionBlocks.Length; i++)
{
@ -229,6 +233,6 @@ namespace FModel.PakReader.Parsers.Objects
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsCompressed() => UncompressedSize != Size || CompressionMethodIndex != (int)ECompressionFlags.COMPRESS_None;
public bool IsCompressed() => _uncompressedSize != _size || _compressionMethodIndex != (int)ECompressionFlags.COMPRESS_None;
}
}

View File

@ -5,9 +5,14 @@ namespace FModel.PakReader
public abstract class ReaderEntry
{
public abstract string Name { get; }
public abstract long UncompressedSize { get; }
public abstract long Size { get; }
public abstract int StructSize { get; }
public abstract uint CompressionMethodIndex { get; }
public abstract bool Encrypted { get; }
public abstract string ContainerName { get; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsUE4Package() => Name[Name.LastIndexOf(".")..].Equals(".uasset");
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@ -567,10 +567,11 @@ namespace FModel.Properties {
/// <summary>
/// Recherche une chaîne localisée semblable à • Waddlesworth • Maiky
///• FunGames • Not Officer
///• FunGames • Officer
///• PsychoPast • TSG
///• GMatrixGames • Jackson
///• XTigerHyperX • FireMonkey.
///• XTigerHyperX • FireMonkey
///• Mang0e.
/// </summary>
public static string ContributorsFDetails {
get {
@ -771,11 +772,15 @@ namespace FModel.Properties {
}
/// <summary>
/// Recherche une chaîne localisée semblable à • Yanteh • Maiky
///• FunGames • HYPEX ♥
///• Alexander • Netu ♥
///• SexyNutella • imatrix
///• Frenzy Leaks • LlamaLeaks.
/// Recherche une chaîne localisée semblable à • Maiky ♥ • HYPEX ♥
///• VenomLeaks ♥ • JayKeyFN ♥
///• Fevers ♥ • Netu ♥
///• Quentin Bellus • Yanteh
///• Shiina • SexyNutella
///• Alexander • imatrix
///• Frenzy Leaks • LlamaLeaks
///• XTigerHyperX • FunGames
///• WeLoveFortnite.
/// </summary>
public static string DonatorsFDetails {
get {

View File

@ -285,10 +285,11 @@ It's now the most used free software to leak on Fortnite.</value>
</data>
<data name="ContributorsFDetails" xml:space="preserve">
<value>• Waddlesworth • Maiky
• FunGames • Not Officer
• FunGames • Officer
• PsychoPast • TSG
• GMatrixGames • Jackson
• XTigerHyperX • FireMonkey</value>
• XTigerHyperX • FireMonkey
• Mang0e</value>
<comment>Do not translate</comment>
</data>
<data name="CopySuccess" xml:space="preserve">
@ -350,11 +351,15 @@ It's now the most used free software to leak on Fortnite.</value>
<value>Donators</value>
</data>
<data name="DonatorsFDetails" xml:space="preserve">
<value>• Yanteh • Maiky
• FunGames • HYPEX ♥
• Alexander • Netu ♥
• SexyNutella • imatrix
• Frenzy Leaks • LlamaLeaks</value>
<value>• Maiky ♥ • HYPEX ♥
• VenomLeaks ♥ • JayKeyFN ♥
• Fevers ♥ • Netu ♥
• Quentin Bellus • Yanteh
• Shiina • SexyNutella
• Alexander • imatrix
• Frenzy Leaks • LlamaLeaks
• XTigerHyperX • FunGames
• WeLoveFortnite</value>
<comment>Do not translate</comment>
</data>
<data name="DownloadError" xml:space="preserve">

View File

@ -343,12 +343,12 @@ namespace FModel.Utils
package = new PakPackage(uasset, uexp, ubulk);
else
package = new IoPackage(uasset, ubulk, ioStoreEntry);
#if !DEBUG
_CachedFiles[entry] = new Dictionary<Package, ArraySegment<byte>[]>
{
[package] = new ArraySegment<byte>[] { uasset, uexp, ubulk }
};
#endif
};
return true;
}

View File

@ -15,6 +15,7 @@ using System.Windows.Controls;
using System.Windows.Input;
using FModel.PakReader.Pak;
using FModel.PakReader.Parsers.Objects;
using FModel.PakReader.IO;
namespace FModel.ViewModels.MenuItem
{
@ -196,6 +197,60 @@ namespace FModel.ViewModels.MenuItem
}
}
}
FFileIoStoreReader globalReader = null;
foreach (FFileIoStoreReader ioStore in MenuItems.pakFiles.GetIoStoreReaders())
{
if (ioStore.IsEncrypted && ioStore.AesKey == null)
continue;
if (!Globals.CachedIoStores.ContainsKey(ioStore.FileName))
{
if (ioStore.FileName.Contains("global.ucas", StringComparison.OrdinalIgnoreCase))
{
globalReader = ioStore;
continue;
}
if (!ioStore.ReadDirectoryIndex())
continue;
Globals.CachedIoStores[ioStore.FileName] = ioStore;
StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.MountedPakTo, ioStore.FileName, ioStore.MountPoint), Properties.Resources.Loading);
}
foreach (var (_, entry) in ioStore)
{
// uasset or umap or idk
writer.Write(entry.Offset);
writer.Write(entry.Length);
writer.Write(entry.UncompressedSize);
writer.Write(entry.Encrypted);
writer.Write(entry.StructSize);
writer.Write(ioStore.MountPoint + entry.Name);
writer.Write(entry.CompressionMethodIndex);
// uexp
if (entry.Uexp != null && entry.Uexp is FIoStoreEntry uexp)
{
writer.Write(uexp.Offset);
writer.Write(uexp.Length);
writer.Write(uexp.UncompressedSize);
writer.Write(uexp.Encrypted);
writer.Write(uexp.StructSize);
writer.Write(ioStore.MountPoint + entry.Uexp.Name);
writer.Write(uexp.CompressionMethodIndex);
}
// ubulk
if (entry.Ubulk != null && entry.Ubulk is FIoStoreEntry ubulk)
{
writer.Write(ubulk.Offset);
writer.Write(ubulk.Length);
writer.Write(ubulk.UncompressedSize);
writer.Write(ubulk.Encrypted);
writer.Write(ubulk.StructSize);
writer.Write(ioStore.MountPoint + entry.Ubulk.Name);
writer.Write(ubulk.CompressionMethodIndex);
}
}
}
}).ContinueWith(t =>
{
if (t.Exception != null) Tasks.TaskCompleted(t.Exception);

View File

@ -13,9 +13,7 @@ using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@ -25,6 +23,7 @@ using FModel.PakReader;
using FModel.PakReader.IO;
using FModel.PakReader.Pak;
using FModel.PakReader.Parsers.Objects;
using System.Linq;
namespace FModel.ViewModels.MenuItem
{
@ -308,9 +307,9 @@ namespace FModel.ViewModels.MenuItem
GC.WaitForPendingFinalizers();
}
private Dictionary<string, FPakEntry> GetOldFiles(EPakLoader mode)
private Dictionary<string, ReaderEntry> GetOldFiles(EPakLoader mode)
{
var diff = new Dictionary<string, FPakEntry>();
var diff = new Dictionary<string, ReaderEntry>();
var ofd = new OpenFileDialog()
{
Title = Properties.Resources.SelectFile,
@ -357,11 +356,16 @@ namespace FModel.ViewModels.MenuItem
}
}
var newFiles = new Dictionary<string, FPakEntry>();
var newFiles = new Dictionary<string, ReaderEntry>();
foreach (var fileReader in Globals.CachedPakFiles)
foreach (var files in fileReader.Value)
newFiles[files.Key] = files.Value;
foreach (var fileReader in Globals.CachedIoStores)
foreach (var files in fileReader.Value)
newFiles[files.Key] = files.Value;
Paks.Merge(oldFilesTemp, out var oldFiles, string.Empty);
switch (mode)
@ -369,7 +373,7 @@ namespace FModel.ViewModels.MenuItem
case EPakLoader.New:
foreach (var kvp in newFiles)
{
if (!oldFiles.TryGetValue(kvp.Key, out var entry))
if (!oldFiles.TryGetValue(kvp.Key, out var _))
diff.Add(kvp.Key, kvp.Value);
}
break;
@ -377,7 +381,7 @@ namespace FModel.ViewModels.MenuItem
foreach (var kvp in newFiles)
{
if (oldFiles.TryGetValue(kvp.Key, out var entry))
if (entry.UncompressedSize != kvp.Value.UncompressedSize)
if (entry.UncompressedSize != kvp.Value.UncompressedSize || entry.Encrypted != kvp.Value.Encrypted)
diff.Add(kvp.Key, kvp.Value);
}
break;
@ -386,7 +390,7 @@ namespace FModel.ViewModels.MenuItem
{
if (oldFiles.TryGetValue(kvp.Key, out var entry))
{
if (entry.UncompressedSize != kvp.Value.UncompressedSize)
if (entry.UncompressedSize != kvp.Value.UncompressedSize || entry.Encrypted != kvp.Value.Encrypted)
diff.Add(kvp.Key, kvp.Value);
}
else
@ -395,21 +399,22 @@ namespace FModel.ViewModels.MenuItem
break;
}
string cosmeticsPath;
if (Globals.Game.ActualGame == EGame.Fortnite)
cosmeticsPath = $"/{Folders.GetGameName()}/Content/Athena/Items/Cosmetics/";
else if (Globals.Game.ActualGame == EGame.Valorant)
cosmeticsPath = $"/{Folders.GetGameName()}/Content/Labels/";
else
cosmeticsPath = "/gqdozqhndpioqgnq/"; // just corrupting it so it doesn't trigger all assets
//string cosmeticsPath;
//if (Globals.Game.ActualGame == EGame.Fortnite)
// cosmeticsPath = $"/{Folders.GetGameName()}/Content/Athena/Items/Cosmetics/";
//else if (Globals.Game.ActualGame == EGame.Valorant)
// cosmeticsPath = $"/{Folders.GetGameName()}/Content/Labels/";
//else
// cosmeticsPath = "/gqdozqhndpioqgnq/"; // just corrupting it so it doesn't trigger all assets
var deleted = oldFiles.Where(kvp => !newFiles.TryGetValue(kvp.Key, out var _) && kvp.Key.StartsWith(cosmeticsPath)).ToDictionary(x => x.Key, x => x.Value);
if (deleted.Count > 0)
{
FConsole.AppendText(Properties.Resources.RemovedRenamedCosmetics, FColors.Red, true);
foreach (var kvp in deleted)
FConsole.AppendText($" - {kvp.Value.Name.Substring(1)}", FColors.LightGray, true);
}
//// Remove this for 14.40
//var deleted = oldFiles.Where(kvp => !newFiles.TryGetValue(kvp.Key, out var _) && kvp.Key.StartsWith(cosmeticsPath)).ToDictionary(x => x.Key, x => x.Value);
//if (deleted.Count > 0)
//{
// FConsole.AppendText(Properties.Resources.RemovedRenamedCosmetics, FColors.Red, true);
// foreach (var kvp in deleted)
// FConsole.AppendText($" - {kvp.Value.Name.Substring(1)}", FColors.LightGray, true);
//}
}
return diff;
}

View File

@ -27,7 +27,7 @@ namespace FModel.ViewModels.TabControl
offsets = string.Join(" ", "0x" + (ioEntry.Offset).ToString("X2"),
entry.Uexp != null ? "0x" + (((FIoStoreEntry)ioEntry.Uexp).Offset).ToString("X2") : string.Empty,
entry.Ubulk != null ? "0x" + (((FIoStoreEntry)ioEntry.Ubulk).Offset).ToString("X2") : string.Empty);
tSize = Strings.GetReadableSize(ioEntry.Length + ((ioEntry.Uexp as FIoStoreEntry)?.Length ?? 0) + ((ioEntry.Ubulk as FIoStoreEntry)?.Length ?? 0));
tSize = Strings.GetReadableSize(ioEntry.Size + ((ioEntry.Uexp as FIoStoreEntry)?.Size ?? 0) + ((ioEntry.Ubulk as FIoStoreEntry)?.Size ?? 0));
}
else
{
@ -40,15 +40,15 @@ namespace FModel.ViewModels.TabControl
vm.IncludedExtensions = ext.TrimEnd();
vm.Offsets = offsets.TrimEnd();
vm.TotalSize = tSize;
if (entry is FPakEntry cast)
if (entry is FPakEntry c1)
{
vm.IsEncrypted = cast.Encrypted ? Properties.Resources.Yes : Properties.Resources.No;
vm.CompMethod = ((ECompressionFlags)cast.CompressionMethodIndex).ToString();
vm.IsEncrypted = c1.Encrypted ? Properties.Resources.Yes : Properties.Resources.No;
vm.CompMethod = ((ECompressionFlags)c1.CompressionMethodIndex).ToString();
}
else
else if (entry is FIoStoreEntry c2)
{
vm.IsEncrypted = Properties.Resources.No;
vm.CompMethod = ECompressionFlags.COMPRESS_None.ToString();
vm.IsEncrypted = c2.Encrypted ? Properties.Resources.Yes : Properties.Resources.No;
vm.CompMethod = c2.CompressionMethodString;
}
});
}