diff --git a/FModel/Creator/Bases/BaseBBDefinition.cs b/FModel/Creator/Bases/BaseBBDefinition.cs index 5293bd63..3d5e38d9 100644 --- a/FModel/Creator/Bases/BaseBBDefinition.cs +++ b/FModel/Creator/Bases/BaseBBDefinition.cs @@ -2,8 +2,8 @@ using System.Windows; using FModel.Creator.Rarities; using FModel.Creator.Texts; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; using SkiaSharp; namespace FModel.Creator.Bases diff --git a/FModel/Creator/Bases/BaseBundle.cs b/FModel/Creator/Bases/BaseBundle.cs index ca8cd3a2..d2f83a8c 100644 --- a/FModel/Creator/Bases/BaseBundle.cs +++ b/FModel/Creator/Bases/BaseBundle.cs @@ -1,9 +1,9 @@ using FModel.Creator.Bundles; using FModel.Creator.Texts; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; using System.Collections.Generic; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Bases { @@ -53,7 +53,7 @@ namespace FModel.Creator.Bases { foreach (SoftObjectProperty questPath in careerQuestBitShifts.Value) { - PakPackage p = Utils.GetPropertyPakPackage(questPath.Value.AssetPathName.String); + Package p = Utils.GetPropertyPakPackage(questPath.Value.AssetPathName.String); if (p.HasExport() && !p.Equals(default)) { var obj = p.GetExport(); diff --git a/FModel/Creator/Bases/BaseGCosmetic.cs b/FModel/Creator/Bases/BaseGCosmetic.cs index cc9241ff..c6c04fd7 100644 --- a/FModel/Creator/Bases/BaseGCosmetic.cs +++ b/FModel/Creator/Bases/BaseGCosmetic.cs @@ -1,10 +1,10 @@ using FModel.Creator.Rarities; using FModel.Creator.Texts; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; using SkiaSharp; using System; using System.Windows; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Bases { diff --git a/FModel/Creator/Bases/BaseIcon.cs b/FModel/Creator/Bases/BaseIcon.cs index 2debe03a..6c79c5bf 100644 --- a/FModel/Creator/Bases/BaseIcon.cs +++ b/FModel/Creator/Bases/BaseIcon.cs @@ -7,16 +7,14 @@ using FModel.Creator.Icons; using FModel.Creator.Rarities; using FModel.Creator.Stats; using FModel.Creator.Texts; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; using FModel.Properties; using FModel.Utils; using Fortnite_API.Objects; using Fortnite_API.Objects.V1; - -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; - using SkiaSharp; namespace FModel.Creator.Bases @@ -68,7 +66,7 @@ namespace FModel.Creator.Bases LargeSmallImage.GetPreviewImage(this, previewImage); else if (export.GetExport("access_item") is { } accessItem) { - PakPackage p = Utils.GetPropertyPakPackage(accessItem.Value.Resource.OuterIndex.Resource.ObjectName.String); + Package p = Utils.GetPropertyPakPackage(accessItem.Value.Resource.OuterIndex.Resource.ObjectName.String); if (p.HasExport() && !p.Equals(default)) { var d = p.GetExport(); diff --git a/FModel/Creator/Bases/BaseItemAccess.cs b/FModel/Creator/Bases/BaseItemAccess.cs index b742ced3..8800e6df 100644 --- a/FModel/Creator/Bases/BaseItemAccess.cs +++ b/FModel/Creator/Bases/BaseItemAccess.cs @@ -1,8 +1,8 @@ using FModel.Creator.Rarities; using FModel.Creator.Texts; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; using SkiaSharp; using SkiaSharp.HarfBuzz; @@ -44,7 +44,7 @@ namespace FModel.Creator.Bases if (export.GetExport("access_item") is ObjectProperty accessItem) { SItem = accessItem.Value.Resource.ObjectName.String; - PakPackage p = Utils.GetPropertyPakPackage(accessItem.Value.Resource.OuterIndex.Resource.ObjectName.String); + Package p = Utils.GetPropertyPakPackage(accessItem.Value.Resource.OuterIndex.Resource.ObjectName.String); if (p.HasExport() && !p.Equals(default)) { var d = p.GetExport(); diff --git a/FModel/Creator/Bases/BaseMapUIData.cs b/FModel/Creator/Bases/BaseMapUIData.cs index 836beb58..fe959efb 100644 --- a/FModel/Creator/Bases/BaseMapUIData.cs +++ b/FModel/Creator/Bases/BaseMapUIData.cs @@ -1,6 +1,6 @@ using FModel.Creator.Texts; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; using SkiaSharp; namespace FModel.Creator.Bases diff --git a/FModel/Creator/Bases/BaseOffer.cs b/FModel/Creator/Bases/BaseOffer.cs index e248b5fe..e8b2abcf 100644 --- a/FModel/Creator/Bases/BaseOffer.cs +++ b/FModel/Creator/Bases/BaseOffer.cs @@ -1,9 +1,9 @@ -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; -using SkiaSharp; +using SkiaSharp; using System; using System.Windows; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Bases { diff --git a/FModel/Creator/Bases/BaseOfferMaterial.cs b/FModel/Creator/Bases/BaseOfferMaterial.cs index 4fc29567..f076485f 100644 --- a/FModel/Creator/Bases/BaseOfferMaterial.cs +++ b/FModel/Creator/Bases/BaseOfferMaterial.cs @@ -1,9 +1,9 @@ -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; -using SkiaSharp; +using SkiaSharp; using System; using System.Windows; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Bases { diff --git a/FModel/Creator/Bases/BasePlaylist.cs b/FModel/Creator/Bases/BasePlaylist.cs index f875c733..68653ae1 100644 --- a/FModel/Creator/Bases/BasePlaylist.cs +++ b/FModel/Creator/Bases/BasePlaylist.cs @@ -2,14 +2,12 @@ using System.Windows; using FModel.Creator.Texts; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; using FModel.Utils; using Fortnite_API.Objects; using Fortnite_API.Objects.V1; - -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; - using SkiaSharp; namespace FModel.Creator.Bases diff --git a/FModel/Creator/Bases/BaseSeason.cs b/FModel/Creator/Bases/BaseSeason.cs index 5d5bd576..f8e5c160 100644 --- a/FModel/Creator/Bases/BaseSeason.cs +++ b/FModel/Creator/Bases/BaseSeason.cs @@ -1,13 +1,13 @@ using FModel.Creator.Bundles; using FModel.Creator.Texts; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; using SkiaSharp; using SkiaSharp.HarfBuzz; using System; using System.Collections.Generic; using System.Linq; using System.Windows.Documents; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Bases { diff --git a/FModel/Creator/Bases/BaseUIData.cs b/FModel/Creator/Bases/BaseUIData.cs index 79e5affe..1be7f5d5 100644 --- a/FModel/Creator/Bases/BaseUIData.cs +++ b/FModel/Creator/Bases/BaseUIData.cs @@ -1,9 +1,9 @@ using FModel.Creator.Stats; using FModel.Creator.Texts; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; using SkiaSharp; using System.Collections.Generic; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Bases { diff --git a/FModel/Creator/Bases/BaseUserOption.cs b/FModel/Creator/Bases/BaseUserOption.cs index 16470651..7beaed75 100644 --- a/FModel/Creator/Bases/BaseUserOption.cs +++ b/FModel/Creator/Bases/BaseUserOption.cs @@ -1,10 +1,10 @@ using FModel.Creator.Texts; -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; using SkiaSharp; using SkiaSharp.HarfBuzz; using System.Collections.Generic; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Bases { diff --git a/FModel/Creator/Bundles/CompletionReward.cs b/FModel/Creator/Bundles/CompletionReward.cs index 3f92b714..b86364ab 100644 --- a/FModel/Creator/Bundles/CompletionReward.cs +++ b/FModel/Creator/Bundles/CompletionReward.cs @@ -1,6 +1,6 @@ using FModel.Utils; -using PakReader.Parsers.PropertyTagData; using System; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Bundles { diff --git a/FModel/Creator/Bundles/Header.cs b/FModel/Creator/Bundles/Header.cs index 658e1804..0f727455 100644 --- a/FModel/Creator/Bundles/Header.cs +++ b/FModel/Creator/Bundles/Header.cs @@ -1,9 +1,9 @@ -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; -using SkiaSharp; +using SkiaSharp; using System; using System.IO; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Bundles { diff --git a/FModel/Creator/Bundles/Quest.cs b/FModel/Creator/Bundles/Quest.cs index ee0847b0..21ac8b88 100644 --- a/FModel/Creator/Bundles/Quest.cs +++ b/FModel/Creator/Bundles/Quest.cs @@ -1,7 +1,7 @@ using FModel.Creator.Texts; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Bundles { @@ -37,7 +37,7 @@ namespace FModel.Creator.Bundles if (obj.TryGetValue("RewardsTable", out var v4) && v4 is ObjectProperty rewardsTable) { - PakPackage p = Utils.GetPropertyPakPackage(rewardsTable.Value.Resource.OuterIndex.Resource.ObjectName.String); + Package p = Utils.GetPropertyPakPackage(rewardsTable.Value.Resource.OuterIndex.Resource.ObjectName.String); if (p.HasExport() && !p.Equals(default)) { var u = p.GetExport(); diff --git a/FModel/Creator/Bundles/Reward.cs b/FModel/Creator/Bundles/Reward.cs index be560c8b..15e75a0a 100644 --- a/FModel/Creator/Bundles/Reward.cs +++ b/FModel/Creator/Bundles/Reward.cs @@ -1,10 +1,10 @@ using FModel.Creator.Bases; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; using SkiaSharp; using System; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Bundles { @@ -37,7 +37,7 @@ namespace FModel.Creator.Bundles string[] parts = assetName.Split(':'); if (parts[0].Equals("HomebaseBannerIcon", StringComparison.CurrentCultureIgnoreCase)) { - PakPackage p = Utils.GetPropertyPakPackage($"/Game/Items/BannerIcons/{parts[1]}.{parts[1]}"); + Package p = Utils.GetPropertyPakPackage($"/Game/Items/BannerIcons/{parts[1]}.{parts[1]}"); if (p.HasExport() && !p.Equals(default)) { if (p.GetExport() is UObject banner) @@ -54,7 +54,7 @@ namespace FModel.Creator.Bundles public Reward(IntProperty quantity, FSoftObjectPath itemFullPath) { RewardQuantity = quantity.Value; - PakPackage p = Utils.GetPropertyPakPackage(itemFullPath.AssetPathName.String); + Package p = Utils.GetPropertyPakPackage(itemFullPath.AssetPathName.String); if (p.HasExport() && !p.Equals(default)) { var d = p.GetExport(); @@ -71,7 +71,7 @@ namespace FModel.Creator.Bundles { RewardQuantity = quantity.Value; - PakPackage p = Utils.GetPropertyPakPackage(itemDefinition.Value.AssetPathName.String); + Package p = Utils.GetPropertyPakPackage(itemDefinition.Value.AssetPathName.String); if (p.HasExport() && !p.Equals(default)) { var d = p.GetExport(); @@ -135,7 +135,7 @@ namespace FModel.Creator.Bundles default: { string path = Utils.GetFullPath($"/FortniteGame/Content/Athena/.*?/{trigger}.*").Replace("FortniteGame/Content", "Game"); - PakPackage p = Utils.GetPropertyPakPackage(path); + Package p = Utils.GetPropertyPakPackage(path); if (p.HasExport() && !p.Equals(default)) { var d = p.GetExport(); diff --git a/FModel/Creator/Creator.cs b/FModel/Creator/Creator.cs index d1b78fbf..061f1bb4 100644 --- a/FModel/Creator/Creator.cs +++ b/FModel/Creator/Creator.cs @@ -5,10 +5,10 @@ using FModel.Creator.Rarities; using FModel.Creator.Stats; using FModel.Creator.Texts; using FModel.ViewModels.ImageBox; -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; using SkiaSharp; using System.IO; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; namespace FModel.Creator { diff --git a/FModel/Creator/Icons/DisplayAssetImage.cs b/FModel/Creator/Icons/DisplayAssetImage.cs index bcc961b0..862b724a 100644 --- a/FModel/Creator/Icons/DisplayAssetImage.cs +++ b/FModel/Creator/Icons/DisplayAssetImage.cs @@ -1,7 +1,7 @@ using FModel.Creator.Bases; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Icons { @@ -33,8 +33,8 @@ namespace FModel.Creator.Icons if (string.IsNullOrEmpty(path)) path = "/Game/Catalog/DisplayAssets/DA_Featured_" + assetName.Substring(0, assetName.LastIndexOf(".")); - PakPackage p = Utils.GetPropertyPakPackage(path); - if (p.HasExport() && !p.Equals(default)) + Package p = Utils.GetPropertyPakPackage(path); + if (p != null && p.HasExport()) { var obj = p.GetExport(); if (obj != null) diff --git a/FModel/Creator/Icons/LargeSmallImage.cs b/FModel/Creator/Icons/LargeSmallImage.cs index 9fd049e3..e9ae83d8 100644 --- a/FModel/Creator/Icons/LargeSmallImage.cs +++ b/FModel/Creator/Icons/LargeSmallImage.cs @@ -1,7 +1,7 @@ using FModel.Creator.Bases; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; using SkiaSharp; namespace FModel.Creator.Icons @@ -16,11 +16,11 @@ namespace FModel.Creator.Icons public static void GetPreviewImage(BaseIcon icon, ObjectProperty o, string assetName) => GetPreviewImage(icon, o, assetName, true); public static void GetPreviewImage(BaseIcon icon, ObjectProperty o, string assetName, bool hightRes) { - string path = o.Value.Resource.OuterIndex.Resource.ObjectName.String; - if (path.Equals("/Game/Athena/Items/Weapons/WID_Harvest_Pickaxe_STWCosmetic_Tier")) + string path = o.Value.Resource?.OuterIndex.Resource?.ObjectName.String; + if (path?.Equals("/Game/Athena/Items/Weapons/WID_Harvest_Pickaxe_STWCosmetic_Tier") == true) path += "_" + assetName.Substring(assetName.LastIndexOf(".") - 1, 1); - PakPackage p = Utils.GetPropertyPakPackage(path); + Package p = Utils.GetPropertyPakPackage(path); if (p.HasExport() && !p.Equals(default)) { if (GetPreviewImage(icon, p.GetIndexedExport(0), hightRes)) diff --git a/FModel/Creator/Icons/UserFacingFlag.cs b/FModel/Creator/Icons/UserFacingFlag.cs index 82b5ac54..08826700 100644 --- a/FModel/Creator/Icons/UserFacingFlag.cs +++ b/FModel/Creator/Icons/UserFacingFlag.cs @@ -1,12 +1,12 @@ using FModel.Creator.Bases; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; using SkiaSharp; using System; using System.Collections.Generic; using System.Windows; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Icons { @@ -16,7 +16,7 @@ namespace FModel.Creator.Icons { if (uffs.Count > 0) { - PakPackage p = Utils.GetPropertyPakPackage("/Game/Items/ItemCategories"); //PrimaryCategories - SecondaryCategories - TertiaryCategories + Package p = Utils.GetPropertyPakPackage("/Game/Items/ItemCategories"); //PrimaryCategories - SecondaryCategories - TertiaryCategories if (p.HasExport() && !p.Equals(default)) { var o = p.GetExport(); diff --git a/FModel/Creator/Rarities/Rarity.cs b/FModel/Creator/Rarities/Rarity.cs index 540725c2..15050f7a 100644 --- a/FModel/Creator/Rarities/Rarity.cs +++ b/FModel/Creator/Rarities/Rarity.cs @@ -1,10 +1,10 @@ using FModel.Creator.Bases; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; using SkiaSharp; using System.Linq; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Rarities { @@ -12,8 +12,8 @@ namespace FModel.Creator.Rarities { public static void GetInGameRarity(BaseIcon icon, EnumProperty e) { - PakPackage p = Utils.GetPropertyPakPackage("/Game/Balance/RarityData"); - if (p.HasExport() && !p.Equals(default)) + Package p = Utils.GetPropertyPakPackage("/Game/Balance/RarityData"); + if (p != null && p.HasExport()) { var d = p.GetExport(); if (d != null) @@ -68,13 +68,13 @@ namespace FModel.Creator.Rarities public static void GetInGameRarity(BaseGCosmetic icon, EnumProperty e) { - PakPackage p = Utils.GetPropertyPakPackage("/Game/UI/UIKit/DT_RarityColors"); - if (p.HasExport() && !p.Equals(default)) + Package p = Utils.GetPropertyPakPackage("/Game/UI/UIKit/DT_RarityColors"); + if (p != null || p.HasExport()) { var d = p.GetExport(); if (d != null) { - if (e != null && d.TryGetValue(e?.Value.String["EXRarity::".Length..], out object r) && r is UObject rarity && + if (e != null && d.TryGetValue(e.Value.String["EXRarity::".Length..], out object r) && r is UObject rarity && rarity.GetExport("Colors") is ArrayProperty colors && colors.Value[0] is StructProperty s1 && s1.Value is FLinearColor color1 && colors.Value[1] is StructProperty s2 && s2.Value is FLinearColor color2 && diff --git a/FModel/Creator/Rarities/Serie.cs b/FModel/Creator/Rarities/Serie.cs index 8d413508..3c384d52 100644 --- a/FModel/Creator/Rarities/Serie.cs +++ b/FModel/Creator/Rarities/Serie.cs @@ -1,8 +1,8 @@ using FModel.Creator.Bases; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; using SkiaSharp; namespace FModel.Creator.Rarities @@ -11,7 +11,7 @@ namespace FModel.Creator.Rarities { public static void GetRarity(BaseIcon icon, ObjectProperty o) { - PakPackage p = Utils.GetPropertyPakPackage(o.Value.Resource.OuterIndex.Resource.ObjectName.String); + Package p = Utils.GetPropertyPakPackage(o.Value.Resource.OuterIndex.Resource.ObjectName.String); if (p.HasExport() && !p.Equals(default)) { var obj = p.GetExport(); diff --git a/FModel/Creator/Stats/Statistics.cs b/FModel/Creator/Stats/Statistics.cs index ca62bdf0..a5287233 100644 --- a/FModel/Creator/Stats/Statistics.cs +++ b/FModel/Creator/Stats/Statistics.cs @@ -1,13 +1,13 @@ using FModel.Creator.Bases; using FModel.Creator.Texts; using FModel.Utils; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; using SkiaSharp; using SkiaSharp.HarfBuzz; using System; using System.Windows; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Stats { @@ -17,7 +17,7 @@ namespace FModel.Creator.Stats { if (!ammoData.Value.AssetPathName.String.StartsWith("/Game/Athena/Items/Consumables/")) { - PakPackage p = Utils.GetPropertyPakPackage(ammoData.Value.AssetPathName.String); + Package p = Utils.GetPropertyPakPackage(ammoData.Value.AssetPathName.String); if (p.HasExport() && !p.Equals(default)) { var obj = p.GetExport(); @@ -43,7 +43,7 @@ namespace FModel.Creator.Stats o1.TryGetValue("DataTable", out var c1) && c1 is ObjectProperty dataTable && o1.TryGetValue("RowName", out var c2) && c2 is NameProperty rowName) { - PakPackage p = Utils.GetPropertyPakPackage(dataTable.Value.Resource.OuterIndex.Resource.ObjectName.String); + Package p = Utils.GetPropertyPakPackage(dataTable.Value.Resource.OuterIndex.Resource.ObjectName.String); if (p.HasExport() && !p.Equals(default)) { var table = p.GetExport(); @@ -79,7 +79,7 @@ namespace FModel.Creator.Stats public static void GetHeroStats(BaseIcon icon, ObjectProperty heroGameplayDefinition) { - PakPackage p = Utils.GetPropertyPakPackage(heroGameplayDefinition.Value.Resource.OuterIndex.Resource.ObjectName.String); + Package p = Utils.GetPropertyPakPackage(heroGameplayDefinition.Value.Resource.OuterIndex.Resource.ObjectName.String); if (p.HasExport() && !p.Equals(default)) { var obj = p.GetExport(); @@ -108,7 +108,7 @@ namespace FModel.Creator.Stats { if (parent.TryGetValue("GrantedAbilityKit", out var v) && v is SoftObjectProperty grantedAbilityKit) { - PakPackage k = Utils.GetPropertyPakPackage(grantedAbilityKit.Value.AssetPathName.String); + Package k = Utils.GetPropertyPakPackage(grantedAbilityKit.Value.AssetPathName.String); if (k.HasExport() && !k.Equals(default)) { var kit = k.GetExport(); diff --git a/FModel/Creator/Texts/GameplayTag.cs b/FModel/Creator/Texts/GameplayTag.cs index 3f70c47f..29d4219a 100644 --- a/FModel/Creator/Texts/GameplayTag.cs +++ b/FModel/Creator/Texts/GameplayTag.cs @@ -1,10 +1,10 @@ using FModel.Creator.Bases; using FModel.Creator.Icons; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; using FModel.Utils; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; namespace FModel.Creator.Texts { @@ -32,7 +32,7 @@ namespace FModel.Creator.Texts private static string GetCosmeticSet(string setName) { - PakPackage p = Utils.GetPropertyPakPackage("/Game/Athena/Items/Cosmetics/Metadata/CosmeticSets"); + Package p = Utils.GetPropertyPakPackage("/Game/Athena/Items/Cosmetics/Metadata/CosmeticSets"); if (p.HasExport() && !p.Equals(default)) { var d = p.GetExport(); diff --git a/FModel/Creator/Texts/Text.cs b/FModel/Creator/Texts/Text.cs index f54f5959..1d626eea 100644 --- a/FModel/Creator/Texts/Text.cs +++ b/FModel/Creator/Texts/Text.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using FModel.Creator.Bases; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; +using FModel.PakReader; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; using SkiaSharp; using SkiaSharp.HarfBuzz; @@ -25,7 +25,7 @@ namespace FModel.Creator.Texts return b.SourceString.Replace("", string.Empty).Replace("", string.Empty); else if (text.Text is FTextHistory.StringTableEntry s) { - PakPackage p = Utils.GetPropertyPakPackage(s.TableId.String); + Package p = Utils.GetPropertyPakPackage(s.TableId.String); if (p.HasExport() && !p.Equals(default)) { var table = p.GetExport(); @@ -69,7 +69,7 @@ namespace FModel.Creator.Texts o2.TryGetValue("CurveTable", out var c2) && c2 is ObjectProperty curveTable && o2.TryGetValue("RowName", out var c3) && c3 is NameProperty rowName) // new way { - PakPackage p = Utils.GetPropertyPakPackage(curveTable.Value.Resource.OuterIndex.Resource.ObjectName.String); + Package p = Utils.GetPropertyPakPackage(curveTable.Value.Resource.OuterIndex.Resource.ObjectName.String); if (p.HasExport() && !p.Equals(default)) { var table = p.GetExport(); @@ -98,7 +98,7 @@ namespace FModel.Creator.Texts o2.TryGetValue("CurveTable", out var c2) && c2 is ObjectProperty curveTable && o2.TryGetValue("RowName", out var c3) && c3 is NameProperty rowName) // new way { - PakPackage p = Utils.GetPropertyPakPackage(curveTable.Value.Resource.OuterIndex.Resource.ObjectName.String); + Package p = Utils.GetPropertyPakPackage(curveTable.Value.Resource.OuterIndex.Resource.ObjectName.String); if (p.HasExport() && !p.Equals(default)) { var table = p.GetExport(); diff --git a/FModel/Creator/Texts/Typefaces.cs b/FModel/Creator/Texts/Typefaces.cs index 457b5d97..79f11c37 100644 --- a/FModel/Creator/Texts/Typefaces.cs +++ b/FModel/Creator/Texts/Typefaces.cs @@ -82,8 +82,13 @@ namespace FModel.Creator.Texts if (Globals.Game.ActualGame == EGame.Fortnite) { ArraySegment[] t = Utils.GetPropertyArraySegmentByte(_FORTNITE_BASE_PATH + _BURBANK_BIG_CONDENSED_BLACK); - if (t != null && t.Length == 3 && t[2].Array != null) - BundleDefaultTypeface = SKTypeface.FromStream(t[2].AsStream()); + if (t != null && t.Length == 3) + { + if (t[0].Array != null) + BundleDefaultTypeface = SKTypeface.FromStream(t[0].AsStream()); + if (BundleDefaultTypeface != null && t[2].Array != null) + BundleDefaultTypeface = SKTypeface.FromStream(t[2].AsStream()); + } else BundleDefaultTypeface = DefaultTypeface; string namePath = _FORTNITE_BASE_PATH + ( @@ -97,8 +102,13 @@ namespace FModel.Creator.Texts if (!namePath.Equals(_FORTNITE_BASE_PATH)) { t = Utils.GetPropertyArraySegmentByte(namePath); - if (t != null && t.Length == 3 && t[2].Array != null) - DisplayNameTypeface = SKTypeface.FromStream(t[2].AsStream()); + if (t != null && t.Length == 3) + { + if (t[0].Array != null) + DisplayNameTypeface = SKTypeface.FromStream(t[0].AsStream()); + if (DisplayNameTypeface != null && t[2].Array != null) + DisplayNameTypeface = SKTypeface.FromStream(t[2].AsStream()); + } } else DisplayNameTypeface = DefaultTypeface; @@ -110,8 +120,13 @@ namespace FModel.Creator.Texts Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Chinese ? string.Empty : _BURBANK_SMALL_BOLD); t = Utils.GetPropertyArraySegmentByte(bottomPath); - if (t != null && t.Length == 3 && t[2].Array != null) - BottomDefaultTypeface = SKTypeface.FromStream(t[2].AsStream()); + if (t != null && t.Length == 3) + { + if (t[0].Array != null) + BottomDefaultTypeface = SKTypeface.FromStream(t[0].AsStream()); + if (BottomDefaultTypeface != null && t[2].Array != null) + BottomDefaultTypeface = SKTypeface.FromStream(t[2].AsStream()); + } string descriptionPath = _FORTNITE_BASE_PATH + ( Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Korean ? _NOTO_SANS_KR_REGULAR : @@ -121,8 +136,13 @@ namespace FModel.Creator.Texts Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Chinese ? _NOTO_SANS_SC_REGULAR : _NOTO_SANS_REGULAR); t = Utils.GetPropertyArraySegmentByte(descriptionPath); - if (t != null && t.Length == 3 && t[2].Array != null) - DescriptionTypeface = SKTypeface.FromStream(t[2].AsStream()); + if (t != null && t.Length == 3) + { + if (t[0].Array != null) + DescriptionTypeface = SKTypeface.FromStream(t[0].AsStream()); + if (DescriptionTypeface != null && t[2].Array != null) + DescriptionTypeface = SKTypeface.FromStream(t[2].AsStream()); + } else DescriptionTypeface = DefaultTypeface; string bundleNamePath = _FORTNITE_BASE_PATH + ( @@ -136,8 +156,13 @@ namespace FModel.Creator.Texts if (!bundleNamePath.Equals(_FORTNITE_BASE_PATH)) { t = Utils.GetPropertyArraySegmentByte(bundleNamePath); - if (t != null && t.Length == 3 && t[2].Array != null) - BundleDisplayNameTypeface = SKTypeface.FromStream(t[2].AsStream()); + if (t != null && t.Length == 3) + { + if (t[0].Array != null) + BundleDisplayNameTypeface = SKTypeface.FromStream(t[0].AsStream()); + if (BundleDisplayNameTypeface != null && t[2].Array != null) + BundleDisplayNameTypeface = SKTypeface.FromStream(t[2].AsStream()); + } } else BundleDisplayNameTypeface = BundleDefaultTypeface; } diff --git a/FModel/Creator/Utils.cs b/FModel/Creator/Utils.cs index ae7fadbd..91770d66 100644 --- a/FModel/Creator/Utils.cs +++ b/FModel/Creator/Utils.cs @@ -1,15 +1,31 @@ using FModel.Utils; -using PakReader.Pak; -using PakReader.Parsers.Class; -using PakReader.Parsers.PropertyTagData; using SkiaSharp; using System; +using System.Linq; using System.Runtime.CompilerServices; +using FModel.PakReader; +using FModel.PakReader.IO; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.PropertyTagData; namespace FModel.Creator { static class Utils { + public static string GetFullPath(FPackageId id) + { + foreach (var ioStore in Globals.CachedIoStores.Values) + { + if (ioStore.IsInitialized) + { + var entry = ioStore.Files.FirstOrDefault(it => it.Value.ChunkId.ChunkId == id.Id).Value; + if (entry != null) + return ioStore.MountPoint + entry.Name; + } + } + + return null; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string GetFullPath(string partialPath) { @@ -18,20 +34,35 @@ namespace FModel.Creator { return fullPath; } + + foreach (var ioStoreReader in Globals.CachedIoStores.Values) + { + if (ioStoreReader.TryGetPartialKey(partialPath, out var fullPath)) + { + return fullPath; + } + } return string.Empty; } - public static PakPackage GetPropertyPakPackage(string value) + public static Package GetPropertyPakPackage(string value) { string path = Strings.FixPath(value); foreach (var fileReader in Globals.CachedPakFiles.Values) if (fileReader.TryGetCaseInsensiteveValue(path, out var entry)) { // kinda sad to use Globals.CachedPakFileMountPoint when the mount point is already in the path ¯\_(ツ)_/¯ - string mount = path.Substring(0, path.Length - entry.Name.Substring(0, entry.Name.LastIndexOf(".")).Length); - return Assets.GetPakPackage(entry, mount); + string mount = path.Substring(0, path.Length - entry.Name.Substring(0, entry.Name.LastIndexOf('.')).Length); + return Assets.GetPackage(entry, mount); } - return default; + foreach (var ioStoreReader in Globals.CachedIoStores.Values) + if (ioStoreReader.TryGetCaseInsensiteveValue(path, out var entry)) + { + // kinda sad to use Globals.CachedPakFileMountPoint when the mount point is already in the path ¯\_(ツ)_/¯ + string mount = path.Substring(0, path.Length - entry.Name.Substring(0, entry.Name.LastIndexOf('.')).Length); + return Assets.GetPackage(entry, mount); + } + return null; } public static ArraySegment[] GetPropertyArraySegmentByte(string value) @@ -41,7 +72,14 @@ namespace FModel.Creator if (fileReader.TryGetCaseInsensiteveValue(path, out var entry)) { // kinda sad to use Globals.CachedPakFileMountPoint when the mount point is already in the path ¯\_(ツ)_/¯ - string mount = path.Substring(0, path.Length - entry.Name.Substring(0, entry.Name.LastIndexOf(".")).Length); + string mount = path.Substring(0, path.Length - entry.Name.Substring(0, entry.Name.LastIndexOf('.')).Length); + return Assets.GetArraySegmentByte(entry, mount); + } + foreach (var ioStoreReader in Globals.CachedIoStores.Values) + if (ioStoreReader.TryGetCaseInsensiteveValue(path, out var entry)) + { + // kinda sad to use Globals.CachedPakFileMountPoint when the mount point is already in the path ¯\_(ツ)_/¯ + string mount = path.Substring(0, path.Length - entry.Name.Substring(0, entry.Name.LastIndexOf('.')).Length); return Assets.GetArraySegmentByte(entry, mount); } return default; @@ -74,7 +112,7 @@ namespace FModel.Creator s = "/Game/UI/Textures/assets/cosmetics/skins/headshot/Skin_Headshot_TimeWeaver_UIT"; } - PakPackage p = GetPropertyPakPackage(s); + var p = GetPropertyPakPackage(s); if (p.HasExport() && !p.Equals(default)) { var i = p.GetExport(); diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index 040b17e8..f97773e8 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -137,7 +137,7 @@ - + @@ -149,6 +149,7 @@ + diff --git a/FModel/Globals.cs b/FModel/Globals.cs index d467e129..15bec5e3 100644 --- a/FModel/Globals.cs +++ b/FModel/Globals.cs @@ -1,8 +1,9 @@ -using PakReader.Pak; -using PakReader.Parsers.Objects; -using System; +using System; using System.Collections.Generic; using System.Windows; +using FModel.PakReader.IO; +using FModel.PakReader.Pak; +using FModel.PakReader.Parsers.Objects; using FModel.Properties; using ToastNotifications; using ToastNotifications.Lifetime; @@ -17,6 +18,10 @@ namespace FModel /// PakFileReader is the reader where you can grab the FPakEntries, MountPoint and more /// public static readonly Dictionary CachedPakFiles = new Dictionary(); + public static readonly Dictionary CachedIoStores = new Dictionary(); + public static FIoGlobalData GlobalData = null; + public static Dictionary> TypeMappings; + public static Dictionary> EnumMappings; public static readonly Notifier gNotifier = new Notifier(cfg => { cfg.LifetimeSupervisor = new TimeAndCountBasedLifetimeSupervisor(TimeSpan.FromSeconds(7), MaximumNotificationCount.FromCount(15)); diff --git a/FModel/Grabber/Manifests/ValorantAPIManifest.cs b/FModel/Grabber/Manifests/ValorantAPIManifest.cs index e9b02d57..0affc74c 100644 --- a/FModel/Grabber/Manifests/ValorantAPIManifest.cs +++ b/FModel/Grabber/Manifests/ValorantAPIManifest.cs @@ -8,11 +8,9 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; - +using FModel.PakReader; using FModel.Utils; -using PakReader; - namespace FModel.Grabber.Manifests { public class ValorantAPIManifest diff --git a/FModel/Grabber/Paks/PaksGrabber.cs b/FModel/Grabber/Paks/PaksGrabber.cs index 773048e1..302f7e00 100644 --- a/FModel/Grabber/Paks/PaksGrabber.cs +++ b/FModel/Grabber/Paks/PaksGrabber.cs @@ -11,12 +11,12 @@ using EpicManifestParser.Objects; using FModel.Grabber.Manifests; using FModel.Logger; +using FModel.PakReader.IO; +using FModel.PakReader.Pak; using FModel.Utils; using FModel.ViewModels.MenuItem; using FModel.Windows.Launcher; -using PakReader.Pak; - namespace FModel.Grabber.Paks { static class PaksGrabber @@ -143,6 +143,7 @@ namespace FModel.Grabber.Paks // define the current game thank to the pak path Folders.SetGameName(Properties.Settings.Default.PakPath); + // paks string[] paks = Directory.GetFiles(Properties.Settings.Default.PakPath, "*.pak"); for (int i = 0; i < paks.Length; i++) { @@ -171,6 +172,33 @@ namespace FModel.Grabber.Paks DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Locked]", paks[i]); } } + + // io stores + var utocs = Directory.GetFiles(Properties.Settings.Default.PakPath, "*.utoc"); + foreach (var utoc in utocs) + { + var ucas = utoc.Replace(".utoc", ".ucas"); + if (!Utils.Paks.IsFileReadLocked(new FileInfo(utoc)) && !Utils.Paks.IsFileReadLocked(new FileInfo(ucas))) + { + var utocStream = new MemoryStream(await File.ReadAllBytesAsync(utoc)); + 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 + { + IoStore = ioStore, + IsEnabled = false + }); + }); + } + else + { + FConsole.AppendText(string.Format(Properties.Resources.PakFileLocked, Path.GetFileNameWithoutExtension(utoc)), FColors.Red, true); + DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[IO Store]", "[Locked]", utoc); + } + } } }); } diff --git a/FModel/MainWindow.xaml b/FModel/MainWindow.xaml index e49c0c11..31adb69a 100644 --- a/FModel/MainWindow.xaml +++ b/FModel/MainWindow.xaml @@ -23,6 +23,7 @@ + @@ -32,6 +33,7 @@ + diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index e92253f5..33f5237c 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -23,14 +23,19 @@ using FModel.Windows.Search; using FModel.Windows.Settings; using FModel.Windows.SoundPlayer; using System; +using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using PropertyInfo = FModel.PakReader.IO.PropertyInfo; namespace FModel { @@ -72,6 +77,8 @@ namespace FModel if (!Properties.Settings.Default.SkipVersion) Updater.CheckForUpdate(); DebugHelper.WriteUserSettings(); Folders.CheckWatermarks(); + + LoadMappings(); await Task.WhenAll(Init()).ContinueWith(t => { @@ -97,6 +104,52 @@ namespace FModel await Folders.DownloadAndExtractVgm().ConfigureAwait(false); } + private async void LoadMappings() + { + try + { +#if DEBUG + string rawMappings = null; + string rawEnumMappings = null; + try + { + rawMappings = await File.ReadAllTextAsync("TypeMappings.json"); + rawEnumMappings = await File.ReadAllTextAsync("EnumMappings.json"); + } + catch + { + rawMappings ??= await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_TYPE_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); +#endif + var serializerSettings = new JsonSerializerSettings + { + ContractResolver = new DefaultContractResolver + {NamingStrategy = new CamelCaseNamingStrategy(false, false)} + }; + Globals.TypeMappings = + JsonConvert.DeserializeObject>>(rawMappings, + serializerSettings); + Globals.EnumMappings = JsonConvert.DeserializeObject>>(rawEnumMappings, + serializerSettings); + + } + catch (Exception exception) + { + DebugHelper.WriteException(exception, "Failed to load Mappings"); + Globals.TypeMappings ??= new Dictionary>(); + Globals.EnumMappings ??= new Dictionary>(); + } + } + + public void ReloadMappings(object sender, RoutedEventArgs e) + { + LoadMappings(); + } + private void AeConfiguration() { AvalonEditFindReplaceHelper Frm = new AvalonEditFindReplaceHelper @@ -206,7 +259,7 @@ namespace FModel FModel_AssetsList.SelectedItem is ListBoxViewModel selectedItem) { bool autoExport = FModel_AssetsList.SelectedItems.Count > 1; - if (!autoExport) Assets.Export(selectedItem.PakEntry, false); // manual export if one + if (!autoExport) Assets.Export(selectedItem.ReaderEntry, false); // manual export if one else { bool ret = Properties.Settings.Default.AutoExport; @@ -375,7 +428,7 @@ namespace FModel { FModel_TabCtrl.SelectedIndex = 1; ExtractStopVm.extractViewModel.IsEnabled = true; - AssetPropertiesVm.assetPropertiesViewModel.Set(selectedItem.PakEntry); + AssetPropertiesVm.assetPropertiesViewModel.Set(selectedItem.ReaderEntry); } else { diff --git a/FModel/PakReader/AESDecryptor.cs b/FModel/PakReader/AESDecryptor.cs index 8967ff93..596a08a7 100644 --- a/FModel/PakReader/AESDecryptor.cs +++ b/FModel/PakReader/AESDecryptor.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Security.Cryptography; -namespace PakReader +namespace FModel.PakReader { static class AESDecryptor { diff --git a/FModel/PakReader/BinaryHelper.cs b/FModel/PakReader/BinaryHelper.cs index c60215c9..0ddb3e53 100644 --- a/FModel/PakReader/BinaryHelper.cs +++ b/FModel/PakReader/BinaryHelper.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Runtime.CompilerServices; -namespace PakReader +namespace FModel.PakReader { static class BinaryHelper { diff --git a/FModel/PakReader/Pak/IO/EIoChunkType.cs b/FModel/PakReader/IO/EIoChunkType.cs similarity index 92% rename from FModel/PakReader/Pak/IO/EIoChunkType.cs rename to FModel/PakReader/IO/EIoChunkType.cs index 3a6ff2bf..bd307b59 100644 --- a/FModel/PakReader/Pak/IO/EIoChunkType.cs +++ b/FModel/PakReader/IO/EIoChunkType.cs @@ -1,4 +1,4 @@ -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { /// /// Addressable chunk types. diff --git a/FModel/PakReader/Pak/IO/EIoContainerFlags.cs b/FModel/PakReader/IO/EIoContainerFlags.cs similarity index 84% rename from FModel/PakReader/Pak/IO/EIoContainerFlags.cs rename to FModel/PakReader/IO/EIoContainerFlags.cs index a2319c23..aace7933 100644 --- a/FModel/PakReader/Pak/IO/EIoContainerFlags.cs +++ b/FModel/PakReader/IO/EIoContainerFlags.cs @@ -1,4 +1,4 @@ -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public enum EIoContainerFlags : byte { diff --git a/FModel/PakReader/IO/FArc.cs b/FModel/PakReader/IO/FArc.cs new file mode 100644 index 00000000..78c51381 --- /dev/null +++ b/FModel/PakReader/IO/FArc.cs @@ -0,0 +1,16 @@ +using System.IO; + +namespace FModel.PakReader.IO +{ + public readonly struct FArc + { + public readonly uint FromNodeIndex; + public readonly uint ToNodeIndex; + + public FArc(BinaryReader reader) + { + FromNodeIndex = reader.ReadUInt32(); + ToNodeIndex = reader.ReadUInt32(); + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FContainerHeader.cs b/FModel/PakReader/IO/FContainerHeader.cs new file mode 100644 index 00000000..964fecbb --- /dev/null +++ b/FModel/PakReader/IO/FContainerHeader.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.IO; + +namespace FModel.PakReader.IO +{ + public class FContainerHeader + { + public readonly FIoContainerId ContainerId; + public readonly uint PackageCount; + public readonly byte[] Names; + public readonly byte[] NameHashes; + public readonly FPackageId[] PackageIds; + public readonly byte[] StoreEntries; + public readonly Dictionary CulturePackageMap; + public readonly (FPackageId source, FPackageId target)[] PackageRedirects; + + public FContainerHeader(BinaryReader reader) + { + ContainerId = new FIoContainerId(reader); + PackageCount = reader.ReadUInt32(); + Names = reader.ReadBytes(reader.ReadInt32()); + NameHashes = reader.ReadBytes(reader.ReadInt32()); + PackageIds = reader.ReadTArray(() => new FPackageId(reader)); + StoreEntries = reader.ReadBytes(reader.ReadInt32()); + var culturePackageMapCount = reader.ReadInt32(); + CulturePackageMap = new Dictionary(culturePackageMapCount); + for (int i = 0; i < culturePackageMapCount; i++) + { + CulturePackageMap.Add( + reader.ReadFString(), + reader.ReadTArray(() => (new FPackageId(reader), new FPackageId(reader)))); + } + + PackageRedirects = reader.ReadTArray(() => (new FPackageId(reader), new FPackageId(reader))); + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FExportBundleEntry.cs b/FModel/PakReader/IO/FExportBundleEntry.cs new file mode 100644 index 00000000..0a461994 --- /dev/null +++ b/FModel/PakReader/IO/FExportBundleEntry.cs @@ -0,0 +1,25 @@ +using System.IO; + +namespace FModel.PakReader.IO +{ + public struct FExportBundleEntry + { + public const int SIZE = 8; + + public uint LocalExportIndex; + public EExportCommandType CommandType; + + public FExportBundleEntry(BinaryReader reader) + { + LocalExportIndex = reader.ReadUInt32(); + CommandType = (EExportCommandType) reader.ReadUInt32(); + } + } + + public enum EExportCommandType + { + ExportCommandType_Create, + ExportCommandType_Serialize, + ExportCommandType_Count + }; +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FExportDesc.cs b/FModel/PakReader/IO/FExportDesc.cs new file mode 100644 index 00000000..06d9cf0f --- /dev/null +++ b/FModel/PakReader/IO/FExportDesc.cs @@ -0,0 +1,16 @@ +using FModel.PakReader.Parsers.Objects; + +namespace FModel.PakReader.IO +{ + public class FExportDesc + { + public FPackageDesc Package = null; + public FName Name; + public FName FullName; + public FPackageObjectIndex OuterIndex; + public FPackageObjectIndex ClassIndex; + public FPackageObjectIndex SuperIndex; + public FPackageObjectIndex TemplateIndex; + public FPackageObjectIndex GlobalImportIndex; + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FExportMapEntry.cs b/FModel/PakReader/IO/FExportMapEntry.cs new file mode 100644 index 00000000..a1afe2ad --- /dev/null +++ b/FModel/PakReader/IO/FExportMapEntry.cs @@ -0,0 +1,37 @@ +using FModel.PakReader.Parsers; +using FModel.PakReader.Parsers.Objects; + +namespace FModel.PakReader.IO +{ + public readonly struct FExportMapEntry + { + public const int SIZE = 72; + + public readonly ulong CookedSerialOffset; + public readonly ulong CookedSerialSize; + public readonly FMappedName ObjectName; + public readonly FPackageObjectIndex OuterIndex; + public readonly FPackageObjectIndex ClassIndex; + public readonly FPackageObjectIndex SuperIndex; + public readonly FPackageObjectIndex TemplateIndex; + public readonly FPackageObjectIndex GlobalImportIndex; + public readonly EObjectFlags ObjectFlags; + public readonly EExportFilterFlags FilterFlags; + + public FExportMapEntry(IoPackageReader reader) + { + CookedSerialOffset = reader.ReadUInt64(); + CookedSerialSize = reader.ReadUInt64(); + ObjectName = new FMappedName(reader); + OuterIndex = new FPackageObjectIndex(reader); + ClassIndex = new FPackageObjectIndex(reader); + SuperIndex = new FPackageObjectIndex(reader); + TemplateIndex = new FPackageObjectIndex(reader); + GlobalImportIndex = new FPackageObjectIndex(reader); + + ObjectFlags = (EObjectFlags) reader.ReadUInt32(); + FilterFlags = (EExportFilterFlags) reader.ReadByte(); + reader.SkipBytes(3); + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/Pak/IO/FFileIoStoreContainerFile.cs b/FModel/PakReader/IO/FFileIoStoreContainerFile.cs similarity index 88% rename from FModel/PakReader/Pak/IO/FFileIoStoreContainerFile.cs rename to FModel/PakReader/IO/FFileIoStoreContainerFile.cs index b023ba0d..2b8a22e0 100644 --- a/FModel/PakReader/Pak/IO/FFileIoStoreContainerFile.cs +++ b/FModel/PakReader/IO/FFileIoStoreContainerFile.cs @@ -1,7 +1,7 @@ using System.IO; -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public struct FFileIoStoreContainerFile { diff --git a/FModel/PakReader/Pak/IO/FFileIoStoreReader.cs b/FModel/PakReader/IO/FFileIoStoreReader.cs similarity index 61% rename from FModel/PakReader/Pak/IO/FFileIoStoreReader.cs rename to FModel/PakReader/IO/FFileIoStoreReader.cs index 82a9fb04..9dfea286 100644 --- a/FModel/PakReader/Pak/IO/FFileIoStoreReader.cs +++ b/FModel/PakReader/IO/FFileIoStoreReader.cs @@ -1,27 +1,34 @@ using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; +using System.Text.RegularExpressions; +using FModel.Logger; +using FModel.PakReader.Parsers; +using FModel.PakReader.Parsers.Objects; using FModel.Utils; using Ionic.Zlib; -using PakReader.Parsers; -using PakReader.Parsers.Objects; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { - public class FFileIoStoreReader + public class FFileIoStoreReader : IReadOnlyDictionary { + public readonly string FileName; public readonly FIoStoreTocResource TocResource; public readonly Dictionary Toc; public readonly FFileIoStoreContainerFile ContainerFile; public readonly FIoContainerId ContainerId; + public bool IsInitialized => Files != null; + private byte[] _aesKey; public byte[] AesKey { get => _aesKey; set { + if (!HasDirectoryIndex) return; if (value != null && !TestAesKey(value)) //if value not null, test but fail, throw not working throw new ArgumentException(string.Format(FModel.Properties.Resources.AesNotWorking, value.ToStringKey(), ContainerFile.FileName)); _aesKey = value; // else, even if value is null, set it @@ -29,22 +36,29 @@ namespace PakReader.Pak.IO } } + public readonly bool CaseSensitive; + + public bool HasDirectoryIndex => TocResource.DirectoryIndexBuffer != null; + public FGuid EncryptionKeyGuid => ContainerFile.EncryptionKeyGuid; public bool IsEncrypted => ContainerFile.ContainerFlags.HasAnyFlags(EIoContainerFlags.Encrypted); - + + public Dictionary Files; public FIoDirectoryIndexResource _directoryIndex; private byte[] _directoryIndexBuffer; - public FFileIoStoreReader(Stream tocStream, Stream containerStream, EIoStoreTocReadOptions tocReadOptions = EIoStoreTocReadOptions.ReadDirectoryIndex) + public FFileIoStoreReader(string fileName, Stream tocStream, Stream containerStream, bool caseSensitive = true, EIoStoreTocReadOptions tocReadOptions = EIoStoreTocReadOptions.ReadDirectoryIndex) { + FileName = fileName; + CaseSensitive = caseSensitive; ContainerFile.FileHandle = containerStream; var tocResource = new FIoStoreTocResource(tocStream, tocReadOptions); TocResource = tocResource; var containerUncompressedSize = tocResource.Header.TocCompressedBlockEntryCount > 0 - ? tocResource.Header.TocCompressedBlockEntryCount * tocResource.Header.CompressionBlockSize - : containerStream.Length; + ? (ulong) tocResource.Header.TocCompressedBlockEntryCount * (ulong) tocResource.Header.CompressionBlockSize + : (ulong) containerStream.Length; Toc = new Dictionary((int) tocResource.Header.TocEntryCount); @@ -79,18 +93,40 @@ namespace PakReader.Pak.IO _directoryIndexBuffer = tocResource.DirectoryIndexBuffer; } - public void ReadIndex() + public bool ReadDirectoryIndex() { - using Stream indexStream = IsEncrypted - ? new MemoryStream(AESDecryptor.DecryptAES(_directoryIndexBuffer, _aesKey)) - : new MemoryStream(_directoryIndexBuffer); - _directoryIndex = new FIoDirectoryIndexResource(indexStream); + try + { + if (HasDirectoryIndex) + { + using Stream indexStream = IsEncrypted + ? new MemoryStream(AESDecryptor.DecryptAES(_directoryIndexBuffer, _aesKey)) + : new MemoryStream(_directoryIndexBuffer); + _directoryIndex = new FIoDirectoryIndexResource(indexStream, CaseSensitive); + + var firstEntry = GetChildDirectory(FIoDirectoryIndexHandle.Root); + + var tempFiles = new Dictionary(); + ReadIndex("", firstEntry, tempFiles); + 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}"); + + return true; + } + } + catch (Exception e) + { + DebugHelper.WriteLine(e.ToString()); + } + return false; } public string MountPoint => _directoryIndex.MountPoint; public bool TestAesKey(byte[] key) { + if (!HasDirectoryIndex) + return false; if (!IsEncrypted) return true; return TestAesKey(_directoryIndexBuffer, key); @@ -122,6 +158,8 @@ namespace PakReader.Pak.IO } } + public bool DoesChunkExist(FIoChunkId chunkId) => Toc.ContainsKey(chunkId); + public byte[] Read(FIoChunkId chunkId) { var offsetAndLength = Toc[chunkId]; @@ -129,16 +167,15 @@ namespace PakReader.Pak.IO var compressionBlockSize = tocResource.Header.CompressionBlockSize; var dst = new byte[offsetAndLength.Length]; var firstBlockIndex = (int) (offsetAndLength.Offset / compressionBlockSize); - var lastBlockIndex = (int) ((BinaryHelper.Align(offsetAndLength.Offset + dst.Length, compressionBlockSize) - 1) / compressionBlockSize); - var offsetInBlock = offsetAndLength.Offset % compressionBlockSize; - - byte[] src; + var lastBlockIndex = (int) ((BinaryHelper.Align((long) offsetAndLength.Offset + dst.Length, compressionBlockSize) - 1) / compressionBlockSize); + var offsetInBlock = (int) offsetAndLength.Offset % compressionBlockSize; var remainingSize = dst.Length; var dstOffset = 0; - for (int blockIndex = firstBlockIndex; blockIndex < lastBlockIndex; blockIndex++) + + for (int blockIndex = firstBlockIndex; blockIndex <= lastBlockIndex; blockIndex++) { var compressionBlock = tocResource.CompressionBlocks[blockIndex]; - + var rawSize = BinaryHelper.Align(compressionBlock.CompressedSize, AESDecryptor.ALIGN); var compressedBuffer = new byte[rawSize]; @@ -153,6 +190,8 @@ namespace PakReader.Pak.IO compressedBuffer = AESDecryptor.DecryptAES(compressedBuffer, _aesKey); } + byte[] src; + if (compressionBlock.CompressionMethodIndex == 0) { src = compressedBuffer; @@ -164,7 +203,7 @@ namespace PakReader.Pak.IO src = uncompressedBuffer; } - var sizeInBlock = (int) Math.Min(compressionBlockSize - offsetInBlock, remainingSize); + var sizeInBlock = (int)Math.Min(compressionBlockSize - offsetInBlock, remainingSize); Buffer.BlockCopy(src, (int) offsetInBlock, dst, dstOffset, sizeInBlock); offsetInBlock = 0; remainingSize -= sizeInBlock; @@ -249,5 +288,111 @@ namespace PakReader.Pak.IO }; compressionStream.Read(outData, 0, outData.Length); } + + private void ReadIndex(string directoryName, FIoDirectoryIndexHandle dir, IDictionary outFiles) + { + + while (dir.IsValid()) + { + var subDirectoryName = string.Concat(directoryName, GetDirectoryName(dir), "/"); + + var file = GetFile(dir); + while (file.IsValid()) + { + var name = GetFileName(file); + var path = string.Concat(subDirectoryName, name); + var data = GetFileData(file); + outFiles[path] = new FIoStoreEntry(this, data, path, CaseSensitive); + file = GetNextFile(file); + } + + ReadIndex(subDirectoryName, GetChildDirectory(dir), outFiles); + + dir = GetNextDirectory(dir); + } + } + + public bool TryGetFile(string path, out ArraySegment ret1, out ArraySegment ret2, out ArraySegment ret3) + { + if (!string.IsNullOrEmpty(path) && Files.TryGetValue(CaseSensitive ? path : path.ToLowerInvariant(), out var entry)) + { + ret1 = entry.GetData(); + if (entry.HasUexp()) + { + ret2 = (entry.Uexp as FIoStoreEntry)?.GetData(); + ret3 = (entry.Ubulk as FIoStoreEntry)?.GetData(); + return true; + } + else // return a fail but keep the uasset data + { + ret2 = null; + ret3 = null; + return false; + } + } + ret1 = null; + ret2 = null; + ret3 = null; + return false; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetPartialKey(string partialKey, out string key) + { + foreach (string path in Files.Keys) + { + if (Regex.Match(path, partialKey, RegexOptions.IgnoreCase).Success) + { + key = path; + return true; + } + } + + key = string.Empty; + return false; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetCaseInsensiteveValue(string key, out FIoStoreEntry value) + { + foreach (var r in Files) + { + if (r.Key.Equals(key, StringComparison.CurrentCultureIgnoreCase)) + { + value = r.Value; + return true; + } + } + value = null; + return false; + } + + public IEnumerator> GetEnumerator() + { + return Files.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable) Files).GetEnumerator(); + } + + public int Count => Files.Count; + + public bool ContainsKey(string key) + { + return Files.ContainsKey(key); + } + + public bool TryGetValue(string key, out FIoStoreEntry value) + { + return Files.TryGetValue(key, out value); + } + + public FIoStoreEntry this[string key] => Files[key]; + + public IEnumerable Keys => Files.Keys; + + public IEnumerable Values => Files.Values; } } \ No newline at end of file diff --git a/FModel/PakReader/IO/FFragment.cs b/FModel/PakReader/IO/FFragment.cs new file mode 100644 index 00000000..e6f3d5d4 --- /dev/null +++ b/FModel/PakReader/IO/FFragment.cs @@ -0,0 +1,26 @@ +namespace FModel.PakReader.IO +{ + public readonly struct FFragment + { + public const uint SkipMax = 127; + public const uint ValueMax = 127; + + public const uint SkipNumMask = 0x007fu; + public const uint HasZeroMask = 0x0080u; + public const int ValueNumShift = 9; + public const uint IsLastMask = 0x0100u; + + public readonly byte SkipNum; // Number of properties to skip before values + public readonly bool HasAnyZeroes; + public readonly byte ValueNum; // Number of subsequent property values stored + public readonly bool IsLast; // Is this the last fragment of the header? + + public FFragment(ushort packed) + { + SkipNum = (byte) (packed & SkipNumMask); + HasAnyZeroes = (packed & HasZeroMask) != 0; + ValueNum = (byte) (packed >> ValueNumShift); + IsLast = (packed & IsLastMask) != 0; + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FImportDesc.cs b/FModel/PakReader/IO/FImportDesc.cs new file mode 100644 index 00000000..4c035d78 --- /dev/null +++ b/FModel/PakReader/IO/FImportDesc.cs @@ -0,0 +1,11 @@ +using FModel.PakReader.Parsers.Objects; + +namespace FModel.PakReader.IO +{ + public class FImportDesc + { + public FName Name; + public FPackageObjectIndex GlobalImportIndex; + public FExportDesc Export; + } +} \ No newline at end of file diff --git a/FModel/PakReader/Pak/IO/FIoChunkHash.cs b/FModel/PakReader/IO/FIoChunkHash.cs similarity index 86% rename from FModel/PakReader/Pak/IO/FIoChunkHash.cs rename to FModel/PakReader/IO/FIoChunkHash.cs index a8b60537..836aacb9 100644 --- a/FModel/PakReader/Pak/IO/FIoChunkHash.cs +++ b/FModel/PakReader/IO/FIoChunkHash.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public struct FIoChunkHash { diff --git a/FModel/PakReader/Pak/IO/FIoChunkId.cs b/FModel/PakReader/IO/FIoChunkId.cs similarity index 51% rename from FModel/PakReader/Pak/IO/FIoChunkId.cs rename to FModel/PakReader/IO/FIoChunkId.cs index 2352442e..0a427c5c 100644 --- a/FModel/PakReader/Pak/IO/FIoChunkId.cs +++ b/FModel/PakReader/IO/FIoChunkId.cs @@ -1,9 +1,8 @@ using System; using System.IO; using System.Linq; -using System.Runtime.CompilerServices; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public readonly struct FIoChunkId { @@ -18,11 +17,18 @@ namespace PakReader.Pak.IO Id = reader.ReadBytes(12); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + public FIoChunkId(ulong chunkId, ushort chunkIndex, EIoChunkType ioChunkType) + { + Id = new byte[12]; + Buffer.BlockCopy(BitConverter.GetBytes(chunkId), 0, Id, 0, sizeof(ulong)); + Buffer.BlockCopy(BitConverter.GetBytes(chunkIndex), 0, Id, sizeof(ulong), sizeof(ushort)); + Id[11] = (byte)ioChunkType; + } + public override int GetHashCode() { var hash = 5381; - for (int i = 0; i < 12; i++) + for (var i = 0; i < 12; i++) { hash = hash * 33 + Id[i]; } @@ -30,18 +36,29 @@ namespace PakReader.Pak.IO return hash; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object? obj) { - if (!(obj is FIoChunkId cast)) return false; + if (!(obj is FIoChunkId cast)) + { + return false; + } + return Id.SequenceEqual(cast.Id); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(FIoChunkId a, FIoChunkId b) => a.Id.SequenceEqual(b.Id); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(FIoChunkId a, FIoChunkId b) => !a.Id.SequenceEqual(b.Id); - - public override string ToString() => BitConverter.ToString(Id).Replace("-",""); + public static bool operator ==(FIoChunkId a, FIoChunkId b) + { + return a.Id.SequenceEqual(b.Id); + } + + public static bool operator !=(FIoChunkId a, FIoChunkId b) + { + return !a.Id.SequenceEqual(b.Id); + } + + public override string ToString() + { + return BitConverter.ToString(Id).Replace("-", ""); + } } } \ No newline at end of file diff --git a/FModel/PakReader/Pak/IO/FIoContainerId.cs b/FModel/PakReader/IO/FIoContainerId.cs similarity index 86% rename from FModel/PakReader/Pak/IO/FIoContainerId.cs rename to FModel/PakReader/IO/FIoContainerId.cs index ce41919d..95109f29 100644 --- a/FModel/PakReader/Pak/IO/FIoContainerId.cs +++ b/FModel/PakReader/IO/FIoContainerId.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public struct FIoContainerId { diff --git a/FModel/PakReader/Pak/IO/FIoDirectoryIndexEntry.cs b/FModel/PakReader/IO/FIoDirectoryIndexEntry.cs similarity index 94% rename from FModel/PakReader/Pak/IO/FIoDirectoryIndexEntry.cs rename to FModel/PakReader/IO/FIoDirectoryIndexEntry.cs index 7abe8f01..81e84a86 100644 --- a/FModel/PakReader/Pak/IO/FIoDirectoryIndexEntry.cs +++ b/FModel/PakReader/IO/FIoDirectoryIndexEntry.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public readonly struct FIoDirectoryIndexEntry { diff --git a/FModel/PakReader/Pak/IO/FIoDirectoryIndexHandle.cs b/FModel/PakReader/IO/FIoDirectoryIndexHandle.cs similarity index 91% rename from FModel/PakReader/Pak/IO/FIoDirectoryIndexHandle.cs rename to FModel/PakReader/IO/FIoDirectoryIndexHandle.cs index 5ec4f972..1708b24f 100644 --- a/FModel/PakReader/Pak/IO/FIoDirectoryIndexHandle.cs +++ b/FModel/PakReader/IO/FIoDirectoryIndexHandle.cs @@ -1,10 +1,11 @@ using System.Runtime.CompilerServices; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public readonly struct FIoDirectoryIndexHandle { public static FIoDirectoryIndexHandle InvalidHandle = new FIoDirectoryIndexHandle(uint.MaxValue); + public static FIoDirectoryIndexHandle Root = new FIoDirectoryIndexHandle(0); private readonly uint _handle; [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/FModel/PakReader/Pak/IO/FIoDirectoryIndexResource.cs b/FModel/PakReader/IO/FIoDirectoryIndexResource.cs similarity index 78% rename from FModel/PakReader/Pak/IO/FIoDirectoryIndexResource.cs rename to FModel/PakReader/IO/FIoDirectoryIndexResource.cs index 159c2c63..3d2db6be 100644 --- a/FModel/PakReader/Pak/IO/FIoDirectoryIndexResource.cs +++ b/FModel/PakReader/IO/FIoDirectoryIndexResource.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public class FIoDirectoryIndexResource { @@ -9,18 +9,22 @@ namespace PakReader.Pak.IO public readonly FIoFileIndexEntry[] FileEntries; public readonly string[] StringTable; - public FIoDirectoryIndexResource(Stream directoryIndexStream) + public FIoDirectoryIndexResource(Stream directoryIndexStream, bool caseSensitive) { using var reader = new BinaryReader(directoryIndexStream); MountPoint = reader.ReadFString(); if (MountPoint.StartsWith("../../..")) { - MountPoint = MountPoint[9..]; + MountPoint = MountPoint[8..]; } else { // Weird mount point location... - MountPoint = ""; + MountPoint = "/"; + } + if (!caseSensitive) + { + MountPoint = MountPoint.ToLowerInvariant(); } DirectoryEntries = reader.ReadTArray(() => new FIoDirectoryIndexEntry(reader)); FileEntries = reader.ReadTArray(() => new FIoFileIndexEntry(reader)); diff --git a/FModel/PakReader/Pak/IO/FIoFileIndexEntry.cs b/FModel/PakReader/IO/FIoFileIndexEntry.cs similarity index 92% rename from FModel/PakReader/Pak/IO/FIoFileIndexEntry.cs rename to FModel/PakReader/IO/FIoFileIndexEntry.cs index 76ccaa53..ee1533c5 100644 --- a/FModel/PakReader/Pak/IO/FIoFileIndexEntry.cs +++ b/FModel/PakReader/IO/FIoFileIndexEntry.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public readonly struct FIoFileIndexEntry { diff --git a/FModel/PakReader/IO/FIoGlobalData.cs b/FModel/PakReader/IO/FIoGlobalData.cs new file mode 100644 index 00000000..014bb8ea --- /dev/null +++ b/FModel/PakReader/IO/FIoGlobalData.cs @@ -0,0 +1,133 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using FModel.PakReader.Parsers.Objects; + +namespace FModel.PakReader.IO +{ + public class FIoGlobalData + { + public readonly FNameEntrySerialized[] GlobalNameMap; + public readonly List GlobalNameHashes; + public readonly Dictionary ScriptObjectByGlobalId; + + public FIoGlobalData(FFileIoStoreReader globalReader, IReadOnlyCollection allReaders) + { + var globalNamesIoBuffer = globalReader.Read(new FIoChunkId(0, 0, EIoChunkType.LoaderGlobalNames)); + var globalNameHashesIoBuffer = globalReader.Read(new FIoChunkId(0, 0, EIoChunkType.LoaderGlobalNameHashes)); + var globalNameMap = new List(); + GlobalNameHashes = new List(); + FNameEntrySerialized.LoadNameBatch(globalNameMap, GlobalNameHashes, globalNamesIoBuffer, globalNameHashesIoBuffer); + GlobalNameMap = globalNameMap.ToArray(); + + var initialLoadIoBuffer = globalReader.Read(new FIoChunkId(0, 0, EIoChunkType.LoaderInitialLoadMeta)); + var initialLoadIoReader = new BinaryReader(new MemoryStream(initialLoadIoBuffer, false)); + var numScriptObjects = initialLoadIoReader.ReadInt32(); + + var scriptObjectByGlobalIdKeys = new FPackageObjectIndex[numScriptObjects]; + var scriptObjectByGlobalIdValues = new FScriptObjectDesc[numScriptObjects]; + var globalIndices = new Dictionary(numScriptObjects); + + for (var i = 0; i < numScriptObjects; i++) + { + var scriptObjectEntry = new FScriptObjectEntry(initialLoadIoReader); + globalIndices.TryAdd(scriptObjectEntry.GlobalIndex, i); + var mappedName = new FMappedName(scriptObjectEntry.ObjectName, GlobalNameMap, null); + + if (!mappedName.IsGlobal()) + { + Debug.WriteLine(i); + } + + scriptObjectByGlobalIdKeys[i] = scriptObjectEntry.GlobalIndex; + scriptObjectByGlobalIdValues[i] = new FScriptObjectDesc(GlobalNameMap[(int)mappedName.GetIndex()], mappedName, scriptObjectEntry); + } + + for (var i = 0; i < numScriptObjects; i++) + { + var scriptObjectDesc = scriptObjectByGlobalIdValues[i]; + + if (!scriptObjectDesc.FullName.IsNone) + { + continue; + } + + var scriptObjectStack = new Stack(); + var current = i; + string fullName = string.Empty; + + while (current > 0) + { + var currentDesc = scriptObjectByGlobalIdValues[current]; + + if (!currentDesc.FullName.IsNone) + { + fullName = currentDesc.FullName.String; + break; + } + + scriptObjectStack.Push(currentDesc); + globalIndices.TryGetValue(currentDesc.OuterIndex, out current); + } + + while (scriptObjectStack.Count != 0) + { + var currentStack = scriptObjectStack.Pop(); + + if (fullName.Length == 0 || fullName.EndsWith('/')) + { + fullName = string.Concat(fullName, currentStack.Name.String); + } + else + { + fullName = string.Concat(fullName, "/", currentStack.Name.String); + } + + currentStack.FullName = new FName(fullName); + } + } + + ScriptObjectByGlobalId = Enumerable.Range(0, numScriptObjects).ToDictionary(i => scriptObjectByGlobalIdKeys[i], i => scriptObjectByGlobalIdValues[i]); + + var packageByPackageIdMap = new Dictionary(); + foreach (var reader in allReaders) + { + var headerChunkId = new FIoChunkId(reader.ContainerId.Id, 0, EIoChunkType.ContainerHeader); + if (reader.DoesChunkExist(headerChunkId) && !reader.IsEncrypted) + { + var buffer = reader.Read(headerChunkId); + using var headerReader = new BinaryReader(new MemoryStream(buffer, false)); + + var containerHeader = new FContainerHeader(headerReader); + + using var storeEntryReader = new BinaryReader(new MemoryStream(containerHeader.StoreEntries)); + + var containerPackages = new List(); + + for (var i = 0; i < containerHeader.PackageCount; i++) + { + var containerEntry = new FPackageStoreEntry(storeEntryReader); + + var packageId = containerHeader.PackageIds[i]; + if (!packageByPackageIdMap.TryGetValue(packageId, out var packageDesc)) + { + /* + packageDesc = new FPackageDesc(); + packageDesc.PackageId = packageId; + packageDesc.Size = containerEntry.ExportBundlesSize; + packageDesc.Exports = new FExportDesc[containerEntry.ExportCount]; + packageDesc.ExportBundleCount = containerEntry.ExportBundleCount; + packageDesc.LoadOrder = containerEntry.LoadOrder; + */ + packageByPackageIdMap[packageId] = containerEntry; + } + //containerPackages.Add(packageDesc); + } + + + } + } + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FIoOffsetAndLength.cs b/FModel/PakReader/IO/FIoOffsetAndLength.cs new file mode 100644 index 00000000..568e7b2a --- /dev/null +++ b/FModel/PakReader/IO/FIoOffsetAndLength.cs @@ -0,0 +1,26 @@ +using System.IO; + +namespace FModel.PakReader.IO +{ + public readonly struct FIoOffsetAndLength + { + // We use 5 bytes for offset and size, this is enough to represent + // an offset and size of 1PB + public readonly byte[] OffsetAndLength; + public ulong Offset => OffsetAndLength[4] + | ((ulong) OffsetAndLength[3] << 8) + | ((ulong) OffsetAndLength[2] << 16) + | ((ulong) OffsetAndLength[1] << 24) + | ((ulong) OffsetAndLength[0] << 32); + public ulong Length => OffsetAndLength[9] + | ((ulong) OffsetAndLength[8] << 8) + | ((ulong) OffsetAndLength[7] << 16) + | ((ulong) OffsetAndLength[6] << 24) + | ((ulong) OffsetAndLength[5] << 32); + + public FIoOffsetAndLength(BinaryReader reader) + { + OffsetAndLength = reader.ReadBytes(5 + 5); + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FIoStoreEntry.cs b/FModel/PakReader/IO/FIoStoreEntry.cs new file mode 100644 index 00000000..de84f420 --- /dev/null +++ b/FModel/PakReader/IO/FIoStoreEntry.cs @@ -0,0 +1,28 @@ +namespace FModel.PakReader.IO +{ + public class FIoStoreEntry : ReaderEntry + { + public readonly FFileIoStoreReader ioStore; + public override string ContainerName => ioStore.FileName; + public override string Name { get; } + public readonly uint UserData; + + 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 FIoStoreEntry(FFileIoStoreReader ioStore, uint userData, string name, bool caseSensitive) + { + this.ioStore = ioStore; + UserData = userData; + if (!caseSensitive) + name = name.ToLowerInvariant(); + if (name.StartsWith('/')) + name = name.Substring(1); + Name = name; + } + + public byte[] GetData() => ioStore.Read(ChunkId); + } +} \ No newline at end of file diff --git a/FModel/PakReader/Pak/IO/FIoStoreTocCompressedBlockEntry.cs b/FModel/PakReader/IO/FIoStoreTocCompressedBlockEntry.cs similarity index 98% rename from FModel/PakReader/Pak/IO/FIoStoreTocCompressedBlockEntry.cs rename to FModel/PakReader/IO/FIoStoreTocCompressedBlockEntry.cs index eb01d933..d2a04825 100644 --- a/FModel/PakReader/Pak/IO/FIoStoreTocCompressedBlockEntry.cs +++ b/FModel/PakReader/IO/FIoStoreTocCompressedBlockEntry.cs @@ -1,7 +1,7 @@ using System.IO; using System.Runtime.CompilerServices; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public readonly struct FIoStoreTocCompressedBlockEntry { diff --git a/FModel/PakReader/Pak/IO/FIoStoreTocEntryMeta.cs b/FModel/PakReader/IO/FIoStoreTocEntryMeta.cs similarity index 93% rename from FModel/PakReader/Pak/IO/FIoStoreTocEntryMeta.cs rename to FModel/PakReader/IO/FIoStoreTocEntryMeta.cs index 08e1ff85..58834425 100644 --- a/FModel/PakReader/Pak/IO/FIoStoreTocEntryMeta.cs +++ b/FModel/PakReader/IO/FIoStoreTocEntryMeta.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public readonly struct FIoStoreTocEntryMeta { diff --git a/FModel/PakReader/Pak/IO/FIoStoreTocEntryMetaFlags.cs b/FModel/PakReader/IO/FIoStoreTocEntryMetaFlags.cs similarity index 80% rename from FModel/PakReader/Pak/IO/FIoStoreTocEntryMetaFlags.cs rename to FModel/PakReader/IO/FIoStoreTocEntryMetaFlags.cs index cf4566c0..bc50b9f4 100644 --- a/FModel/PakReader/Pak/IO/FIoStoreTocEntryMetaFlags.cs +++ b/FModel/PakReader/IO/FIoStoreTocEntryMetaFlags.cs @@ -1,4 +1,4 @@ -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public enum FIoStoreTocEntryMetaFlags : byte { diff --git a/FModel/PakReader/Pak/IO/FIoStoreTocHeader.cs b/FModel/PakReader/IO/FIoStoreTocHeader.cs similarity index 96% rename from FModel/PakReader/Pak/IO/FIoStoreTocHeader.cs rename to FModel/PakReader/IO/FIoStoreTocHeader.cs index 582abb6a..838c141c 100644 --- a/FModel/PakReader/Pak/IO/FIoStoreTocHeader.cs +++ b/FModel/PakReader/IO/FIoStoreTocHeader.cs @@ -1,8 +1,8 @@ using System.IO; using System.Linq; -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public enum EIoStoreTocVersion : byte { diff --git a/FModel/PakReader/Pak/IO/FIoStoreTocResource.cs b/FModel/PakReader/IO/FIoStoreTocResource.cs similarity index 96% rename from FModel/PakReader/Pak/IO/FIoStoreTocResource.cs rename to FModel/PakReader/IO/FIoStoreTocResource.cs index 1c2a20db..72eac823 100644 --- a/FModel/PakReader/Pak/IO/FIoStoreTocResource.cs +++ b/FModel/PakReader/IO/FIoStoreTocResource.cs @@ -1,11 +1,9 @@ -using System; -using System.Collections.Generic; -using System.IO; +using System.IO; using System.Text; +using FModel.PakReader.Parsers.Objects; using FModel.Utils; -using PakReader.Parsers.Objects; -namespace PakReader.Pak.IO +namespace FModel.PakReader.IO { public enum EIoStoreTocReadOptions { @@ -87,7 +85,7 @@ namespace PakReader.Pak.IO ChunkBlockSignatures[i] = new FSHAHash(reader); } - // You could very hashes here but nah + // You could verify hashes here but nah } // Directory index diff --git a/FModel/PakReader/IO/FIterator.cs b/FModel/PakReader/IO/FIterator.cs new file mode 100644 index 00000000..632eac7f --- /dev/null +++ b/FModel/PakReader/IO/FIterator.cs @@ -0,0 +1,74 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; + +namespace FModel.PakReader.IO +{ + public class FIterator : IEnumerator<(int Val, bool IsNonZero)> + { + private int _schemaIt; + private readonly BitArray _zeroMask; + private int _zeroMaskIndex; + private readonly IEnumerator _fragmentIt; + + private int _remainingFragmentValues; + + public FIterator(FUnversionedHeader header) + { + _zeroMask = header.ZeroMask; + _fragmentIt = header.Fragments.GetEnumerator(); + Skip(); + } + + public bool MoveNext() + { + _schemaIt++; + _remainingFragmentValues--; + if (_fragmentIt.Current.HasAnyZeroes) + _zeroMaskIndex++; + + if (_remainingFragmentValues == 0) + { + if (_fragmentIt.Current.IsLast) + return false; + + _fragmentIt.MoveNext(); + Skip(); + } + return true; + } + + private void Skip() + { + _schemaIt += _fragmentIt.Current.SkipNum; + + while (_fragmentIt.Current.ValueNum == 0) + { + if (_fragmentIt.Current.IsLast) + throw new FileLoadException("Cannot receive last fragment in Skip()"); + _fragmentIt.MoveNext(); + _schemaIt += _fragmentIt.Current.SkipNum; + } + + _remainingFragmentValues = _fragmentIt.Current.ValueNum; + } + + public void Reset() + { + _schemaIt = _zeroMaskIndex = _remainingFragmentValues = 0; + _fragmentIt.Reset(); + Skip(); + } + + public bool IsNonZero => !_fragmentIt.Current.HasAnyZeroes || !_zeroMask[_zeroMaskIndex]; + + public (int Val, bool IsNonZero) Current => (_schemaIt, IsNonZero); + + object IEnumerator.Current => Current; + + public void Dispose() + { + _fragmentIt.Dispose(); + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FMappedName.cs b/FModel/PakReader/IO/FMappedName.cs new file mode 100644 index 00000000..5819fea4 --- /dev/null +++ b/FModel/PakReader/IO/FMappedName.cs @@ -0,0 +1,71 @@ +using FModel.PakReader.Parsers; +using FModel.PakReader.Parsers.Objects; + +namespace FModel.PakReader.IO +{ + public readonly struct FMappedName + { + public const uint InvalidIndex = ~0u; + public const uint IndexBits = 30u; + public const uint IndexMask = (1u << (int)IndexBits) - 1u; + public const uint TypeMask = ~IndexMask; + public const uint TypeShift = IndexBits; + + private readonly IoPackageReader _reader; + + private readonly FNameEntrySerialized[] _globalNameMap => + _reader != null ? _reader.GlobalData.GlobalNameMap : __globalNameMap; + private readonly FNameEntrySerialized[] __globalNameMap; + private readonly FNameEntrySerialized[] _localNameMap => + _reader != null ? _reader.NameMap : __localNameMap; + private readonly FNameEntrySerialized[] __localNameMap; + + public readonly uint Index; + public readonly uint Number; + + public string String + { + get + { + var index = GetIndex(); + var nameMap = IsGlobal() ? _globalNameMap : _localNameMap; + if (nameMap != null && index < _globalNameMap.Length) + { + return nameMap[index].Name; + } + + return null; + } + } + + public FMappedName(IoPackageReader reader) + { + Index = reader.ReadUInt32(); + Number = reader.ReadUInt32(); + _reader = reader; + __globalNameMap = null; + __localNameMap = null; + } + + public FMappedName(FMinimalName minimalName, FNameEntrySerialized[] globalNameMap, FNameEntrySerialized[] localNameMap) + { + Index = minimalName.Index.Value; + Number = (uint)minimalName.Number; + _reader = null; + __globalNameMap = globalNameMap; + __localNameMap = localNameMap; + } + + public uint GetIndex() + { + return Index & IndexMask; + } + + public bool IsGlobal() + { + return (Index & TypeMask) >> (int)TypeShift != 0; + } + + public override string ToString() => String; + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FMinimalName.cs b/FModel/PakReader/IO/FMinimalName.cs new file mode 100644 index 00000000..aa50af6a --- /dev/null +++ b/FModel/PakReader/IO/FMinimalName.cs @@ -0,0 +1,22 @@ +using System.IO; + +namespace FModel.PakReader.IO +{ + public readonly struct FMinimalName + { + public readonly FNameEntryId Index; + public readonly int Number; // #define NAME_NO_NUMBER_INTERNAL 0 + + public FMinimalName(BinaryReader reader) + { + Index = new FNameEntryId(reader); + Number = reader.ReadInt32(); + } + + public FMinimalName(FNameEntryId inIndex, int inNumber) + { + Index = inIndex; + Number = inNumber; + } + } +} diff --git a/FModel/PakReader/IO/FNameEntryId.cs b/FModel/PakReader/IO/FNameEntryId.cs new file mode 100644 index 00000000..8be4c397 --- /dev/null +++ b/FModel/PakReader/IO/FNameEntryId.cs @@ -0,0 +1,45 @@ +using System; +using System.IO; + +namespace FModel.PakReader.IO +{ + public readonly struct FNameEntryId : IEquatable + { + public readonly uint Value; + + public FNameEntryId(uint value) + { + Value = value; + } + + public FNameEntryId(BinaryReader reader) + { + Value = reader.ReadUInt32(); + } + + public bool Equals(FNameEntryId other) + { + return Value == other.Value; + } + + public override bool Equals(object obj) + { + return obj is FNameEntryId other && Equals(other); + } + + public override int GetHashCode() + { + return (int)Value; + } + + public static bool operator ==(FNameEntryId left, FNameEntryId right) + { + return left.Equals(right); + } + + public static bool operator !=(FNameEntryId left, FNameEntryId right) + { + return !left.Equals(right); + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FPackageDesc.cs b/FModel/PakReader/IO/FPackageDesc.cs new file mode 100644 index 00000000..a46eec80 --- /dev/null +++ b/FModel/PakReader/IO/FPackageDesc.cs @@ -0,0 +1,18 @@ +using FModel.PakReader.Parsers.Objects; + +namespace FModel.PakReader.IO +{ + public class FPackageDesc + { + public FPackageId PackageId; + public FName PackageName; + public ulong Size = 0; + public uint LoadOrder = uint.MaxValue; + public uint PackageFlags = 0; + public int NameCount = -1; + public int ExportBundleCount = -1; + public FPackageLocation[] Locations; + public FImportDesc[] Imports; + public FExportDesc[] Exports; + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FPackageId.cs b/FModel/PakReader/IO/FPackageId.cs new file mode 100644 index 00000000..804ead5a --- /dev/null +++ b/FModel/PakReader/IO/FPackageId.cs @@ -0,0 +1,21 @@ +using System.IO; + +namespace FModel.PakReader.IO +{ + public readonly struct FPackageId + { + public readonly ulong Id; + + public FPackageId(ulong id) + { + Id = id; + } + + public FPackageId(BinaryReader reader) + { + Id = reader.ReadUInt64(); + } + + public FIoChunkId CreateIoChunkId(ushort chunkIndex, EIoChunkType type = EIoChunkType.ExportBundleData) => new FIoChunkId(Id, chunkIndex, type); + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FPackageLocation.cs b/FModel/PakReader/IO/FPackageLocation.cs new file mode 100644 index 00000000..6fcb909a --- /dev/null +++ b/FModel/PakReader/IO/FPackageLocation.cs @@ -0,0 +1,10 @@ +using FModel.PakReader.Parsers.Objects; + +namespace FModel.PakReader.IO +{ + public readonly struct FPackageLocation + { + public readonly FName ContainerName; + public readonly ulong Offset; + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FPackageObjectIndex.cs b/FModel/PakReader/IO/FPackageObjectIndex.cs new file mode 100644 index 00000000..d6bcef31 --- /dev/null +++ b/FModel/PakReader/IO/FPackageObjectIndex.cs @@ -0,0 +1,71 @@ +using System; +using System.IO; + +namespace FModel.PakReader.IO +{ + public readonly struct FPackageObjectIndex : IEquatable + { + public const int IndexBits = 62; + public const ulong IndexMask = (1UL << IndexBits) - 1UL; + public const ulong TypeMask = ~IndexMask; + public const int TypeShift = IndexBits; + public const ulong Invalid = ~0UL; + + + private readonly ulong _typeAndId; + public EType Type => (EType) (_typeAndId >> TypeShift); + public ulong Value => _typeAndId & IndexMask; + + public bool IsNull => _typeAndId == Invalid; + public bool IsExport => Type == EType.Export; + public bool IsImport => IsScriptImport || IsPackageImport; + public bool IsScriptImport => Type == EType.ScriptImport; + public bool IsPackageImport => Type == EType.PackageImport; + public uint AsExport => (uint) _typeAndId; + + public FPackageObjectIndex(BinaryReader reader) + { + //TypeAndId = Invalid; + _typeAndId = reader.ReadUInt64(); + } + + public FPackageObjectIndex(ulong typeAndId) + { + _typeAndId = typeAndId; + } + + public bool Equals(FPackageObjectIndex other) + { + return _typeAndId == other._typeAndId; + } + + public override bool Equals(object obj) + { + return obj is FPackageObjectIndex other && Equals(other); + } + + public override int GetHashCode() + { + return _typeAndId.GetHashCode(); + } + + public static bool operator ==(FPackageObjectIndex left, FPackageObjectIndex right) + { + return left.Equals(right); + } + + public static bool operator !=(FPackageObjectIndex left, FPackageObjectIndex right) + { + return !left.Equals(right); + } + } + + public enum EType + { + Export, + ScriptImport, + PackageImport, + Null, + TypeCount = Null + }; +} diff --git a/FModel/PakReader/IO/FPackageStoreEntry.cs b/FModel/PakReader/IO/FPackageStoreEntry.cs new file mode 100644 index 00000000..c43c66f0 --- /dev/null +++ b/FModel/PakReader/IO/FPackageStoreEntry.cs @@ -0,0 +1,36 @@ +using System.IO; + +namespace FModel.PakReader.IO +{ + public readonly struct FPackageStoreEntry + { + public readonly ulong ExportBundlesSize; + public readonly int ExportCount; + public readonly int ExportBundleCount; + public readonly uint LoadOrder; + public readonly FPackageId[] ImportedPackages; + + + public FPackageStoreEntry(BinaryReader reader) + { + ExportBundlesSize = reader.ReadUInt64(); + ExportCount = reader.ReadInt32(); + ExportBundleCount = reader.ReadInt32(); + LoadOrder = reader.ReadUInt32(); + reader.BaseStream.Position += 4; // Padding + + var pos = reader.BaseStream.Position; + var packageStoreArrayNum = reader.ReadInt32(); + var packageStoreOffsetToData = reader.ReadUInt32(); + reader.BaseStream.Position = pos + packageStoreOffsetToData; + ImportedPackages = new FPackageId[packageStoreArrayNum]; + + for (var i = 0; i < packageStoreArrayNum; i++) + { + ImportedPackages[i] = new FPackageId(reader); + } + + reader.BaseStream.Position = pos + 8; + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FPackageSummary.cs b/FModel/PakReader/IO/FPackageSummary.cs new file mode 100644 index 00000000..2f8bd94e --- /dev/null +++ b/FModel/PakReader/IO/FPackageSummary.cs @@ -0,0 +1,39 @@ +using FModel.PakReader.Parsers; + +namespace FModel.PakReader.IO +{ + public class FPackageSummary + { + public readonly FMappedName Name; + public readonly FMappedName SourceName; + public readonly uint PackageFlags; + public readonly uint CookedHeaderSize; + public readonly int NameMapNamesOffset; + public readonly int NameMapNamesSize; + public readonly int NameMapHashesOffset; + public readonly int NameMapHashesSize; + public readonly int ImportMapOffset; + public readonly int ExportMapOffset; + public readonly int ExportBundlesOffset; + public readonly int GraphDataOffset; + public readonly int GraphDataSize; + + public FPackageSummary(IoPackageReader reader) + { + Name = new FMappedName(reader); + SourceName = new FMappedName(reader); + PackageFlags = reader.ReadUInt32(); + CookedHeaderSize = reader.ReadUInt32(); + NameMapNamesOffset = reader.ReadInt32(); + NameMapNamesSize = reader.ReadInt32(); + NameMapHashesOffset = reader.ReadInt32(); + NameMapHashesSize = reader.ReadInt32(); + ImportMapOffset = reader.ReadInt32(); + ExportMapOffset = reader.ReadInt32(); + ExportBundlesOffset = reader.ReadInt32(); + GraphDataOffset = reader.ReadInt32(); + GraphDataSize = reader.ReadInt32(); + reader.SkipBytes(4); // Padding + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FScriptObjectDesc.cs b/FModel/PakReader/IO/FScriptObjectDesc.cs new file mode 100644 index 00000000..bac8e489 --- /dev/null +++ b/FModel/PakReader/IO/FScriptObjectDesc.cs @@ -0,0 +1,20 @@ +using FModel.PakReader.Parsers.Objects; + +namespace FModel.PakReader.IO +{ + public class FScriptObjectDesc + { + public readonly FName Name; + public FName FullName; + public readonly FPackageObjectIndex GlobalImportIndex; + public readonly FPackageObjectIndex OuterIndex; + + public FScriptObjectDesc(FNameEntrySerialized name, FMappedName fMappedName, FScriptObjectEntry fScriptObjectEntry) + { + Name = new FName(name.Name, (int)fMappedName.Index, (int)fMappedName.Number); + FullName = default; + GlobalImportIndex = fScriptObjectEntry.GlobalIndex; + OuterIndex = fScriptObjectEntry.OuterIndex; + } + } +} diff --git a/FModel/PakReader/IO/FScriptObjectEntry.cs b/FModel/PakReader/IO/FScriptObjectEntry.cs new file mode 100644 index 00000000..429fb1c8 --- /dev/null +++ b/FModel/PakReader/IO/FScriptObjectEntry.cs @@ -0,0 +1,20 @@ +using System.IO; + +namespace FModel.PakReader.IO +{ + public readonly struct FScriptObjectEntry + { + public readonly FMinimalName ObjectName; + public readonly FPackageObjectIndex GlobalIndex; + public readonly FPackageObjectIndex OuterIndex; + public readonly FPackageObjectIndex CDOClassIndex; + + public FScriptObjectEntry(BinaryReader reader) + { + ObjectName = new FMinimalName(reader); + GlobalIndex = new FPackageObjectIndex(reader); + OuterIndex = new FPackageObjectIndex(reader); + CDOClassIndex = new FPackageObjectIndex(reader); + } + } +} diff --git a/FModel/PakReader/IO/FSerializedNameHeader.cs b/FModel/PakReader/IO/FSerializedNameHeader.cs new file mode 100644 index 00000000..60ce507c --- /dev/null +++ b/FModel/PakReader/IO/FSerializedNameHeader.cs @@ -0,0 +1,17 @@ +using System.IO; + +namespace FModel.PakReader.IO +{ + public readonly struct FSerializedNameHeader + { + private readonly byte[] _data; + + public bool IsUtf16 => (_data[0] & 0x80u) != 0; + public uint Length => ((_data[0] & 0x7Fu) << 8) + _data[1]; + + public FSerializedNameHeader(BinaryReader reader) + { + _data = reader.ReadBytes(2); + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/FUnversionedHeader.cs b/FModel/PakReader/IO/FUnversionedHeader.cs new file mode 100644 index 00000000..aae487d4 --- /dev/null +++ b/FModel/PakReader/IO/FUnversionedHeader.cs @@ -0,0 +1,65 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using FModel.Utils; + +namespace FModel.PakReader.IO +{ + public class FUnversionedHeader + { + public List Fragments = new List(); + public BitArray ZeroMask; + public readonly bool HasNonZeroValues; + public bool HasValues => HasNonZeroValues | (ZeroMask.Count > 0); + + public FUnversionedHeader(BinaryReader reader) + { + FFragment fragment; + int zeroMaskNum = 0; + uint unmaskedNum = 0; + do + { + fragment = new FFragment(reader.ReadUInt16()); + + Fragments.Add(fragment); + if (fragment.HasAnyZeroes) + zeroMaskNum += fragment.ValueNum; + else + unmaskedNum += fragment.ValueNum; + } while (!fragment.IsLast); + + if (zeroMaskNum > 0) + { + LoadZeroMaskData(reader, zeroMaskNum, out ZeroMask); + HasNonZeroValues = unmaskedNum > 0 || ZeroMask.Contains(false); + } + else + { + ZeroMask = new BitArray(new int[8]); + HasNonZeroValues = unmaskedNum > 0; + } + } + + private static void LoadZeroMaskData(BinaryReader reader, int numBits, out BitArray data) + { + if (numBits <= 8) + { + data = new BitArray(new[] { reader.ReadByte() }); + } + else if (numBits <= 16) + { + data = new BitArray(new []{ (int) reader.ReadUInt16() }); + } + else + { + var num = numBits.DivideAndRoundUp(32); + var intData = new int[num]; + for (int idx = 0; idx < num; idx++) + { + intData[idx] = reader.ReadInt32(); + } + data = new BitArray(intData); + } + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/IoPackage.cs b/FModel/PakReader/IO/IoPackage.cs new file mode 100644 index 00000000..26c51f47 --- /dev/null +++ b/FModel/PakReader/IO/IoPackage.cs @@ -0,0 +1,74 @@ +using System.IO; +using FModel.PakReader.Parsers; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using Newtonsoft.Json; + +namespace FModel.PakReader.IO +{ + public class IoPackage : Package + { + private byte[] UAsset; + private byte[] UBulk; + private FIoStoreEntry _entry; + private IoPackageReader _reader; + private string _jsonData = null; + + internal IoPackage(byte[] asset, byte[] bulk, FIoStoreEntry entry) + { + UAsset = asset; + UBulk = bulk; + _entry = entry; + } + + public IoPackageReader Reader + { + get + { + if (_reader == null) + { + var asset = new MemoryStream(UAsset); + var bulk = UBulk != null ? new MemoryStream(UBulk) : null; + asset.Position = 0; + if (bulk != null) + bulk.Position = 0; + + return _reader = new IoPackageReader(asset, bulk, Globals.GlobalData, _entry.ioStore, true); + } + + return _reader; + } + } + + public override string JsonData + { + get + { + if (string.IsNullOrEmpty(_jsonData)) + { + var ret = new JsonExport[Exports.Length]; + for (int i = 0; i < ret.Length; i++) + { + ret[i] = new JsonExport + { + ExportType = ExportTypes[i].String, + ExportValue = (FModel.EJsonType)FModel.Properties.Settings.Default.AssetsJsonType switch + { + FModel.EJsonType.Default => Exports[i].GetJsonDict(), + _ => Exports[i] + } + }; + } +#if DEBUG + return JsonConvert.SerializeObject(ret, Formatting.Indented); +#else + return _jsonData = JsonConvert.SerializeObject(ret, Formatting.Indented); +#endif + } + return _jsonData; + } + } + public override FName[] ExportTypes => Reader.DataExportTypes; + public override IUExport[] Exports => Reader.DataExports; + } +} \ No newline at end of file diff --git a/FModel/PakReader/IO/PropertyInfo.cs b/FModel/PakReader/IO/PropertyInfo.cs new file mode 100644 index 00000000..3e2b43bd --- /dev/null +++ b/FModel/PakReader/IO/PropertyInfo.cs @@ -0,0 +1,31 @@ +using Newtonsoft.Json; + +namespace FModel.PakReader.IO +{ + public class PropertyInfo + { + public string Name; + public string Type; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string StructType; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public bool? Bool; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string EnumName; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string InnerType; + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string ValueType; + + public PropertyInfo(string name, string type, string structType = null, bool? b = null, string enumName = null, string innerType = null, string valueType = null) + { + Name = name; + Type = type; + StructType = structType; + Bool = b; + EnumName = enumName; + InnerType = innerType; + ValueType = valueType; + } + } +} \ No newline at end of file diff --git a/FModel/PakReader/LocMetaReader.cs b/FModel/PakReader/LocMetaReader.cs index 70ca684f..664aeb95 100644 --- a/FModel/PakReader/LocMetaReader.cs +++ b/FModel/PakReader/LocMetaReader.cs @@ -1,7 +1,7 @@ using System.IO; -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader +namespace FModel.PakReader { public class LocMetaReader { diff --git a/FModel/PakReader/LocResReader.cs b/FModel/PakReader/LocResReader.cs index 64d8808d..12360740 100644 --- a/FModel/PakReader/LocResReader.cs +++ b/FModel/PakReader/LocResReader.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.IO; -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader +namespace FModel.PakReader { public class LocResReader { diff --git a/FModel/PakReader/Package.cs b/FModel/PakReader/Package.cs new file mode 100644 index 00000000..5e89ad9f --- /dev/null +++ b/FModel/PakReader/Package.cs @@ -0,0 +1,64 @@ +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; + +namespace FModel.PakReader +{ + public abstract class Package + { + public abstract string JsonData { get; } + public abstract FName[] ExportTypes { get; } + public abstract IUExport[] Exports { get; } + + public T GetExport() where T : IUExport + { + var exports = Exports; + for (int i = 0; i < exports.Length; i++) + { + if (exports[i] is T) + return (T)exports[i]; + } + return default; + } + public T GetIndexedExport(int index) where T : IUExport + { + var exports = Exports; + var foundCount = 0; + for (var i = 0; i < exports.Length; i++) + { + if (exports[i] is T cast) + { + if (foundCount == index) + return cast; + foundCount++; + } + } + return default; + } + public T GetTypedExport(string exportType) where T : IUExport + { + int index = 0; + var exportTypes = ExportTypes; + for (int i = 0; i < exportTypes.Length; i++) + { + if (exportTypes[i].String == exportType) + index = i; + } + return (T)Exports[index]; + } + + public bool HasExport() => Exports != default; + } + + public sealed class ExportList + { + public string JsonData; + public FName[] ExportTypes; + public IUExport[] Exports; + } + + public sealed class JsonExport + { + public string ExportType; + public object ExportValue; + } +} \ No newline at end of file diff --git a/FModel/PakReader/Pak/DefaultPakFilter.cs b/FModel/PakReader/Pak/DefaultPakFilter.cs index 35e96ea7..1bda2c62 100644 --- a/FModel/PakReader/Pak/DefaultPakFilter.cs +++ b/FModel/PakReader/Pak/DefaultPakFilter.cs @@ -1,4 +1,4 @@ -namespace PakReader.Pak +namespace FModel.PakReader.Pak { class DefaultPakFilter : IPakFilter { diff --git a/FModel/PakReader/Pak/IO/FIoOffsetAndLength.cs b/FModel/PakReader/Pak/IO/FIoOffsetAndLength.cs deleted file mode 100644 index a4ecad84..00000000 --- a/FModel/PakReader/Pak/IO/FIoOffsetAndLength.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.IO; - -namespace PakReader.Pak.IO -{ - public readonly struct FIoOffsetAndLength - { - // We use 5 bytes for offset and size, this is enough to represent - // an offset and size of 1PB - public readonly byte[] OffsetAndLength; - public long Offset => OffsetAndLength[4] - | ((long) OffsetAndLength[3] << 8) - | ((long) OffsetAndLength[2] << 16) - | ((long) OffsetAndLength[1] << 24) - | ((long) OffsetAndLength[0] << 32); - public long Length => OffsetAndLength[9] - | ((long) OffsetAndLength[8] << 8) - | ((long) OffsetAndLength[7] << 16) - | ((long) OffsetAndLength[6] << 24) - | ((long) OffsetAndLength[5] << 32); - - public FIoOffsetAndLength(BinaryReader reader) - { - OffsetAndLength = reader.ReadBytes(5 + 5); - } - } -} \ No newline at end of file diff --git a/FModel/PakReader/Pak/IPakFilter.cs b/FModel/PakReader/Pak/IPakFilter.cs index d45859d8..320a2ca4 100644 --- a/FModel/PakReader/Pak/IPakFilter.cs +++ b/FModel/PakReader/Pak/IPakFilter.cs @@ -1,4 +1,4 @@ -namespace PakReader.Pak +namespace FModel.PakReader.Pak { public interface IPakFilter { diff --git a/FModel/PakReader/Pak/PakFileReader.cs b/FModel/PakReader/Pak/PakFileReader.cs index c7c21f55..ae08bf9c 100644 --- a/FModel/PakReader/Pak/PakFileReader.cs +++ b/FModel/PakReader/Pak/PakFileReader.cs @@ -8,9 +8,8 @@ using System.Text.RegularExpressions; using FModel.Logger; using FModel.PakReader.Parsers.Objects; using FModel.Utils; -using PakReader.Parsers.Objects; -namespace PakReader.Pak +namespace FModel.PakReader.Pak { public sealed class PakFileReader : IReadOnlyDictionary { @@ -42,7 +41,7 @@ namespace PakReader.Pak // Buffered streams increase performance dramatically public PakFileReader(string file, bool caseSensitive = true) - : this(file, new BufferedStream(new FileInfo(file).Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite)), caseSensitive) + : this(file, new FileInfo(file).Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite), caseSensitive) { } public PakFileReader(string path, Stream stream, bool caseSensitive = true) @@ -446,15 +445,15 @@ namespace PakReader.Pak ret1 = entry.GetData(Stream, AesKey, Info.CompressionMethods); if (entry.HasUexp()) { - ret2 = entry.Uexp.GetData(Stream, AesKey, Info.CompressionMethods); - ret3 = entry.HasUbulk() ? entry.Ubulk.GetData(Stream, AesKey, Info.CompressionMethods) : null; + ret2 = ((FPakEntry)entry.Uexp).GetData(Stream, AesKey, Info.CompressionMethods); + ret3 = entry.HasUbulk() ? ((FPakEntry)entry.Ubulk).GetData(Stream, AesKey, Info.CompressionMethods) : null; return true; } else // return a fail but keep the uasset data { ret2 = null; ret3 = null; - return false; + return entry.GetExtension().Contains(".ufont", StringComparison.OrdinalIgnoreCase); } } ret1 = null; diff --git a/FModel/PakReader/Pak/PakFilter.cs b/FModel/PakReader/Pak/PakFilter.cs index 26b1d3cc..f5181b9c 100644 --- a/FModel/PakReader/Pak/PakFilter.cs +++ b/FModel/PakReader/Pak/PakFilter.cs @@ -1,7 +1,7 @@ using System.Collections; using System.Collections.Generic; -namespace PakReader.Pak +namespace FModel.PakReader.Pak { // Currently only supports strings that start with a value // I've just implemented this myself to save tons of memory so you don't have to diff --git a/FModel/PakReader/Pak/PakIndex.cs b/FModel/PakReader/Pak/PakIndex.cs index fbf63e23..319104ca 100644 --- a/FModel/PakReader/Pak/PakIndex.cs +++ b/FModel/PakReader/Pak/PakIndex.cs @@ -2,9 +2,9 @@ using System.Collections; using System.Collections.Generic; using System.IO; -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Pak +namespace FModel.PakReader.Pak { public class PakIndex : IEnumerable { diff --git a/FModel/PakReader/Pak/PakPackage.cs b/FModel/PakReader/Pak/PakPackage.cs index c5731ddc..ca521b1e 100644 --- a/FModel/PakReader/Pak/PakPackage.cs +++ b/FModel/PakReader/Pak/PakPackage.cs @@ -1,19 +1,27 @@ using System; using System.IO; +using FModel.PakReader.Parsers; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; using Newtonsoft.Json; -using PakReader.Parsers; -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; -namespace PakReader.Pak +namespace FModel.PakReader.Pak { - public readonly struct PakPackage + public sealed class PakPackage : Package { readonly ArraySegment UAsset; readonly ArraySegment UExp; readonly ArraySegment UBulk; + + internal PakPackage(ArraySegment asset, ArraySegment exp, ArraySegment bulk) + { + UAsset = asset; + UExp = exp; + UBulk = bulk; + exports = new ExportList(); + } - public string JsonData + public override string JsonData { get { @@ -37,7 +45,7 @@ namespace PakReader.Pak return exports.JsonData; } } - public FName[] ExportTypes + public override FName[] ExportTypes { get { @@ -51,14 +59,14 @@ namespace PakReader.Pak if (bulk != null) bulk.Position = 0; - var p = new PackageReader(asset, exp, bulk); + var p = new LegacyPackageReader(asset, exp, bulk); exports.Exports = p.DataExports; return exports.ExportTypes = p.DataExportTypes; } return exports.ExportTypes; } } - public IUExport[] Exports + public override IUExport[] Exports { get { @@ -72,74 +80,17 @@ namespace PakReader.Pak if (bulk != null) bulk.Position = 0; - var p = new PackageReader(asset, exp, bulk); + var p = new LegacyPackageReader(asset, exp, bulk); exports.ExportTypes = p.DataExportTypes; return exports.Exports = p.DataExports; } return exports.Exports; } } - readonly ExportList exports; + private readonly ExportList exports; - internal PakPackage(ArraySegment asset, ArraySegment exp, ArraySegment bulk) - { - UAsset = asset; - UExp = exp; - UBulk = bulk; - exports = new ExportList(); - } - - public T GetExport() where T : IUExport - { - var exports = Exports; - for (int i = 0; i < exports.Length; i++) - { - if (exports[i] is T) - return (T)exports[i]; - } - return default; - } - public T GetIndexedExport(int index) where T : IUExport - { - var exports = Exports; - int foundCount = 0; - for (int i = 0; i < exports.Length; i++) - { - if (exports[i] is T) - { - if (foundCount == index) - return (T)exports[i]; - foundCount++; - } - } - return default; - } - public T GetTypedExport(string exportType) where T : IUExport - { - int index = 0; - var exportTypes = ExportTypes; - for (int i = 0; i < exportTypes.Length; i++) - { - if (exportTypes[i].String == exportType) - index = i; - } - return (T)Exports[index]; - } - - public bool HasExport() => exports != null; // hacky way to get the package to be a readonly struct, essentially a double pointer i guess - sealed class ExportList - { - public string JsonData; - public FName[] ExportTypes; - public IUExport[] Exports; - } - - sealed class JsonExport - { - public string ExportType; - public object ExportValue; - } + } } diff --git a/FModel/PakReader/Parsers/Class/IUExport.cs b/FModel/PakReader/Parsers/Class/IUExport.cs index cf6687b1..a24059c3 100644 --- a/FModel/PakReader/Parsers/Class/IUExport.cs +++ b/FModel/PakReader/Parsers/Class/IUExport.cs @@ -1,8 +1,8 @@ -using PakReader.Parsers.PropertyTagData; -using System.Collections.Generic; +using System.Collections.Generic; using System.Runtime.CompilerServices; +using FModel.PakReader.Parsers.PropertyTagData; -namespace PakReader.Parsers.Class +namespace FModel.PakReader.Parsers.Class { /// /// IReadOnlyDictionary is only used to be able to iterate over properties diff --git a/FModel/PakReader/Parsers/Class/UAkMediaAssetData.cs b/FModel/PakReader/Parsers/Class/UAkMediaAssetData.cs index 94312972..d7badc4d 100644 --- a/FModel/PakReader/Parsers/Class/UAkMediaAssetData.cs +++ b/FModel/PakReader/Parsers/Class/UAkMediaAssetData.cs @@ -1,9 +1,9 @@ -using PakReader.Parsers.Objects; -using System; +using System; using System.IO; using System.Linq; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.Class +namespace FModel.PakReader.Parsers.Class { public sealed class UAkMediaAssetData : UObject { diff --git a/FModel/PakReader/Parsers/Class/UCurveTable.cs b/FModel/PakReader/Parsers/Class/UCurveTable.cs index 7296db5e..de3840ed 100644 --- a/FModel/PakReader/Parsers/Class/UCurveTable.cs +++ b/FModel/PakReader/Parsers/Class/UCurveTable.cs @@ -1,18 +1,21 @@ -using PakReader.Parsers.Objects; -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.Class +namespace FModel.PakReader.Parsers.Class { public sealed class UCurveTable : IUExport { public ECurveTableMode CurveTableMode { get; } readonly Dictionary RowMap; - + internal UCurveTable(PackageReader reader) { - _ = new UObject(reader); //will break + if (!(reader is IoPackageReader)) + { + _ = new UObject(reader); //will break + } int NumRows = reader.ReadInt32(); CurveTableMode = (ECurveTableMode)reader.ReadByte(); diff --git a/FModel/PakReader/Parsers/Class/UDataTable.cs b/FModel/PakReader/Parsers/Class/UDataTable.cs index 07d7ac74..83f6abef 100644 --- a/FModel/PakReader/Parsers/Class/UDataTable.cs +++ b/FModel/PakReader/Parsers/Class/UDataTable.cs @@ -3,12 +3,16 @@ using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; -namespace PakReader.Parsers.Class +using FModel.PakReader.IO; +using FModel.PakReader.Parsers.PropertyTagData; +using FModel.Utils; + +namespace FModel.PakReader.Parsers.Class { public sealed class UDataTable : IUExport { /** Map of name of row to row data structure. */ - readonly Dictionary RowMap; + private readonly Dictionary RowMap; internal UDataTable(PackageReader reader) { @@ -30,6 +34,55 @@ namespace PakReader.Parsers.Class } } + internal UDataTable(IoPackageReader reader, IReadOnlyDictionary properties, string type) + { + var baseObj = new UObject(reader, properties, type: type); + + if (!baseObj.TryGetValue("RowStruct", out var rowStructProp) || !(rowStructProp is ObjectProperty rowStruct) || !rowStruct.Value.IsImport) + { + return; + } + + var rowStructimportIndex = rowStruct.Value.AsImport; + + if (rowStructimportIndex >= reader.ImportMap.Length) + { + return; + } + + var rowStructimport = reader.ImportMap[rowStructimportIndex]; + + if (rowStructimport.Type != EType.ScriptImport || + !Globals.GlobalData.ScriptObjectByGlobalId.TryGetValue(rowStructimport, out var rowStrucDesc) || + rowStrucDesc.Name.IsNone) + { + return; + } + + if (!Globals.TypeMappings.TryGetValue(rowStrucDesc.Name.String, out var rowProperties)) + { + FConsole.AppendText($"{reader.Summary.Name.String} can't be parsed yet (RowType: {rowStrucDesc.Name.String})", FColors.Red, true); + return; + } + + var NumRows = reader.ReadInt32(); + RowMap = new Dictionary(); + + for (var i = 0; i < NumRows; i++) + { + var num = 1; + var RowName = reader.ReadFName().String ?? ""; + var baseName = RowName; + + while (RowMap.ContainsKey(RowName)) + { + RowName = $"{baseName}_NK{num++:00}"; + } + + RowMap[RowName] = new UObject(reader, rowProperties, true, rowStrucDesc.Name.String); + } + } + public object this[string key] => RowMap[key]; public IEnumerable Keys => RowMap.Keys; public IEnumerable Values => RowMap.Values; diff --git a/FModel/PakReader/Parsers/Class/UFontFace.cs b/FModel/PakReader/Parsers/Class/UFontFace.cs index cc7e4f46..42908bfe 100644 --- a/FModel/PakReader/Parsers/Class/UFontFace.cs +++ b/FModel/PakReader/Parsers/Class/UFontFace.cs @@ -1,10 +1,10 @@ -using PakReader.Parsers.PropertyTagData; -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; +using FModel.PakReader.Parsers.PropertyTagData; -namespace PakReader.Parsers.Class +namespace FModel.PakReader.Parsers.Class { public sealed class UFontFace : IUExport { @@ -14,18 +14,16 @@ namespace PakReader.Parsers.Class internal UFontFace(PackageReader reader, Stream ufont) { FontFaceAsset = new UObject(reader, true); - foreach (KeyValuePair prop in FontFaceAsset) - { - if (prop.Key.Equals("SourceFilename") && prop.Value is StrProperty str) - { - string FontFilename = Path.GetFileName(str.Value); - string folder = FModel.Properties.Settings.Default.OutputPath + "\\Fonts\\"; - if (ufont != null) - { - using var fileStream = new FileStream(folder + FontFilename, FileMode.Create, FileAccess.Write); - ufont.CopyTo(fileStream); - } + if (FontFaceAsset.TryGetValue("SourceFilename", out var prop) && prop is StrProperty str) + { + string FontFilename = Path.GetFileName(str.Value); + string folder = Properties.Settings.Default.OutputPath + "\\Fonts\\"; + + if (ufont != null) + { + using var fileStream = new FileStream(folder + FontFilename, FileMode.Create, FileAccess.Write); + ufont.CopyTo(fileStream); } } } diff --git a/FModel/PakReader/Parsers/Class/UObject.cs b/FModel/PakReader/Parsers/Class/UObject.cs index f0f3a1ff..03dd3928 100644 --- a/FModel/PakReader/Parsers/Class/UObject.cs +++ b/FModel/PakReader/Parsers/Class/UObject.cs @@ -1,24 +1,101 @@ using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; +using FModel.Logger; +using FModel.PakReader.IO; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; +using FModel.Utils; -namespace PakReader.Parsers.Class +namespace FModel.PakReader.Parsers.Class { public class UObject : IUExport, IUStruct { - readonly Dictionary Dict; + private readonly Dictionary Dict; + + public UObject(IoPackageReader reader, IReadOnlyDictionary properties, bool structFallback = false, string type = null) + { + Dict = new Dictionary(); + var header = new FUnversionedHeader(reader); + using var it = new FIterator(header); + +#if DEBUG + + var headerWritten = false; + + do + { + if (properties.ContainsKey(it.Current.Val)) + { + continue; + } + + if (!headerWritten) + { + headerWritten = true; + FConsole.AppendText(string.Concat("\n", type ?? "Unknown", ": ", reader.Summary.Name.String), "#CA6C6C", true); + } + + FConsole.AppendText($"Val: {it.Current.Val} (IsNonZero: {it.Current.IsNonZero})", FColors.Yellow, true); + } + while (it.MoveNext()); + it.Reset(); +#endif + + var num = 1; + + do + { + var (val, isNonZero) = it.Current; + if (properties.TryGetValue(val, out var propertyInfo)) + { + if (isNonZero) + { + var obj = BaseProperty.ReadAsObject(reader, new FPropertyTag(propertyInfo), new FName(propertyInfo.Type), ReadType.NORMAL); + var key = Dict.ContainsKey(propertyInfo.Name) ? $"{propertyInfo.Name}_NK{num++:00}" : propertyInfo.Name; + Dict[key] = obj; + } + else + { + var obj = BaseProperty.ReadAsZeroObject(reader, new FPropertyTag(propertyInfo), + new FName(propertyInfo.Type)); + var key = Dict.ContainsKey(propertyInfo.Name) ? $"{propertyInfo.Name}_NK{num++:00}" : propertyInfo.Name; + Dict[key] = obj; + } + } + else + { + if (!isNonZero) + { + // We are lucky: We don't know this property but it also has no content + DebugHelper.WriteLine($"Unknown property for {GetType().Name} with value {val} but it's zero so we are good"); + } + else + { + DebugHelper.WriteLine($"Unknown property for {GetType().Name} with value {val}. Can't proceed serialization (Serialized {Dict.Count} properties till now)"); + return; + //throw new FileLoadException($"Unknown property for {GetType().Name} with value {val}. Can't proceed serialization"); + } + } + } while (it.MoveNext()); + if (!structFallback && reader.ReadInt32() != 0/* && reader.Position + 16 <= maxSize*/) + { + new FGuid(reader); + } + } + + // Empty UObject used for new package format when a property is zero + public UObject() + { + Dict = new Dictionary(); + } // https://github.com/EpicGames/UnrealEngine/blob/bf95c2cbc703123e08ab54e3ceccdd47e48d224a/Engine/Source/Runtime/CoreUObject/Private/UObject/Class.cpp#L930 - public UObject(PackageReader reader) : this(reader, reader.ExportMap.Sum(e => e.SerialSize), false) { } - public UObject(PackageReader reader, bool structFallback) : this(reader, reader.ExportMap.Sum(e => e.SerialSize), structFallback) { } - public UObject(PackageReader reader, long maxSize) : this(reader, maxSize, false) { } + public UObject(PackageReader reader) : this(reader, false) { } // Structs that don't use binary serialization // https://github.com/EpicGames/UnrealEngine/blob/7d9919ac7bfd80b7483012eab342cb427d60e8c9/Engine/Source/Runtime/CoreUObject/Private/UObject/Class.cpp#L2197 - internal UObject(PackageReader reader, long maxSize, bool structFallback) + internal UObject(PackageReader reader, bool structFallback) { var properties = new Dictionary(); int num = 1; @@ -46,7 +123,7 @@ namespace PakReader.Parsers.Class } Dict = properties; - if (!structFallback && reader.ReadInt32() != 0 && reader.Position + 16 <= maxSize) + if (!structFallback && reader.ReadInt32() != 0/* && reader.Position + 16 <= maxSize*/) { new FGuid(reader); } diff --git a/FModel/PakReader/Parsers/Class/USoundWave.cs b/FModel/PakReader/Parsers/Class/USoundWave.cs index d457bca8..21c1dd9f 100644 --- a/FModel/PakReader/Parsers/Class/USoundWave.cs +++ b/FModel/PakReader/Parsers/Class/USoundWave.cs @@ -1,10 +1,12 @@ -using PakReader.Parsers.Objects; -using PakReader.Parsers.PropertyTagData; -using System; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; +using FModel.PakReader.IO; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.PropertyTagData; -namespace PakReader.Parsers.Class +namespace FModel.PakReader.Parsers.Class { public sealed class USoundWave : UObject { @@ -51,7 +53,18 @@ namespace PakReader.Parsers.Class } } + internal USoundWave(IoPackageReader reader, Dictionary properties, Stream ubulk, + long ubulkOffset) : base(reader, properties) + { + Serialize(reader, ubulk, ubulkOffset); + } + internal USoundWave(PackageReader reader, Stream ubulk, long ubulkOffset) : base(reader) + { + Serialize(reader, ubulk, ubulkOffset); + } + + private void Serialize(PackageReader reader, Stream ubulk, long ubulkOffset) { // if UE4.25+ && Windows -> True bStreaming = FModel.Globals.Game.Version >= EPakVersion.PATH_HASH_INDEX; diff --git a/FModel/PakReader/Parsers/Class/UStringTable.cs b/FModel/PakReader/Parsers/Class/UStringTable.cs index 3118b079..a6b44dd5 100644 --- a/FModel/PakReader/Parsers/Class/UStringTable.cs +++ b/FModel/PakReader/Parsers/Class/UStringTable.cs @@ -1,9 +1,9 @@ -using PakReader.Parsers.Objects; -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.Class +namespace FModel.PakReader.Parsers.Class { public sealed class UStringTable : IUExport { diff --git a/FModel/PakReader/Parsers/Class/UTexture2D.cs b/FModel/PakReader/Parsers/Class/UTexture2D.cs index f7862d4d..fdcb46d9 100644 --- a/FModel/PakReader/Parsers/Class/UTexture2D.cs +++ b/FModel/PakReader/Parsers/Class/UTexture2D.cs @@ -1,14 +1,15 @@ using System.Collections.Generic; using System.IO; -using PakReader.Parsers.Objects; -using PakReader.Textures; +using FModel.PakReader.IO; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Textures; using SkiaSharp; -namespace PakReader.Parsers.Class +namespace FModel.PakReader.Parsers.Class { public sealed class UTexture2D : UObject { - public FTexturePlatformData[] PlatformDatas { get; } + public FTexturePlatformData[] PlatformDatas { get; private set; } SKImage image; public SKImage Image @@ -49,7 +50,17 @@ namespace PakReader.Parsers.Class } } + internal UTexture2D(IoPackageReader reader, Dictionary properties, Stream ubulk, + long bulkOffset) : base(reader, properties) + { + Serialize(reader, ubulk, bulkOffset); + } internal UTexture2D(PackageReader reader, Stream ubulk, long bulkOffset) : base(reader) + { + Serialize(reader, ubulk, bulkOffset); + } + + private void Serialize(PackageReader reader, Stream ubulk, long bulkOffset) { new FStripDataFlags(reader); // and I quote, "still no idea" new FStripDataFlags(reader); // "why there are two" :) diff --git a/FModel/PakReader/Parsers/IoPackageReader.cs b/FModel/PakReader/Parsers/IoPackageReader.cs new file mode 100644 index 00000000..1f4f34ad --- /dev/null +++ b/FModel/PakReader/Parsers/IoPackageReader.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using FModel.PakReader.IO; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; +using FModel.Utils; + +namespace FModel.PakReader.Parsers +{ + public sealed class IoPackageReader : PackageReader + { + public readonly FIoGlobalData GlobalData; + public readonly FPackageSummary Summary; + public readonly FPackageObjectIndex[] ImportMap; + public readonly FExportMapEntry[] ExportMap; + + internal List FakeImportMap; + + public override FNameEntrySerialized[] NameMap { get; } + + private IUExport[] _dataExports; + private Stream _ubulk; + public override IUExport[] DataExports { + get + { + if (_dataExports == null) + ReadContent(); + return _dataExports; + } + } + + private FName[] _dataExportTypes; + public override FName[] DataExportTypes + { + get + { + if (_dataExportTypes == null) + ReadContent(); + return _dataExportTypes; + } + } + + private Dictionary _importMappings; + + public IoPackageReader(Stream uasset, Stream ubulk, FIoGlobalData globalData, FFileIoStoreReader reader, bool onlyInfo = false) : this(new BinaryReader(uasset), + ubulk, globalData, reader, onlyInfo) { } + public IoPackageReader(BinaryReader uasset, Stream ubulk, FIoGlobalData globalData, FFileIoStoreReader reader, bool onlyInfo = false) + { + Loader = uasset; + _ubulk = ubulk; + GlobalData = globalData; + Summary = new FPackageSummary(this); + + var nameMap = new List(); + var nameHashes = new List(); + if (Summary.NameMapNamesSize > 0) + { + Loader.BaseStream.Position = Summary.NameMapNamesOffset; + var nameMapNames = Loader.ReadBytes(Summary.NameMapNamesSize); + Loader.BaseStream.Position = Summary.NameMapHashesOffset; + var nameMapHashes = Loader.ReadBytes(Summary.NameMapHashesSize); + + FNameEntrySerialized.LoadNameBatch(nameMap, nameHashes, nameMapNames, nameMapHashes); + } + + NameMap = nameMap.ToArray(); + + Loader.BaseStream.Position = Summary.ImportMapOffset; + var importMapCount = (Summary.ExportMapOffset - Summary.ImportMapOffset) / /*sizeof(FPackageObjectIndex)*/ sizeof(ulong); + ImportMap = new FPackageObjectIndex[importMapCount]; + for (int i = 0; i < importMapCount; i++) + { + ImportMap[i] = new FPackageObjectIndex(Loader); + } + + Loader.BaseStream.Position = Summary.ExportMapOffset; + var exportMapCount = (Summary.ExportBundlesOffset - Summary.ExportMapOffset) / FExportMapEntry.SIZE; + ExportMap = new FExportMapEntry[exportMapCount]; + for (int i = 0; i < exportMapCount; i++) + { + ExportMap[i] = new FExportMapEntry(this); + } + + if (!onlyInfo) + ReadContent(); + } + + private void ReadContent() + { + Loader.BaseStream.Position = Summary.GraphDataOffset; + var referencedPackagesCount = Loader.ReadInt32(); + var graphData = new (FPackageId importedPackageId, FArc[] arcs)[referencedPackagesCount]; + _importMappings = new Dictionary(referencedPackagesCount); + FakeImportMap = new List(); + for (int i = 0; i < ImportMap.Length; i++) + FakeImportMap.Add(new FObjectResource(new FName(), new FPackageIndex())); + for (int i = 0; i < referencedPackagesCount; i++) + { + var importedPackageId = new FPackageId(Loader); + var arcs = Loader.ReadTArray(() => new FArc(Loader)); + graphData[i] = (importedPackageId, arcs); + var importedPackageName = Creator.Utils.GetFullPath(importedPackageId) + ?.Replace($"{Folders.GetGameName()}/Content", "Game"); + var package = Creator.Utils.GetPropertyPakPackage(importedPackageName) as IoPackage; + if (package == null) continue; + 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); + } + } + + var beginExportOffset = Summary.GraphDataOffset + Summary.GraphDataSize; + var currentExportDataOffset = beginExportOffset; + _dataExports = new IUExport[ExportMap.Length]; + _dataExportTypes = new FName[ExportMap.Length]; + for (var i = 0; i < ExportMap.Length; i++) + { + var exportMapEntry = ExportMap[i]; + FName exportType; + + if (GlobalData != null && GlobalData.ScriptObjectByGlobalId.TryGetValue(exportMapEntry.ClassIndex, out var scriptObject)) + { + exportType = scriptObject.Name; + } + else + { + exportType = new FName("Unknown"); + } + + Loader.BaseStream.Position = currentExportDataOffset; + + if (Globals.TypeMappings.TryGetValue(exportType.String, out var properties)) + { + _dataExports[i] = exportType.String switch + { + "Texture2D" => new UTexture2D(this, properties, _ubulk, + ExportMap.Sum(e => (long) e.CookedSerialSize) + beginExportOffset), + "VirtualTexture2D" => new UTexture2D(this, properties, _ubulk, ExportMap.Sum(e => (long) e.CookedSerialSize) + beginExportOffset), + //"CurveTable" => new UCurveTable(this), + "DataTable" => new UDataTable(this, properties, exportType.String), + //"FontFace" => new UFontFace(this, ubulk), + "SoundWave" => new USoundWave(this, properties, _ubulk, ExportMap.Sum(e => (long) e.CookedSerialSize) + beginExportOffset), + //"StringTable" => new UStringTable(this), + //"AkMediaAssetData" => new UAkMediaAssetData(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), + _ => new UObject(this, properties, type: exportType.String), + }; + _dataExportTypes[i] = exportType; + } + else + { +#if DEBUG + var header = new FUnversionedHeader(this); + using var it = new FIterator(header); + + FConsole.AppendText(string.Concat("\n", exportType.String, ": ", Summary.Name.String), "#CA6C6C", true); + + do + { + FConsole.AppendText($"Val: {it.Current.Val} (IsNonZero: {it.Current.IsNonZero})", FColors.Yellow, true); + } + while (it.MoveNext()); +#endif + } + currentExportDataOffset += (int) exportMapEntry.CookedSerialSize; + } + } + + public override string ToString() => Summary.Name.String; + } +} \ No newline at end of file diff --git a/FModel/PakReader/Parsers/LegacyPackageReader.cs b/FModel/PakReader/Parsers/LegacyPackageReader.cs new file mode 100644 index 00000000..3fdfbe91 --- /dev/null +++ b/FModel/PakReader/Parsers/LegacyPackageReader.cs @@ -0,0 +1,123 @@ +using System; +using System.IO; +using System.Linq; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; + +namespace FModel.PakReader.Parsers +{ + public sealed class LegacyPackageReader : PackageReader + { + public FPackageFileSummary PackageFileSummary { get; } + public FObjectImport[] ImportMap { get; } + public FObjectExport[] ExportMap { get; } + + public override FNameEntrySerialized[] NameMap { get; } + + public override IUExport[] DataExports { get; } + public override FName[] DataExportTypes { get; } + + public LegacyPackageReader(string uasset, string uexp, string ubulk) : this(File.OpenRead(uasset), File.OpenRead(uexp), File.Exists(ubulk) ? File.OpenRead(ubulk) : null) { } + public LegacyPackageReader(Stream uasset, Stream uexp, Stream ubulk) : this(new BinaryReader(uasset), new BinaryReader(uexp), ubulk) { } + + LegacyPackageReader(BinaryReader uasset, BinaryReader uexp, Stream ubulk) + { + Loader = uasset; + PackageFileSummary = new FPackageFileSummary(Loader); + + NameMap = SerializeNameMap(); + ImportMap = SerializeImportMap(); + ExportMap = SerializeExportMap(); + DataExports = new IUExport[ExportMap.Length]; + DataExportTypes = new FName[ExportMap.Length]; + Loader = uexp; + for(int i = 0; i < ExportMap.Length; i++) + { + FObjectExport Export = ExportMap[i]; + { + FName ExportType; + if (Export.ClassIndex.IsNull) + ExportType = DataExportTypes[i] = ReadFName(); // check if this is true, I don't know if Fortnite ever uses this + else if (Export.ClassIndex.IsExport) + ExportType = DataExportTypes[i] = ExportMap[Export.ClassIndex.AsExport].SuperIndex.Resource.ObjectName; + else if (Export.ClassIndex.IsImport) + ExportType = DataExportTypes[i] = ImportMap[Export.ClassIndex.AsImport].ObjectName; + else + throw new FileLoadException("Can't get class name"); // Shouldn't reach this unless the laws of math have bent to MagmaReef's will + + var pos = Position = Export.SerialOffset - PackageFileSummary.TotalHeaderSize; + DataExports[i] = ExportType.String switch + { + "Texture2D" => new UTexture2D(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), + "VirtualTexture2D" => new UTexture2D(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), + "CurveTable" => new UCurveTable(this), + "DataTable" => new UDataTable(this), + "FontFace" => new UFontFace(this, ubulk), + "SoundWave" => new USoundWave(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), + "StringTable" => new UStringTable(this), + "AkMediaAssetData" => new UAkMediaAssetData(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), + _ => new UObject(this), + }; + +#if DEBUG + if (pos + Export.SerialSize != Position) + { + System.Diagnostics.Debug.WriteLine($"[ExportType={ExportType.String}] Didn't read {Export.ObjectName} correctly (at {Position}, should be {pos + Export.SerialSize}, {pos + Export.SerialSize - Position} behind)"); + } +#endif + } + } + return; + } + + FNameEntrySerialized[] SerializeNameMap() + { + if (PackageFileSummary.NameCount > 0) + { + Loader.BaseStream.Position = PackageFileSummary.NameOffset; + + var OutNameMap = new FNameEntrySerialized[PackageFileSummary.NameCount]; + for (int NameMapIdx = 0; NameMapIdx < PackageFileSummary.NameCount; ++NameMapIdx) + { + // Read the name entry from the file. + OutNameMap[NameMapIdx] = new FNameEntrySerialized(Loader); + } + return OutNameMap; + } + return Array.Empty(); + } + + FObjectImport[] SerializeImportMap() + { + if (PackageFileSummary.ImportCount > 0) + { + Loader.BaseStream.Position = PackageFileSummary.ImportOffset; + + var OutImportMap = new FObjectImport[PackageFileSummary.ImportCount]; + for (int ImportMapIdx = 0; ImportMapIdx < PackageFileSummary.ImportCount; ++ImportMapIdx) + { + OutImportMap[ImportMapIdx] = new FObjectImport(this); + } + return OutImportMap; + } + return Array.Empty(); + } + + FObjectExport[] SerializeExportMap() + { + if (PackageFileSummary.ExportCount > 0) + { + Loader.BaseStream.Position = PackageFileSummary.ExportOffset; + + var OutExportMap = new FObjectExport[PackageFileSummary.ExportCount]; + for (int ExportMapIdx = 0; ExportMapIdx < PackageFileSummary.ExportCount; ++ExportMapIdx) + { + OutExportMap[ExportMapIdx] = new FObjectExport(this); + } + return OutExportMap; + } + return Array.Empty(); + } + + } +} diff --git a/FModel/PakReader/Parsers/Objects/EAnimationCompressionFormat.cs b/FModel/PakReader/Parsers/Objects/EAnimationCompressionFormat.cs index be2adda0..abc7dd79 100644 --- a/FModel/PakReader/Parsers/Objects/EAnimationCompressionFormat.cs +++ b/FModel/PakReader/Parsers/Objects/EAnimationCompressionFormat.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EAnimationCompressionFormat { diff --git a/FModel/PakReader/Parsers/Objects/EAnimationKeyFormat.cs b/FModel/PakReader/Parsers/Objects/EAnimationKeyFormat.cs index 7f685078..721af95f 100644 --- a/FModel/PakReader/Parsers/Objects/EAnimationKeyFormat.cs +++ b/FModel/PakReader/Parsers/Objects/EAnimationKeyFormat.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EAnimationKeyFormat : byte { diff --git a/FModel/PakReader/Parsers/Objects/EAssetRegistryDependencyType.cs b/FModel/PakReader/Parsers/Objects/EAssetRegistryDependencyType.cs index 744a0dea..035714e5 100644 --- a/FModel/PakReader/Parsers/Objects/EAssetRegistryDependencyType.cs +++ b/FModel/PakReader/Parsers/Objects/EAssetRegistryDependencyType.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EAssetRegistryDependencyType { diff --git a/FModel/PakReader/Parsers/Objects/EBulkDataFlags.cs b/FModel/PakReader/Parsers/Objects/EBulkDataFlags.cs index 4d075664..766c6925 100644 --- a/FModel/PakReader/Parsers/Objects/EBulkDataFlags.cs +++ b/FModel/PakReader/Parsers/Objects/EBulkDataFlags.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** * Flags serialized with the bulk data. diff --git a/FModel/PakReader/Parsers/Objects/ECompressionFlags.cs b/FModel/PakReader/Parsers/Objects/ECompressionFlags.cs index 6a0f072c..1bb39aca 100644 --- a/FModel/PakReader/Parsers/Objects/ECompressionFlags.cs +++ b/FModel/PakReader/Parsers/Objects/ECompressionFlags.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** * Flags controlling [de]compression diff --git a/FModel/PakReader/Parsers/Objects/ECurveTableMode.cs b/FModel/PakReader/Parsers/Objects/ECurveTableMode.cs index 800a3ad0..8662f7b6 100644 --- a/FModel/PakReader/Parsers/Objects/ECurveTableMode.cs +++ b/FModel/PakReader/Parsers/Objects/ECurveTableMode.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** * Whether the curve table contains simple, rich, or no curves diff --git a/FModel/PakReader/Parsers/Objects/EDateTimeStyle.cs b/FModel/PakReader/Parsers/Objects/EDateTimeStyle.cs index b44de2d4..12db5319 100644 --- a/FModel/PakReader/Parsers/Objects/EDateTimeStyle.cs +++ b/FModel/PakReader/Parsers/Objects/EDateTimeStyle.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EDateTimeStyle : byte { diff --git a/FModel/PakReader/Parsers/Objects/EDecompressionType.cs b/FModel/PakReader/Parsers/Objects/EDecompressionType.cs index 9d88f9e1..3ea5e184 100644 --- a/FModel/PakReader/Parsers/Objects/EDecompressionType.cs +++ b/FModel/PakReader/Parsers/Objects/EDecompressionType.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EDecompressionType { diff --git a/FModel/PakReader/Parsers/Objects/EExportFilterFlags.cs b/FModel/PakReader/Parsers/Objects/EExportFilterFlags.cs new file mode 100644 index 00000000..2d1f4b5a --- /dev/null +++ b/FModel/PakReader/Parsers/Objects/EExportFilterFlags.cs @@ -0,0 +1,9 @@ +namespace FModel.PakReader.Parsers.Objects +{ + public enum EExportFilterFlags : byte + { + None, + NotForClient, + NotForServer + } +} \ No newline at end of file diff --git a/FModel/PakReader/Parsers/Objects/EExpressionType.cs b/FModel/PakReader/Parsers/Objects/EExpressionType.cs index 9f3fbec4..b1a78f7b 100644 --- a/FModel/PakReader/Parsers/Objects/EExpressionType.cs +++ b/FModel/PakReader/Parsers/Objects/EExpressionType.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EExpressionType { diff --git a/FModel/PakReader/Parsers/Objects/EFormatArgumentType.cs b/FModel/PakReader/Parsers/Objects/EFormatArgumentType.cs index d0485fc8..c5c06e97 100644 --- a/FModel/PakReader/Parsers/Objects/EFormatArgumentType.cs +++ b/FModel/PakReader/Parsers/Objects/EFormatArgumentType.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EFormatArgumentType { diff --git a/FModel/PakReader/Parsers/Objects/EInitializationMode.cs b/FModel/PakReader/Parsers/Objects/EInitializationMode.cs index 3f330c9c..56d3cfe4 100644 --- a/FModel/PakReader/Parsers/Objects/EInitializationMode.cs +++ b/FModel/PakReader/Parsers/Objects/EInitializationMode.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** * Enum controlling how we initialize this state diff --git a/FModel/PakReader/Parsers/Objects/ELightingBuildQuality.cs b/FModel/PakReader/Parsers/Objects/ELightingBuildQuality.cs index fca145a9..d0f837ff 100644 --- a/FModel/PakReader/Parsers/Objects/ELightingBuildQuality.cs +++ b/FModel/PakReader/Parsers/Objects/ELightingBuildQuality.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum ELightingBuildQuality { diff --git a/FModel/PakReader/Parsers/Objects/EObjectFlags.cs b/FModel/PakReader/Parsers/Objects/EObjectFlags.cs index ae99ae1a..378a20e1 100644 --- a/FModel/PakReader/Parsers/Objects/EObjectFlags.cs +++ b/FModel/PakReader/Parsers/Objects/EObjectFlags.cs @@ -1,8 +1,11 @@ -namespace PakReader.Parsers.Objects +using System; + +namespace FModel.PakReader.Parsers.Objects { /** * Flags describing an object instance */ + [Flags] public enum EObjectFlags : uint { // Do not add new flags unless they truly belong here. There are alternatives. @@ -45,6 +48,7 @@ RF_NonPIEDuplicateTransient = 0x02000000, ///< Object should not be included for duplication unless it's being duplicated for a PIE session RF_Dynamic = 0x04000000, ///< Field Only. Dynamic field - doesn't get constructed during static initialization, can be constructed multiple times RF_WillBeLoaded = 0x08000000, ///< This object was constructed during load and will be loaded shortly + RF_HasExternalPackage =0x10000000, ///< This object has an external package assigned and should look it up when getting the outermost package // Extra defines RF_Load = RF_Public | RF_Standalone | RF_Transactional | RF_ClassDefaultObject | RF_ArchetypeObject | RF_DefaultSubObject | RF_TextExportTransient | RF_InheritableComponentTemplate | RF_DuplicateTransient | RF_NonPIEDuplicateTransient, diff --git a/FModel/PakReader/Parsers/Objects/EPackageFlags.cs b/FModel/PakReader/Parsers/Objects/EPackageFlags.cs index 5716b27b..231285fb 100644 --- a/FModel/PakReader/Parsers/Objects/EPackageFlags.cs +++ b/FModel/PakReader/Parsers/Objects/EPackageFlags.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EPackageFlags : uint { diff --git a/FModel/PakReader/Parsers/Objects/EPakVersion.cs b/FModel/PakReader/Parsers/Objects/EPakVersion.cs index 90fced84..ffa14ab1 100644 --- a/FModel/PakReader/Parsers/Objects/EPakVersion.cs +++ b/FModel/PakReader/Parsers/Objects/EPakVersion.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { // NOTE: THIS IS NOT AN ACTUAL ENUM IN UE4. // LINK: https://github.com/EpicGames/UnrealEngine/blob/8b6414ae4bca5f93b878afadcc41ab518b09984f/Engine/Source/Runtime/PakFile/Public/IPlatformFilePak.h#L85 diff --git a/FModel/PakReader/Parsers/Objects/EPixelFormat.cs b/FModel/PakReader/Parsers/Objects/EPixelFormat.cs index 66fde5b8..0b49535d 100644 --- a/FModel/PakReader/Parsers/Objects/EPixelFormat.cs +++ b/FModel/PakReader/Parsers/Objects/EPixelFormat.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EPixelFormat { diff --git a/FModel/PakReader/Parsers/Objects/ERangeBoundType.cs b/FModel/PakReader/Parsers/Objects/ERangeBoundType.cs index 69d41cef..17460285 100644 --- a/FModel/PakReader/Parsers/Objects/ERangeBoundType.cs +++ b/FModel/PakReader/Parsers/Objects/ERangeBoundType.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum ERangeBoundType { diff --git a/FModel/PakReader/Parsers/Objects/ERichCurveCompressionFormat.cs b/FModel/PakReader/Parsers/Objects/ERichCurveCompressionFormat.cs index 1070585d..8f363e7f 100644 --- a/FModel/PakReader/Parsers/Objects/ERichCurveCompressionFormat.cs +++ b/FModel/PakReader/Parsers/Objects/ERichCurveCompressionFormat.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** Enumerates curve compression options. */ public enum ERichCurveCompressionFormat diff --git a/FModel/PakReader/Parsers/Objects/ERichCurveExtrapolation.cs b/FModel/PakReader/Parsers/Objects/ERichCurveExtrapolation.cs index ba6f488b..0d6c41d9 100644 --- a/FModel/PakReader/Parsers/Objects/ERichCurveExtrapolation.cs +++ b/FModel/PakReader/Parsers/Objects/ERichCurveExtrapolation.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum ERichCurveExtrapolation { diff --git a/FModel/PakReader/Parsers/Objects/ERichCurveInterpMode.cs b/FModel/PakReader/Parsers/Objects/ERichCurveInterpMode.cs index ff06932b..cc9b590d 100644 --- a/FModel/PakReader/Parsers/Objects/ERichCurveInterpMode.cs +++ b/FModel/PakReader/Parsers/Objects/ERichCurveInterpMode.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** Method of interpolation between this key and the next. */ public enum ERichCurveInterpMode : byte diff --git a/FModel/PakReader/Parsers/Objects/ERichCurveKeyTimeCompressionFormat.cs b/FModel/PakReader/Parsers/Objects/ERichCurveKeyTimeCompressionFormat.cs index 78cd7662..09077ba7 100644 --- a/FModel/PakReader/Parsers/Objects/ERichCurveKeyTimeCompressionFormat.cs +++ b/FModel/PakReader/Parsers/Objects/ERichCurveKeyTimeCompressionFormat.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** Enumerates key time compression options. */ public enum ERichCurveKeyTimeCompressionFormat diff --git a/FModel/PakReader/Parsers/Objects/ERichCurveTangentMode.cs b/FModel/PakReader/Parsers/Objects/ERichCurveTangentMode.cs index a3a977ac..dd2ab2df 100644 --- a/FModel/PakReader/Parsers/Objects/ERichCurveTangentMode.cs +++ b/FModel/PakReader/Parsers/Objects/ERichCurveTangentMode.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** If using Cubic, this enum describes how the tangents should be controlled in editor. */ public enum ERichCurveTangentMode : byte diff --git a/FModel/PakReader/Parsers/Objects/ERichCurveTangentWeightMode.cs b/FModel/PakReader/Parsers/Objects/ERichCurveTangentWeightMode.cs index a8768776..03cb5e16 100644 --- a/FModel/PakReader/Parsers/Objects/ERichCurveTangentWeightMode.cs +++ b/FModel/PakReader/Parsers/Objects/ERichCurveTangentWeightMode.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** Enumerates tangent weight modes. */ public enum ERichCurveTangentWeightMode diff --git a/FModel/PakReader/Parsers/Objects/ESoundGroup.cs b/FModel/PakReader/Parsers/Objects/ESoundGroup.cs index abb60dfd..dce2ccde 100644 --- a/FModel/PakReader/Parsers/Objects/ESoundGroup.cs +++ b/FModel/PakReader/Parsers/Objects/ESoundGroup.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum ESoundGroup { diff --git a/FModel/PakReader/Parsers/Objects/ESoundWaveLoadingBehavior.cs b/FModel/PakReader/Parsers/Objects/ESoundWaveLoadingBehavior.cs index 7f6feb19..ee2096e0 100644 --- a/FModel/PakReader/Parsers/Objects/ESoundWaveLoadingBehavior.cs +++ b/FModel/PakReader/Parsers/Objects/ESoundWaveLoadingBehavior.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum ESoundWaveLoadingBehavior : byte { diff --git a/FModel/PakReader/Parsers/Objects/ESoundWavePrecacheState.cs b/FModel/PakReader/Parsers/Objects/ESoundWavePrecacheState.cs index 456f9cc7..6b68eed6 100644 --- a/FModel/PakReader/Parsers/Objects/ESoundWavePrecacheState.cs +++ b/FModel/PakReader/Parsers/Objects/ESoundWavePrecacheState.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** Precache states */ public enum ESoundWavePrecacheState diff --git a/FModel/PakReader/Parsers/Objects/ESoundwaveSampleRateSettings.cs b/FModel/PakReader/Parsers/Objects/ESoundwaveSampleRateSettings.cs index 491efc9a..3a70a827 100644 --- a/FModel/PakReader/Parsers/Objects/ESoundwaveSampleRateSettings.cs +++ b/FModel/PakReader/Parsers/Objects/ESoundwaveSampleRateSettings.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum ESoundwaveSampleRateSettings : byte { diff --git a/FModel/PakReader/Parsers/Objects/EStringTableLoadingPhase.cs b/FModel/PakReader/Parsers/Objects/EStringTableLoadingPhase.cs index ba29a273..58c81cfe 100644 --- a/FModel/PakReader/Parsers/Objects/EStringTableLoadingPhase.cs +++ b/FModel/PakReader/Parsers/Objects/EStringTableLoadingPhase.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EStringTableLoadingPhase : byte { diff --git a/FModel/PakReader/Parsers/Objects/ETextFlag.cs b/FModel/PakReader/Parsers/Objects/ETextFlag.cs index 9279c0d6..c3e6919b 100644 --- a/FModel/PakReader/Parsers/Objects/ETextFlag.cs +++ b/FModel/PakReader/Parsers/Objects/ETextFlag.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum ETextFlag : uint { diff --git a/FModel/PakReader/Parsers/Objects/ETextGender.cs b/FModel/PakReader/Parsers/Objects/ETextGender.cs index a2ca2cad..f8138f75 100644 --- a/FModel/PakReader/Parsers/Objects/ETextGender.cs +++ b/FModel/PakReader/Parsers/Objects/ETextGender.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum ETextGender : byte { diff --git a/FModel/PakReader/Parsers/Objects/ETextHistoryType.cs b/FModel/PakReader/Parsers/Objects/ETextHistoryType.cs index 1281275a..be2edf0d 100644 --- a/FModel/PakReader/Parsers/Objects/ETextHistoryType.cs +++ b/FModel/PakReader/Parsers/Objects/ETextHistoryType.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum ETextHistoryType : sbyte { diff --git a/FModel/PakReader/Parsers/Objects/ETransformType.cs b/FModel/PakReader/Parsers/Objects/ETransformType.cs index 3f6cb3d6..9ad73365 100644 --- a/FModel/PakReader/Parsers/Objects/ETransformType.cs +++ b/FModel/PakReader/Parsers/Objects/ETransformType.cs @@ -1,5 +1,5 @@  -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum ETransformType : byte { diff --git a/FModel/PakReader/Parsers/Objects/EUnrealEngineObjectLicenseeUE4Version.cs b/FModel/PakReader/Parsers/Objects/EUnrealEngineObjectLicenseeUE4Version.cs index 89784388..1f6bbecf 100644 --- a/FModel/PakReader/Parsers/Objects/EUnrealEngineObjectLicenseeUE4Version.cs +++ b/FModel/PakReader/Parsers/Objects/EUnrealEngineObjectLicenseeUE4Version.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EUnrealEngineObjectLicenseeUE4Version { diff --git a/FModel/PakReader/Parsers/Objects/EUnrealEngineObjectUE4Version.cs b/FModel/PakReader/Parsers/Objects/EUnrealEngineObjectUE4Version.cs index 0920c956..8e091bc7 100644 --- a/FModel/PakReader/Parsers/Objects/EUnrealEngineObjectUE4Version.cs +++ b/FModel/PakReader/Parsers/Objects/EUnrealEngineObjectUE4Version.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EUnrealEngineObjectUE4Version { diff --git a/FModel/PakReader/Parsers/Objects/EVirtualTextureCodec.cs b/FModel/PakReader/Parsers/Objects/EVirtualTextureCodec.cs index dcf29d38..c24bf1cb 100644 --- a/FModel/PakReader/Parsers/Objects/EVirtualTextureCodec.cs +++ b/FModel/PakReader/Parsers/Objects/EVirtualTextureCodec.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public enum EVirtualTextureCodec : byte { diff --git a/FModel/PakReader/Parsers/Objects/FAkMediaDataChunk.cs b/FModel/PakReader/Parsers/Objects/FAkMediaDataChunk.cs index 30b15729..b8a25aa0 100644 --- a/FModel/PakReader/Parsers/Objects/FAkMediaDataChunk.cs +++ b/FModel/PakReader/Parsers/Objects/FAkMediaDataChunk.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FAkMediaDataChunk : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FAssetData.cs b/FModel/PakReader/Parsers/Objects/FAssetData.cs index 53401b1b..0bfd8638 100644 --- a/FModel/PakReader/Parsers/Objects/FAssetData.cs +++ b/FModel/PakReader/Parsers/Objects/FAssetData.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FAssetData : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FAssetDataTagMapSharedView.cs b/FModel/PakReader/Parsers/Objects/FAssetDataTagMapSharedView.cs index 795975b7..efc49e61 100644 --- a/FModel/PakReader/Parsers/Objects/FAssetDataTagMapSharedView.cs +++ b/FModel/PakReader/Parsers/Objects/FAssetDataTagMapSharedView.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FAssetDataTagMapSharedView : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FAssetIdentifier.cs b/FModel/PakReader/Parsers/Objects/FAssetIdentifier.cs index 81360d4b..6a66d99c 100644 --- a/FModel/PakReader/Parsers/Objects/FAssetIdentifier.cs +++ b/FModel/PakReader/Parsers/Objects/FAssetIdentifier.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FAssetIdentifier : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FAssetPackageData.cs b/FModel/PakReader/Parsers/Objects/FAssetPackageData.cs index 4477d9bd..649412af 100644 --- a/FModel/PakReader/Parsers/Objects/FAssetPackageData.cs +++ b/FModel/PakReader/Parsers/Objects/FAssetPackageData.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FAssetPackageData : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FAssetRegistryState.cs b/FModel/PakReader/Parsers/Objects/FAssetRegistryState.cs index 975c0c0c..16d8c06b 100644 --- a/FModel/PakReader/Parsers/Objects/FAssetRegistryState.cs +++ b/FModel/PakReader/Parsers/Objects/FAssetRegistryState.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FAssetRegistryState : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FAssetRegistryVersion.cs b/FModel/PakReader/Parsers/Objects/FAssetRegistryVersion.cs index e72fad11..ef3b387f 100644 --- a/FModel/PakReader/Parsers/Objects/FAssetRegistryVersion.cs +++ b/FModel/PakReader/Parsers/Objects/FAssetRegistryVersion.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FAssetRegistryVersion : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FBodyInstance.cs b/FModel/PakReader/Parsers/Objects/FBodyInstance.cs index f9f3b86f..267a85e6 100644 --- a/FModel/PakReader/Parsers/Objects/FBodyInstance.cs +++ b/FModel/PakReader/Parsers/Objects/FBodyInstance.cs @@ -1,6 +1,6 @@ using System; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FBodyInstance : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FBox.cs b/FModel/PakReader/Parsers/Objects/FBox.cs index 68e2e6bd..c8b1240a 100644 --- a/FModel/PakReader/Parsers/Objects/FBox.cs +++ b/FModel/PakReader/Parsers/Objects/FBox.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FBox : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FBox2D.cs b/FModel/PakReader/Parsers/Objects/FBox2D.cs index a782e0c7..ca067e65 100644 --- a/FModel/PakReader/Parsers/Objects/FBox2D.cs +++ b/FModel/PakReader/Parsers/Objects/FBox2D.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FBox2D : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FByteBulkData.cs b/FModel/PakReader/Parsers/Objects/FByteBulkData.cs index f0cdaf74..2c460688 100644 --- a/FModel/PakReader/Parsers/Objects/FByteBulkData.cs +++ b/FModel/PakReader/Parsers/Objects/FByteBulkData.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FByteBulkData : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FChunkHeader.cs b/FModel/PakReader/Parsers/Objects/FChunkHeader.cs index 33e747b6..54a8038f 100644 --- a/FModel/PakReader/Parsers/Objects/FChunkHeader.cs +++ b/FModel/PakReader/Parsers/Objects/FChunkHeader.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FChunkHeader : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FColor.cs b/FModel/PakReader/Parsers/Objects/FColor.cs index 74ad7e6c..7cbe971c 100644 --- a/FModel/PakReader/Parsers/Objects/FColor.cs +++ b/FModel/PakReader/Parsers/Objects/FColor.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FColor : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FColorMaterialInput.cs b/FModel/PakReader/Parsers/Objects/FColorMaterialInput.cs index df02c126..7bb15120 100644 --- a/FModel/PakReader/Parsers/Objects/FColorMaterialInput.cs +++ b/FModel/PakReader/Parsers/Objects/FColorMaterialInput.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FColorMaterialInput : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FCompressedChunk.cs b/FModel/PakReader/Parsers/Objects/FCompressedChunk.cs index 439fe545..5b929eae 100644 --- a/FModel/PakReader/Parsers/Objects/FCompressedChunk.cs +++ b/FModel/PakReader/Parsers/Objects/FCompressedChunk.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FCompressedChunk : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FCompressedOffsetData.cs b/FModel/PakReader/Parsers/Objects/FCompressedOffsetData.cs index 179b2207..79f19c6d 100644 --- a/FModel/PakReader/Parsers/Objects/FCompressedOffsetData.cs +++ b/FModel/PakReader/Parsers/Objects/FCompressedOffsetData.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FCompressedOffsetData : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FCompressedSegment.cs b/FModel/PakReader/Parsers/Objects/FCompressedSegment.cs index 44bd8672..9b5481c5 100644 --- a/FModel/PakReader/Parsers/Objects/FCompressedSegment.cs +++ b/FModel/PakReader/Parsers/Objects/FCompressedSegment.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FCompressedSegment : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FCustomVersion.cs b/FModel/PakReader/Parsers/Objects/FCustomVersion.cs index 54695703..59462869 100644 --- a/FModel/PakReader/Parsers/Objects/FCustomVersion.cs +++ b/FModel/PakReader/Parsers/Objects/FCustomVersion.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FCustomVersion { diff --git a/FModel/PakReader/Parsers/Objects/FCustomVersionContainer.cs b/FModel/PakReader/Parsers/Objects/FCustomVersionContainer.cs index 50b7b06e..44be22e6 100644 --- a/FModel/PakReader/Parsers/Objects/FCustomVersionContainer.cs +++ b/FModel/PakReader/Parsers/Objects/FCustomVersionContainer.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FCustomVersionContainer : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FDateTime.cs b/FModel/PakReader/Parsers/Objects/FDateTime.cs index 94523882..55d1fc43 100644 --- a/FModel/PakReader/Parsers/Objects/FDateTime.cs +++ b/FModel/PakReader/Parsers/Objects/FDateTime.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FDateTime : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FDependsNode.cs b/FModel/PakReader/Parsers/Objects/FDependsNode.cs index 9e860e0b..31865046 100644 --- a/FModel/PakReader/Parsers/Objects/FDependsNode.cs +++ b/FModel/PakReader/Parsers/Objects/FDependsNode.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public struct FDependsNode : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FDictionaryHeader.cs b/FModel/PakReader/Parsers/Objects/FDictionaryHeader.cs index 249f7170..f643c9ef 100644 --- a/FModel/PakReader/Parsers/Objects/FDictionaryHeader.cs +++ b/FModel/PakReader/Parsers/Objects/FDictionaryHeader.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FDictionaryHeader : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FEngineVersion.cs b/FModel/PakReader/Parsers/Objects/FEngineVersion.cs index 96d6d73a..9e2c6870 100644 --- a/FModel/PakReader/Parsers/Objects/FEngineVersion.cs +++ b/FModel/PakReader/Parsers/Objects/FEngineVersion.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FEngineVersion { diff --git a/FModel/PakReader/Parsers/Objects/FEntry.cs b/FModel/PakReader/Parsers/Objects/FEntry.cs index f7988147..cba91f02 100644 --- a/FModel/PakReader/Parsers/Objects/FEntry.cs +++ b/FModel/PakReader/Parsers/Objects/FEntry.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FEntry : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FEvaluationTreeEntryHandle.cs b/FModel/PakReader/Parsers/Objects/FEvaluationTreeEntryHandle.cs index 5d668cb6..9eaff8d4 100644 --- a/FModel/PakReader/Parsers/Objects/FEvaluationTreeEntryHandle.cs +++ b/FModel/PakReader/Parsers/Objects/FEvaluationTreeEntryHandle.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FEvaluationTreeEntryHandle : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FFactChunk.cs b/FModel/PakReader/Parsers/Objects/FFactChunk.cs index 122863cc..7e247c01 100644 --- a/FModel/PakReader/Parsers/Objects/FFactChunk.cs +++ b/FModel/PakReader/Parsers/Objects/FFactChunk.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FFactChunk : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FFormatArgumentData.cs b/FModel/PakReader/Parsers/Objects/FFormatArgumentData.cs index 047a6559..6f8176fc 100644 --- a/FModel/PakReader/Parsers/Objects/FFormatArgumentData.cs +++ b/FModel/PakReader/Parsers/Objects/FFormatArgumentData.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FFormatArgumentData : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FFormatArgumentValue.cs b/FModel/PakReader/Parsers/Objects/FFormatArgumentValue.cs index a961f2c0..a0d7f501 100644 --- a/FModel/PakReader/Parsers/Objects/FFormatArgumentValue.cs +++ b/FModel/PakReader/Parsers/Objects/FFormatArgumentValue.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FFormatArgumentValue : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FFormatContainer.cs b/FModel/PakReader/Parsers/Objects/FFormatContainer.cs index 9b0e569a..f1d71b23 100644 --- a/FModel/PakReader/Parsers/Objects/FFormatContainer.cs +++ b/FModel/PakReader/Parsers/Objects/FFormatContainer.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FFormatContainer : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FFrameNumber.cs b/FModel/PakReader/Parsers/Objects/FFrameNumber.cs index f7646541..05c2ca3d 100644 --- a/FModel/PakReader/Parsers/Objects/FFrameNumber.cs +++ b/FModel/PakReader/Parsers/Objects/FFrameNumber.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FFrameNumber : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FGameplayTagContainer.cs b/FModel/PakReader/Parsers/Objects/FGameplayTagContainer.cs index 16067c12..85c3a843 100644 --- a/FModel/PakReader/Parsers/Objects/FGameplayTagContainer.cs +++ b/FModel/PakReader/Parsers/Objects/FGameplayTagContainer.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FGameplayTagContainer : IUStruct { @@ -9,7 +9,7 @@ namespace PakReader.Parsers.Objects internal FGameplayTagContainer(PackageReader reader) { - GameplayTags = reader.ReadTArray(() => reader.ReadFName()); + GameplayTags = reader.ReadTArray(reader.ReadFName); } public string[] GetValue() diff --git a/FModel/PakReader/Parsers/Objects/FGenerationInfo.cs b/FModel/PakReader/Parsers/Objects/FGenerationInfo.cs index 2df28c96..eec8c1c7 100644 --- a/FModel/PakReader/Parsers/Objects/FGenerationInfo.cs +++ b/FModel/PakReader/Parsers/Objects/FGenerationInfo.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FGenerationInfo { diff --git a/FModel/PakReader/Parsers/Objects/FGuid.cs b/FModel/PakReader/Parsers/Objects/FGuid.cs index b6c1788b..c09c5965 100644 --- a/FModel/PakReader/Parsers/Objects/FGuid.cs +++ b/FModel/PakReader/Parsers/Objects/FGuid.cs @@ -3,7 +3,7 @@ using System.Globalization; using System.IO; using Newtonsoft.Json; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FGuid : IUStruct, IEquatable { diff --git a/FModel/PakReader/Parsers/Objects/FIntPoint.cs b/FModel/PakReader/Parsers/Objects/FIntPoint.cs index 3d8b1030..bed0519f 100644 --- a/FModel/PakReader/Parsers/Objects/FIntPoint.cs +++ b/FModel/PakReader/Parsers/Objects/FIntPoint.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FIntPoint : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FLevelSequenceLegacyObjectReference.cs b/FModel/PakReader/Parsers/Objects/FLevelSequenceLegacyObjectReference.cs index 9db6af8e..7a67d77f 100644 --- a/FModel/PakReader/Parsers/Objects/FLevelSequenceLegacyObjectReference.cs +++ b/FModel/PakReader/Parsers/Objects/FLevelSequenceLegacyObjectReference.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FLevelSequenceLegacyObjectReference : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FLevelSequenceObjectReferenceMap.cs b/FModel/PakReader/Parsers/Objects/FLevelSequenceObjectReferenceMap.cs index 8b1ef4b8..830d951c 100644 --- a/FModel/PakReader/Parsers/Objects/FLevelSequenceObjectReferenceMap.cs +++ b/FModel/PakReader/Parsers/Objects/FLevelSequenceObjectReferenceMap.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FLevelSequenceObjectReferenceMap : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FLinearColor.cs b/FModel/PakReader/Parsers/Objects/FLinearColor.cs index e0b2ae51..5442402c 100644 --- a/FModel/PakReader/Parsers/Objects/FLinearColor.cs +++ b/FModel/PakReader/Parsers/Objects/FLinearColor.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FLinearColor : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FMD5Hash.cs b/FModel/PakReader/Parsers/Objects/FMD5Hash.cs index d159eaaa..ce716576 100644 --- a/FModel/PakReader/Parsers/Objects/FMD5Hash.cs +++ b/FModel/PakReader/Parsers/Objects/FMD5Hash.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FMD5Hash : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FMaterialInput.cs b/FModel/PakReader/Parsers/Objects/FMaterialInput.cs index c5338e39..a026c8a9 100644 --- a/FModel/PakReader/Parsers/Objects/FMaterialInput.cs +++ b/FModel/PakReader/Parsers/Objects/FMaterialInput.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FMaterialInput : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationKey.cs b/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationKey.cs index 57f35d1e..a56e7cf5 100644 --- a/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationKey.cs +++ b/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationKey.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FMovieSceneEvaluationKey : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTemplate.cs b/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTemplate.cs index a55e1eb5..47b5095a 100644 --- a/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTemplate.cs +++ b/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTemplate.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FMovieSceneEvaluationTemplate : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTree.cs b/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTree.cs index 09c4a387..ddce1c5d 100644 --- a/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTree.cs +++ b/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTree.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FMovieSceneEvaluationTree : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTreeNode.cs b/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTreeNode.cs index 46cd0e32..6109bed2 100644 --- a/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTreeNode.cs +++ b/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTreeNode.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FMovieSceneEvaluationTreeNode : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTreeNodeHandle.cs b/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTreeNodeHandle.cs index de38415a..2b4f8651 100644 --- a/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTreeNodeHandle.cs +++ b/FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTreeNodeHandle.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FMovieSceneEvaluationTreeNodeHandle : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FMovieSceneFloatChannel.cs b/FModel/PakReader/Parsers/Objects/FMovieSceneFloatChannel.cs index ad8c98ac..b048ce6d 100644 --- a/FModel/PakReader/Parsers/Objects/FMovieSceneFloatChannel.cs +++ b/FModel/PakReader/Parsers/Objects/FMovieSceneFloatChannel.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FMovieSceneFloatChannel : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FMovieSceneFrameRange.cs b/FModel/PakReader/Parsers/Objects/FMovieSceneFrameRange.cs index ef1ca0b2..7f1ead9c 100644 --- a/FModel/PakReader/Parsers/Objects/FMovieSceneFrameRange.cs +++ b/FModel/PakReader/Parsers/Objects/FMovieSceneFrameRange.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FMovieSceneFrameRange : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FMovieSceneSegment.cs b/FModel/PakReader/Parsers/Objects/FMovieSceneSegment.cs index bde84267..fa8982c9 100644 --- a/FModel/PakReader/Parsers/Objects/FMovieSceneSegment.cs +++ b/FModel/PakReader/Parsers/Objects/FMovieSceneSegment.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FMovieSceneSegment : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FName.cs b/FModel/PakReader/Parsers/Objects/FName.cs index 2cf1901a..f962ea3b 100644 --- a/FModel/PakReader/Parsers/Objects/FName.cs +++ b/FModel/PakReader/Parsers/Objects/FName.cs @@ -1,27 +1,35 @@ using Newtonsoft.Json; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FName { - readonly FNameEntrySerialized Name; + //readonly FNameEntrySerialized Name; [JsonIgnore] public readonly int Index; [JsonIgnore] public readonly int Number; - public string String => Name.Name; + public readonly string String; [JsonIgnore] - public bool IsNone => String == "None"; + public bool IsNone => String == null || String == "None"; internal FName(FNameEntrySerialized name, int index, int number) { - Name = name; + //Name = name; + String = name.Name; Index = index; Number = number; } - public override string ToString() => Name.Name; + public FName(string name, int index = 0, int number = 0) + { + String = name; + Index = index; + Number = number; + } + + public override string ToString() => String; } } diff --git a/FModel/PakReader/Parsers/Objects/FNameEntrySerialized.cs b/FModel/PakReader/Parsers/Objects/FNameEntrySerialized.cs index 3791a7fb..b444f48f 100644 --- a/FModel/PakReader/Parsers/Objects/FNameEntrySerialized.cs +++ b/FModel/PakReader/Parsers/Objects/FNameEntrySerialized.cs @@ -1,12 +1,16 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; +using System.Text; +using FModel.PakReader.IO; +using FModel.Utils; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { // The only values this contains from the original FNameEntrySerialized is the isWide (unused here since C# strings are always 16 bit anyway) and the Index (some typedef of an int which was unused anyway) // FNames are passed into a pool, but I don't think this has any impact or difference on the resolving of these values. I could make a Dictionary or Lookup for values having the same hash or something..? // FNameEntrySerialized is a class due to the value typing that C# has for structs. This is for memory performance to reduce duplicate strings in memory. Refrain from saving the FNameEntrySerialized's value (Name) and opt for a class instead - internal readonly struct FNameEntrySerialized + public readonly struct FNameEntrySerialized { public readonly string Name; @@ -18,6 +22,40 @@ namespace PakReader.Parsers.Objects reader.BaseStream.Position += 4; } + public FNameEntrySerialized(string name) + { + Name = name; + } + public override string ToString() => Name; + + public static void LoadNameBatch(List outNames, List outHashes, byte[] nameData, byte[] hashData) + { + using var nameReader = new BinaryReader(new MemoryStream(nameData)); + using var hashReader = new BinaryReader(new MemoryStream(hashData)); + + var hashDataIt = hashReader.ReadUInt64(); + var hashVersion = hashDataIt.IntelOrder64(); + + //var hashCount = (int) (hashReader.BaseStream.Length / sizeof(ulong) - 1); + var hashCount = hashData.Length / sizeof(ulong) - 1; + outNames.Capacity = hashCount; + + for (var i = 0; i < hashCount; i++) + { + outHashes.Add(hashReader.ReadUInt64()); + outNames.Add(LoadNameHeader(nameReader)); + } + } + + private static FNameEntrySerialized LoadNameHeader(BinaryReader nameReader) + { + var header = new FSerializedNameHeader(nameReader); + + var length = (int)header.Length; + return header.IsUtf16 ? + new FNameEntrySerialized(Encoding.Unicode.GetString(nameReader.ReadBytes(length * 2))) : + new FNameEntrySerialized(Encoding.UTF8.GetString(nameReader.ReadBytes(length))); + } } } diff --git a/FModel/PakReader/Parsers/Objects/FNameTableArchiveReader.cs b/FModel/PakReader/Parsers/Objects/FNameTableArchiveReader.cs index d910f087..e84eefd6 100644 --- a/FModel/PakReader/Parsers/Objects/FNameTableArchiveReader.cs +++ b/FModel/PakReader/Parsers/Objects/FNameTableArchiveReader.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FNameTableArchiveReader : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FNavAgentSelectorCustomization.cs b/FModel/PakReader/Parsers/Objects/FNavAgentSelectorCustomization.cs index bb74dfb1..fb135d84 100644 --- a/FModel/PakReader/Parsers/Objects/FNavAgentSelectorCustomization.cs +++ b/FModel/PakReader/Parsers/Objects/FNavAgentSelectorCustomization.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FNavAgentSelectorCustomization : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FObjectExport.cs b/FModel/PakReader/Parsers/Objects/FObjectExport.cs index 552c2b78..a4b12e6f 100644 --- a/FModel/PakReader/Parsers/Objects/FObjectExport.cs +++ b/FModel/PakReader/Parsers/Objects/FObjectExport.cs @@ -1,6 +1,8 @@ -using Newtonsoft.Json; +using FModel.PakReader.IO; -namespace PakReader.Parsers.Objects +using Newtonsoft.Json; + +namespace FModel.PakReader.Parsers.Objects { public sealed class FObjectExport : FObjectResource { @@ -43,6 +45,17 @@ namespace PakReader.Parsers.Objects [JsonIgnore] public int CreateBeforeCreateDependencies { get; } + internal FObjectExport(IoPackageReader reader, int index) + { + var exportMapEntry = reader.ExportMap[index]; + OuterIndex = new FPackageIndex(reader, (int)exportMapEntry.OuterIndex.Value + 1); + ObjectFlags = exportMapEntry.ObjectFlags; + SerialOffset = (long)exportMapEntry.CookedSerialOffset; + SerialSize = (long)exportMapEntry.CookedSerialSize; + PackageFlags = reader.Summary.PackageFlags; + ObjectName = new FName(exportMapEntry.ObjectName.String, (int)exportMapEntry.ObjectName.Index, (int)exportMapEntry.ObjectName.Number); + } + internal FObjectExport(PackageReader reader) { ClassIndex = new FPackageIndex(reader); @@ -84,8 +97,8 @@ namespace PakReader.Parsers.Objects public enum EDynamicType : byte { NotDynamicExport, - DynamicType, - ClassDefaultObject, - }; + DynamicType, + ClassDefaultObject, + }; } } diff --git a/FModel/PakReader/Parsers/Objects/FObjectImport.cs b/FModel/PakReader/Parsers/Objects/FObjectImport.cs index fee40357..52f78313 100644 --- a/FModel/PakReader/Parsers/Objects/FObjectImport.cs +++ b/FModel/PakReader/Parsers/Objects/FObjectImport.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public sealed class FObjectImport : FObjectResource { diff --git a/FModel/PakReader/Parsers/Objects/FObjectResource.cs b/FModel/PakReader/Parsers/Objects/FObjectResource.cs index 47c8b3f8..e6851326 100644 --- a/FModel/PakReader/Parsers/Objects/FObjectResource.cs +++ b/FModel/PakReader/Parsers/Objects/FObjectResource.cs @@ -1,8 +1,19 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public class FObjectResource { public FName ObjectName { get; protected set; } public FPackageIndex OuterIndex { get; protected set; } + + public FObjectResource() + { + + } + + public FObjectResource(FName objectName, FPackageIndex outerIndex) + { + ObjectName = objectName; + OuterIndex = outerIndex; + } } } diff --git a/FModel/PakReader/Parsers/Objects/FOodleCompressedData.cs b/FModel/PakReader/Parsers/Objects/FOodleCompressedData.cs index e9d81227..d844f64e 100644 --- a/FModel/PakReader/Parsers/Objects/FOodleCompressedData.cs +++ b/FModel/PakReader/Parsers/Objects/FOodleCompressedData.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FOodleCompressedData : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FOodleDictionaryArchive.cs b/FModel/PakReader/Parsers/Objects/FOodleDictionaryArchive.cs index b2433ace..294fd0ab 100644 --- a/FModel/PakReader/Parsers/Objects/FOodleDictionaryArchive.cs +++ b/FModel/PakReader/Parsers/Objects/FOodleDictionaryArchive.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FOodleDictionaryArchive : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FPackageFileSummary.cs b/FModel/PakReader/Parsers/Objects/FPackageFileSummary.cs index adf1712c..ec1e11b8 100644 --- a/FModel/PakReader/Parsers/Objects/FPackageFileSummary.cs +++ b/FModel/PakReader/Parsers/Objects/FPackageFileSummary.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FPackageFileSummary { diff --git a/FModel/PakReader/Parsers/Objects/FPackageIndex.cs b/FModel/PakReader/Parsers/Objects/FPackageIndex.cs index 8ff277d9..97749634 100644 --- a/FModel/PakReader/Parsers/Objects/FPackageIndex.cs +++ b/FModel/PakReader/Parsers/Objects/FPackageIndex.cs @@ -1,7 +1,8 @@ -using Newtonsoft.Json; -using System.Collections.Generic; +using System.Collections.Generic; +using System.Diagnostics; +using Newtonsoft.Json; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** * Wrapper for index into a ULnker's ImportMap or ExportMap. @@ -20,22 +21,50 @@ namespace PakReader.Parsers.Objects { if (!IsNull) { - if (IsImport && AsImport < Reader.ImportMap.Length) - return Reader.ImportMap[AsImport]; - else if (IsImport && AsExport < Reader.ExportMap.Length) - return Reader.ExportMap[AsExport]; + if (Reader is LegacyPackageReader legacyReader) + { + if (IsImport && AsImport < legacyReader.ImportMap.Length) + { + return legacyReader.ImportMap[AsImport]; + } + + if (IsExport && AsExport < legacyReader.ExportMap.Length) + { + return legacyReader.ExportMap[AsExport]; + } + } + else if (Reader is IoPackageReader ioReader) + { + if (IsImport && AsImport < ioReader.FakeImportMap.Count) + { + return ioReader.FakeImportMap[AsImport]; + } + + if (IsExport && AsExport < ioReader.ExportMap.Length) + { + return new FObjectExport(ioReader, AsExport); + } + + Debugger.Break(); + } } return null; } } - readonly PackageReader Reader; + private readonly PackageReader Reader; internal FPackageIndex(PackageReader reader) { Index = reader.ReadInt32(); Reader = reader; } + + internal FPackageIndex(PackageReader reader, int index) + { + Index = index; + Reader = reader; + } public object GetValue() { diff --git a/FModel/PakReader/Parsers/Objects/FPakCompressedBlock.cs b/FModel/PakReader/Parsers/Objects/FPakCompressedBlock.cs index fdbe2c4c..0e494597 100644 --- a/FModel/PakReader/Parsers/Objects/FPakCompressedBlock.cs +++ b/FModel/PakReader/Parsers/Objects/FPakCompressedBlock.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FPakCompressedBlock { diff --git a/FModel/PakReader/Parsers/Objects/FPakDirectoryEntry.cs b/FModel/PakReader/Parsers/Objects/FPakDirectoryEntry.cs index 4676204c..8988ff43 100644 --- a/FModel/PakReader/Parsers/Objects/FPakDirectoryEntry.cs +++ b/FModel/PakReader/Parsers/Objects/FPakDirectoryEntry.cs @@ -1,5 +1,4 @@ -using PakReader; -using System.IO; +using System.IO; namespace FModel.PakReader.Parsers.Objects { diff --git a/FModel/PakReader/Parsers/Objects/FPakEntry.cs b/FModel/PakReader/Parsers/Objects/FPakEntry.cs index e1cf4ba2..cf7e096c 100644 --- a/FModel/PakReader/Parsers/Objects/FPakEntry.cs +++ b/FModel/PakReader/Parsers/Objects/FPakEntry.cs @@ -1,11 +1,11 @@ -using Ionic.Zlib; -using System; +using System; using System.IO; using System.Runtime.CompilerServices; +using Ionic.Zlib; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { - public class FPakEntry + public class FPakEntry : ReaderEntry { const byte Flag_Encrypted = 0x01; const byte Flag_Deleted = 0x02; @@ -13,8 +13,9 @@ namespace PakReader.Parsers.Objects public bool Encrypted => (Flags & Flag_Encrypted) != 0; public bool Deleted => (Flags & Flag_Deleted) != 0; - public readonly string PakFileName; - public readonly string Name; + 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; @@ -31,9 +32,9 @@ namespace PakReader.Parsers.Objects CompressionBlockSize = 0; Flags = 0; - PakFileName = pakName; + ContainerName = pakName; string name = caseSensitive ? reader.ReadFString() : reader.ReadFString().ToLowerInvariant(); - Name = name.StartsWith("/") ? name[1..] : name; + _name = name.StartsWith("/") ? name[1..] : name; var StartOffset = reader.BaseStream.Position; @@ -95,8 +96,8 @@ namespace PakReader.Parsers.Objects CompressionBlockSize = 0; Flags = 0; - PakFileName = pakName; - Name = caseSensitive ? reader.ReadFString() : reader.ReadFString().ToLowerInvariant(); + ContainerName = pakName; + _name = caseSensitive ? reader.ReadFString() : reader.ReadFString().ToLowerInvariant(); var StartOffset = reader.BaseStream.Position; @@ -118,8 +119,8 @@ namespace PakReader.Parsers.Objects internal FPakEntry(string pakName, string name, long offset, long size, long uncompressedSize, FPakCompressedBlock[] compressionBlocks, uint compressionBlockSize, uint compressionMethodIndex, byte flags) { - PakFileName = pakName; - Name = name; + ContainerName = pakName; + _name = name; Offset = offset; Size = size; UncompressedSize = uncompressedSize; @@ -227,49 +228,7 @@ namespace PakReader.Parsers.Objects return SerializedSize; } - public FPakEntry Uexp = null; - public FPakEntry Ubulk = null; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsUE4Package() => Name[Name.LastIndexOf(".")..].Equals(".uasset"); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsLocres() => Name[Name.LastIndexOf(".")..].Equals(".locres"); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsUE4Map() => Name[Name.LastIndexOf(".")..].Equals(".umap"); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsUE4Font() => Name[Name.LastIndexOf(".")..].Equals(".ufont"); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasUexp() => Uexp != null; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasUbulk() => Ubulk != null; - [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsCompressed() => UncompressedSize != Size || CompressionMethodIndex != (int)ECompressionFlags.COMPRESS_None; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public string GetExtension() => Name[Name.LastIndexOf(".")..]; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public string GetPathWithoutFile() - { - int stop = Name.LastIndexOf("/"); - if (stop <= -1) - stop = 0; - return Name.Substring(0, stop); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public string GetPathWithoutExtension() => Name.Substring(0, Name.LastIndexOf(".")); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public string GetNameWithExtension() => Name.Substring(Name.LastIndexOf("/") + 1); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public string GetNameWithoutExtension() - { - int start = Name.LastIndexOf("/") + 1; - int stop = Name.LastIndexOf(".") - start; - return Name.Substring(start, stop); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public string GetFirstFolder() => Name.Substring(Name.StartsWith('/') ? 1 : 0, Name.IndexOf('/')); - - public override string ToString() => Name; } } diff --git a/FModel/PakReader/Parsers/Objects/FPakInfo.cs b/FModel/PakReader/Parsers/Objects/FPakInfo.cs index c6abf70d..818882ea 100644 --- a/FModel/PakReader/Parsers/Objects/FPakInfo.cs +++ b/FModel/PakReader/Parsers/Objects/FPakInfo.cs @@ -2,7 +2,7 @@ using System.IO; using System.Text; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FPakInfo { diff --git a/FModel/PakReader/Parsers/Objects/FPathHashIndexEntry.cs b/FModel/PakReader/Parsers/Objects/FPathHashIndexEntry.cs index 083d5181..8b75be74 100644 --- a/FModel/PakReader/Parsers/Objects/FPathHashIndexEntry.cs +++ b/FModel/PakReader/Parsers/Objects/FPathHashIndexEntry.cs @@ -1,5 +1,4 @@ -using PakReader; -using System.IO; +using System.IO; namespace FModel.PakReader.Parsers.Objects { diff --git a/FModel/PakReader/Parsers/Objects/FPerPlatformFloat.cs b/FModel/PakReader/Parsers/Objects/FPerPlatformFloat.cs index f6951e63..bb19cb93 100644 --- a/FModel/PakReader/Parsers/Objects/FPerPlatformFloat.cs +++ b/FModel/PakReader/Parsers/Objects/FPerPlatformFloat.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FPerPlatformFloat : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FPerPlatformInt.cs b/FModel/PakReader/Parsers/Objects/FPerPlatformInt.cs index 9a18d49b..3c54d4f6 100644 --- a/FModel/PakReader/Parsers/Objects/FPerPlatformInt.cs +++ b/FModel/PakReader/Parsers/Objects/FPerPlatformInt.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FPerPlatformInt : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FPropertyTag.cs b/FModel/PakReader/Parsers/Objects/FPropertyTag.cs index df61de6b..15f8ccd7 100644 --- a/FModel/PakReader/Parsers/Objects/FPropertyTag.cs +++ b/FModel/PakReader/Parsers/Objects/FPropertyTag.cs @@ -1,4 +1,6 @@ -namespace PakReader.Parsers.Objects +using FModel.PakReader.IO; + +namespace FModel.PakReader.Parsers.Objects { readonly struct FPropertyTag { @@ -18,6 +20,23 @@ public readonly FName Type; // Variables public readonly FName ValueType; + public FPropertyTag(PropertyInfo info) + { + Name = new FName(info.Name); + Type = new FName(info.Type); + StructName = new FName(info.StructType); + BoolVal = (byte) ((info.Bool ?? false) ? 1 : 0); + EnumName = new FName(info.EnumName); + InnerType = new FName(info.InnerType); + ValueType = new FName(info.ValueType); + ArrayIndex = 0; + Position = 0; + HasPropertyGuid = 0; + PropertyGuid = default; + Size = 0; + SizeOffset = 0; + StructGuid = default; + } internal FPropertyTag(PackageReader reader) { ArrayIndex = 0; diff --git a/FModel/PakReader/Parsers/Objects/FQuat.cs b/FModel/PakReader/Parsers/Objects/FQuat.cs index 750f86ed..8865c48c 100644 --- a/FModel/PakReader/Parsers/Objects/FQuat.cs +++ b/FModel/PakReader/Parsers/Objects/FQuat.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FQuat : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FRichCurveKey.cs b/FModel/PakReader/Parsers/Objects/FRichCurveKey.cs index ca709c50..2fb8c063 100644 --- a/FModel/PakReader/Parsers/Objects/FRichCurveKey.cs +++ b/FModel/PakReader/Parsers/Objects/FRichCurveKey.cs @@ -1,6 +1,4 @@ -using Newtonsoft.Json; - -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FRichCurveKey : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FRiffWaveHeader.cs b/FModel/PakReader/Parsers/Objects/FRiffWaveHeader.cs index 2694e64e..ee5036ef 100644 --- a/FModel/PakReader/Parsers/Objects/FRiffWaveHeader.cs +++ b/FModel/PakReader/Parsers/Objects/FRiffWaveHeader.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FRiffWaveHeader : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FRotator.cs b/FModel/PakReader/Parsers/Objects/FRotator.cs index 8323beff..c1bf4201 100644 --- a/FModel/PakReader/Parsers/Objects/FRotator.cs +++ b/FModel/PakReader/Parsers/Objects/FRotator.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FRotator : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FSHAHash.cs b/FModel/PakReader/Parsers/Objects/FSHAHash.cs index 50fa9082..fcdc531d 100644 --- a/FModel/PakReader/Parsers/Objects/FSHAHash.cs +++ b/FModel/PakReader/Parsers/Objects/FSHAHash.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FSHAHash { diff --git a/FModel/PakReader/Parsers/Objects/FSampleChunk.cs b/FModel/PakReader/Parsers/Objects/FSampleChunk.cs index 615305a3..560f24c9 100644 --- a/FModel/PakReader/Parsers/Objects/FSampleChunk.cs +++ b/FModel/PakReader/Parsers/Objects/FSampleChunk.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FSampleChunk : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FSampleLoop.cs b/FModel/PakReader/Parsers/Objects/FSampleLoop.cs index 19c483a2..2bc1d389 100644 --- a/FModel/PakReader/Parsers/Objects/FSampleLoop.cs +++ b/FModel/PakReader/Parsers/Objects/FSampleLoop.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FSampleLoop : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FSectionEvaluationDataTree.cs b/FModel/PakReader/Parsers/Objects/FSectionEvaluationDataTree.cs index a07102c1..e1c5f0b2 100644 --- a/FModel/PakReader/Parsers/Objects/FSectionEvaluationDataTree.cs +++ b/FModel/PakReader/Parsers/Objects/FSectionEvaluationDataTree.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FSectionEvaluationDataTree : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FSimpleCurveKey.cs b/FModel/PakReader/Parsers/Objects/FSimpleCurveKey.cs index a24bc31a..dfe1601b 100644 --- a/FModel/PakReader/Parsers/Objects/FSimpleCurveKey.cs +++ b/FModel/PakReader/Parsers/Objects/FSimpleCurveKey.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FSimpleCurveKey : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FSkeletalMeshAreaWeightedTriangleSampler.cs b/FModel/PakReader/Parsers/Objects/FSkeletalMeshAreaWeightedTriangleSampler.cs index 69d99f96..9045d70d 100644 --- a/FModel/PakReader/Parsers/Objects/FSkeletalMeshAreaWeightedTriangleSampler.cs +++ b/FModel/PakReader/Parsers/Objects/FSkeletalMeshAreaWeightedTriangleSampler.cs @@ -1,6 +1,6 @@ using System; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { /** Allows area weighted sampling of triangles on a skeletal mesh. */ public readonly struct FSkeletalMeshAreaWeightedTriangleSampler : IUStruct diff --git a/FModel/PakReader/Parsers/Objects/FSkeletalMeshSamplingLODBuiltData.cs b/FModel/PakReader/Parsers/Objects/FSkeletalMeshSamplingLODBuiltData.cs index b89603c6..20a5d851 100644 --- a/FModel/PakReader/Parsers/Objects/FSkeletalMeshSamplingLODBuiltData.cs +++ b/FModel/PakReader/Parsers/Objects/FSkeletalMeshSamplingLODBuiltData.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FSkeletalMeshSamplingLODBuiltData : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FSmartName.cs b/FModel/PakReader/Parsers/Objects/FSmartName.cs index 7a8b0102..dfa6cf00 100644 --- a/FModel/PakReader/Parsers/Objects/FSmartName.cs +++ b/FModel/PakReader/Parsers/Objects/FSmartName.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FSmartName : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FSoftObjectPath.cs b/FModel/PakReader/Parsers/Objects/FSoftObjectPath.cs index ec401b5d..21552e3e 100644 --- a/FModel/PakReader/Parsers/Objects/FSoftObjectPath.cs +++ b/FModel/PakReader/Parsers/Objects/FSoftObjectPath.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FSoftObjectPath : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FStreamedAudioChunk.cs b/FModel/PakReader/Parsers/Objects/FStreamedAudioChunk.cs index a93926ff..572c8bfe 100644 --- a/FModel/PakReader/Parsers/Objects/FStreamedAudioChunk.cs +++ b/FModel/PakReader/Parsers/Objects/FStreamedAudioChunk.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FStreamedAudioChunk : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FStringTable.cs b/FModel/PakReader/Parsers/Objects/FStringTable.cs index 2486475b..d7930980 100644 --- a/FModel/PakReader/Parsers/Objects/FStringTable.cs +++ b/FModel/PakReader/Parsers/Objects/FStringTable.cs @@ -1,7 +1,7 @@ -using FModel.Utils; -using System.Collections.Generic; +using System.Collections.Generic; +using FModel.Utils; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FStringTable : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FStripDataFlags.cs b/FModel/PakReader/Parsers/Objects/FStripDataFlags.cs index 649baecd..6f2c72e5 100644 --- a/FModel/PakReader/Parsers/Objects/FStripDataFlags.cs +++ b/FModel/PakReader/Parsers/Objects/FStripDataFlags.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FStripDataFlags { diff --git a/FModel/PakReader/Parsers/Objects/FText.cs b/FModel/PakReader/Parsers/Objects/FText.cs index 6c5c4958..36ecd309 100644 --- a/FModel/PakReader/Parsers/Objects/FText.cs +++ b/FModel/PakReader/Parsers/Objects/FText.cs @@ -1,7 +1,7 @@ -using Newtonsoft.Json; -using System; +using System; +using Newtonsoft.Json; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FText { @@ -9,6 +9,12 @@ namespace PakReader.Parsers.Objects public readonly ETextFlag Flags; public readonly FTextHistory Text; + internal FText(ETextFlag flags, FTextHistory text) + { + Flags = flags; + Text = text; + } + // https://github.com/EpicGames/UnrealEngine/blob/7d9919ac7bfd80b7483012eab342cb427d60e8c9/Engine/Source/Runtime/Core/Private/Internationalization/Text.cpp#L769 internal FText(PackageReader reader) { diff --git a/FModel/PakReader/Parsers/Objects/FTextHistory.cs b/FModel/PakReader/Parsers/Objects/FTextHistory.cs index 71c16976..a5f1a9a0 100644 --- a/FModel/PakReader/Parsers/Objects/FTextHistory.cs +++ b/FModel/PakReader/Parsers/Objects/FTextHistory.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public abstract partial class FTextHistory { diff --git a/FModel/PakReader/Parsers/Objects/FTextHistoryArgumentDataFormat.cs b/FModel/PakReader/Parsers/Objects/FTextHistoryArgumentDataFormat.cs index cb40ca12..13438e4d 100644 --- a/FModel/PakReader/Parsers/Objects/FTextHistoryArgumentDataFormat.cs +++ b/FModel/PakReader/Parsers/Objects/FTextHistoryArgumentDataFormat.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public partial class FTextHistory { diff --git a/FModel/PakReader/Parsers/Objects/FTextHistoryAsDate.cs b/FModel/PakReader/Parsers/Objects/FTextHistoryAsDate.cs index daad2260..2aff3d28 100644 --- a/FModel/PakReader/Parsers/Objects/FTextHistoryAsDate.cs +++ b/FModel/PakReader/Parsers/Objects/FTextHistoryAsDate.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public partial class FTextHistory { diff --git a/FModel/PakReader/Parsers/Objects/FTextHistoryAsTime.cs b/FModel/PakReader/Parsers/Objects/FTextHistoryAsTime.cs index 4ea3a4ee..184ba04d 100644 --- a/FModel/PakReader/Parsers/Objects/FTextHistoryAsTime.cs +++ b/FModel/PakReader/Parsers/Objects/FTextHistoryAsTime.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public partial class FTextHistory { diff --git a/FModel/PakReader/Parsers/Objects/FTextHistoryBase.cs b/FModel/PakReader/Parsers/Objects/FTextHistoryBase.cs index 72c77e6b..938ef448 100644 --- a/FModel/PakReader/Parsers/Objects/FTextHistoryBase.cs +++ b/FModel/PakReader/Parsers/Objects/FTextHistoryBase.cs @@ -1,6 +1,6 @@ using FModel.Utils; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public partial class FTextHistory { diff --git a/FModel/PakReader/Parsers/Objects/FTextHistoryDateTime.cs b/FModel/PakReader/Parsers/Objects/FTextHistoryDateTime.cs index 934e1f53..3dffc145 100644 --- a/FModel/PakReader/Parsers/Objects/FTextHistoryDateTime.cs +++ b/FModel/PakReader/Parsers/Objects/FTextHistoryDateTime.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public partial class FTextHistory { diff --git a/FModel/PakReader/Parsers/Objects/FTextHistoryFormatNumber.cs b/FModel/PakReader/Parsers/Objects/FTextHistoryFormatNumber.cs index ec16bb20..ac7d6cc1 100644 --- a/FModel/PakReader/Parsers/Objects/FTextHistoryFormatNumber.cs +++ b/FModel/PakReader/Parsers/Objects/FTextHistoryFormatNumber.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public partial class FTextHistory { diff --git a/FModel/PakReader/Parsers/Objects/FTextHistoryNone.cs b/FModel/PakReader/Parsers/Objects/FTextHistoryNone.cs index d1fd8e1b..7c1e5969 100644 --- a/FModel/PakReader/Parsers/Objects/FTextHistoryNone.cs +++ b/FModel/PakReader/Parsers/Objects/FTextHistoryNone.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public partial class FTextHistory { @@ -6,6 +6,11 @@ { public readonly string CultureInvariantString; + internal None() + { + CultureInvariantString = null; + } + // https://github.com/EpicGames/UnrealEngine/blob/5677c544747daa1efc3b5ede31642176644518a6/Engine/Source/Runtime/Core/Private/Internationalization/Text.cpp#L974 internal None(PackageReader reader) { diff --git a/FModel/PakReader/Parsers/Objects/FTextHistoryOrderedFormat.cs b/FModel/PakReader/Parsers/Objects/FTextHistoryOrderedFormat.cs index 868fdda4..b2eb163a 100644 --- a/FModel/PakReader/Parsers/Objects/FTextHistoryOrderedFormat.cs +++ b/FModel/PakReader/Parsers/Objects/FTextHistoryOrderedFormat.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public partial class FTextHistory { diff --git a/FModel/PakReader/Parsers/Objects/FTextHistoryStringTableEntry.cs b/FModel/PakReader/Parsers/Objects/FTextHistoryStringTableEntry.cs index 66eaa3b1..eb9f393e 100644 --- a/FModel/PakReader/Parsers/Objects/FTextHistoryStringTableEntry.cs +++ b/FModel/PakReader/Parsers/Objects/FTextHistoryStringTableEntry.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public partial class FTextHistory { diff --git a/FModel/PakReader/Parsers/Objects/FTextHistoryTransform.cs b/FModel/PakReader/Parsers/Objects/FTextHistoryTransform.cs index 91505af4..dc358b2b 100644 --- a/FModel/PakReader/Parsers/Objects/FTextHistoryTransform.cs +++ b/FModel/PakReader/Parsers/Objects/FTextHistoryTransform.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public partial class FTextHistory { diff --git a/FModel/PakReader/Parsers/Objects/FTextKey.cs b/FModel/PakReader/Parsers/Objects/FTextKey.cs index f55f20ea..433432fd 100644 --- a/FModel/PakReader/Parsers/Objects/FTextKey.cs +++ b/FModel/PakReader/Parsers/Objects/FTextKey.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FTextKey { diff --git a/FModel/PakReader/Parsers/Objects/FTexture2DMipMap.cs b/FModel/PakReader/Parsers/Objects/FTexture2DMipMap.cs index 231308c9..80855854 100644 --- a/FModel/PakReader/Parsers/Objects/FTexture2DMipMap.cs +++ b/FModel/PakReader/Parsers/Objects/FTexture2DMipMap.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FTexture2DMipMap { diff --git a/FModel/PakReader/Parsers/Objects/FTexturePlatformData.cs b/FModel/PakReader/Parsers/Objects/FTexturePlatformData.cs index ed5540d2..afb9a423 100644 --- a/FModel/PakReader/Parsers/Objects/FTexturePlatformData.cs +++ b/FModel/PakReader/Parsers/Objects/FTexturePlatformData.cs @@ -1,9 +1,7 @@ using System; using System.IO; -using FModel; - -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FTexturePlatformData { diff --git a/FModel/PakReader/Parsers/Objects/FUniqueObjectGuid.cs b/FModel/PakReader/Parsers/Objects/FUniqueObjectGuid.cs index 4812164e..57392fde 100644 --- a/FModel/PakReader/Parsers/Objects/FUniqueObjectGuid.cs +++ b/FModel/PakReader/Parsers/Objects/FUniqueObjectGuid.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FUniqueObjectGuid : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FVector.cs b/FModel/PakReader/Parsers/Objects/FVector.cs index 45489beb..0cf84d53 100644 --- a/FModel/PakReader/Parsers/Objects/FVector.cs +++ b/FModel/PakReader/Parsers/Objects/FVector.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FVector : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FVector2D.cs b/FModel/PakReader/Parsers/Objects/FVector2D.cs index 0b1d0a48..58275c80 100644 --- a/FModel/PakReader/Parsers/Objects/FVector2D.cs +++ b/FModel/PakReader/Parsers/Objects/FVector2D.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FVector2D : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FVector4.cs b/FModel/PakReader/Parsers/Objects/FVector4.cs index eaf12a46..29adcffe 100644 --- a/FModel/PakReader/Parsers/Objects/FVector4.cs +++ b/FModel/PakReader/Parsers/Objects/FVector4.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FVector4 : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FVectorMaterialInput.cs b/FModel/PakReader/Parsers/Objects/FVectorMaterialInput.cs index 985a9c97..7bd9a8a0 100644 --- a/FModel/PakReader/Parsers/Objects/FVectorMaterialInput.cs +++ b/FModel/PakReader/Parsers/Objects/FVectorMaterialInput.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FVectorMaterialInput : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/FVirtualTextureBuiltData.cs b/FModel/PakReader/Parsers/Objects/FVirtualTextureBuiltData.cs index 7d569367..0129bab9 100644 --- a/FModel/PakReader/Parsers/Objects/FVirtualTextureBuiltData.cs +++ b/FModel/PakReader/Parsers/Objects/FVirtualTextureBuiltData.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FVirtualTextureBuiltData { diff --git a/FModel/PakReader/Parsers/Objects/FVirtualTextureDataChunk.cs b/FModel/PakReader/Parsers/Objects/FVirtualTextureDataChunk.cs index 7a3bf1f7..05ce1072 100644 --- a/FModel/PakReader/Parsers/Objects/FVirtualTextureDataChunk.cs +++ b/FModel/PakReader/Parsers/Objects/FVirtualTextureDataChunk.cs @@ -1,6 +1,6 @@ using System.IO; -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct FVirtualTextureDataChunk { diff --git a/FModel/PakReader/Parsers/Objects/IUStruct.cs b/FModel/PakReader/Parsers/Objects/IUStruct.cs index d8ca7e19..37fbab35 100644 --- a/FModel/PakReader/Parsers/Objects/IUStruct.cs +++ b/FModel/PakReader/Parsers/Objects/IUStruct.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { // Used to signify if it is used in UScriptStruct binary serialization public interface IUStruct { } diff --git a/FModel/PakReader/Parsers/Objects/TEvaluationTreeEntryContainer.cs b/FModel/PakReader/Parsers/Objects/TEvaluationTreeEntryContainer.cs index 9fe3f9f0..1ac546d6 100644 --- a/FModel/PakReader/Parsers/Objects/TEvaluationTreeEntryContainer.cs +++ b/FModel/PakReader/Parsers/Objects/TEvaluationTreeEntryContainer.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct TEvaluationTreeEntryContainer : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/TMovieSceneEvaluationTree.cs b/FModel/PakReader/Parsers/Objects/TMovieSceneEvaluationTree.cs index f6ab72c8..eb30d6ba 100644 --- a/FModel/PakReader/Parsers/Objects/TMovieSceneEvaluationTree.cs +++ b/FModel/PakReader/Parsers/Objects/TMovieSceneEvaluationTree.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct TMovieSceneEvaluationTree { diff --git a/FModel/PakReader/Parsers/Objects/TRange.cs b/FModel/PakReader/Parsers/Objects/TRange.cs index eeebe057..84aa8637 100644 --- a/FModel/PakReader/Parsers/Objects/TRange.cs +++ b/FModel/PakReader/Parsers/Objects/TRange.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct TRange { diff --git a/FModel/PakReader/Parsers/Objects/TRangeBound.cs b/FModel/PakReader/Parsers/Objects/TRangeBound.cs index dbc94994..b8a19dd1 100644 --- a/FModel/PakReader/Parsers/Objects/TRangeBound.cs +++ b/FModel/PakReader/Parsers/Objects/TRangeBound.cs @@ -1,4 +1,4 @@ -namespace PakReader.Parsers.Objects +namespace FModel.PakReader.Parsers.Objects { public readonly struct TRangeBound : IUStruct { diff --git a/FModel/PakReader/Parsers/Objects/UScriptStruct.cs b/FModel/PakReader/Parsers/Objects/UScriptStruct.cs index 144e49e0..834e4f28 100644 --- a/FModel/PakReader/Parsers/Objects/UScriptStruct.cs +++ b/FModel/PakReader/Parsers/Objects/UScriptStruct.cs @@ -1,11 +1,15 @@ -using PakReader.Parsers.Class; +using System.Collections.Generic; +using System.Runtime.CompilerServices; -namespace PakReader.Parsers.Objects +using FModel.PakReader.IO; +using FModel.PakReader.Parsers.Class; + +namespace FModel.PakReader.Parsers.Objects { public readonly struct UScriptStruct { public readonly IUStruct Struct; - + // Binary serialization, tagged property serialization otherwise // https://github.com/EpicGames/UnrealEngine/blob/7d9919ac7bfd80b7483012eab342cb427d60e8c9/Engine/Source/Runtime/CoreUObject/Private/UObject/Class.cpp#L2146 internal UScriptStruct(PackageReader reader, FName structName) : this(reader, structName.String) { } @@ -18,6 +22,7 @@ namespace PakReader.Parsers.Objects { "LevelSequenceObjectReferenceMap" => new FLevelSequenceObjectReferenceMap(reader), "GameplayTagContainer" => new FGameplayTagContainer(reader), + //"GameplayTag" => new FGameplayTagContainer(reader), "NavAgentSelector" => new FNavAgentSelectorCustomization(reader), "Quat" => new FQuat(reader), "Vector4" => new FVector4(reader), @@ -54,8 +59,72 @@ namespace PakReader.Parsers.Objects "VectorMaterialInput" => new FVectorMaterialInput(reader), "ColorMaterialInput" => new FColorMaterialInput(reader), "ExpressionInput" => new FMaterialInput(reader), - _ => new UObject(reader, true), + // + "PrimaryAssetType" => new FPrimaryAssetType(reader), + "PrimaryAssetId" => new FPrimaryAssetId(reader), + _ => Fallback(reader, structName) }; } + + internal UScriptStruct(string structName) + { + Struct = structName switch + { + "LevelSequenceObjectReferenceMap" => new FLevelSequenceObjectReferenceMap(), + "GameplayTagContainer" => new FGameplayTagContainer(), + //"GameplayTag" => new FGameplayTagContainer(reader), + "NavAgentSelector" => new FNavAgentSelectorCustomization(), + "Quat" => new FQuat(), + "Vector4" => new FVector4(), + "Vector2D" => new FVector2D(), + "Box2D" => new FBox2D(), + "Box" => new FBox(), + "Vector" => new FVector(), + "Rotator" => new FRotator(), + "IntPoint" => new FIntPoint(), + "Guid" => new FGuid(), + "SoftObjectPath" => new FSoftObjectPath(), + "SoftClassPath" => new FSoftObjectPath(), + "Color" => new FColor(), + "LinearColor" => new FLinearColor(), + "SimpleCurveKey" => new FSimpleCurveKey(), + "RichCurveKey" => new FRichCurveKey(), + "FrameNumber" => new FFrameNumber(), + "SmartName" => new FSmartName(), + "PerPlatformFloat" => new FPerPlatformFloat(), + "PerPlatformInt" => new FPerPlatformInt(), + "DateTime" => new FDateTime(), + "Timespan" => new FDateTime(), + "MovieSceneTrackIdentifier" => new FFrameNumber(), + "MovieSceneSegmentIdentifier" => new FFrameNumber(), + "MovieSceneSequenceID" => new FFrameNumber(), + "MovieSceneSegment" => new FMovieSceneSegment(), + "SectionEvaluationDataTree" => new FSectionEvaluationDataTree(), + "MovieSceneFrameRange" => new FMovieSceneFrameRange(), + "MovieSceneEvaluationKey" => new FMovieSceneEvaluationKey(), + "MovieSceneFloatValue" => new FRichCurveKey(), + "MovieSceneFloatChannel" => new FMovieSceneFloatChannel(), + "MovieSceneEvaluationTemplate" => new FMovieSceneEvaluationTemplate(), + //"SkeletalMeshSamplingLODBuiltData" => new FSkeletalMeshSamplingLODBuiltData(reader), + "VectorMaterialInput" => new FVectorMaterialInput(), + "ColorMaterialInput" => new FColorMaterialInput(), + "ExpressionInput" => new FMaterialInput(), + // + "PrimaryAssetType" => new FPrimaryAssetType(), + "PrimaryAssetId" => new FPrimaryAssetId(), + _ => new UObject() + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static IUStruct Fallback(PackageReader reader, string structName) + { + if (reader is IoPackageReader ioReader) + { + return Globals.TypeMappings.TryGetValue(structName, out var structProperties) ? new UObject(ioReader, structProperties, true, structName) : new UObject(ioReader, new Dictionary(), true, structName); + } + + return new UObject(reader, true); + } } } diff --git a/FModel/PakReader/Parsers/OodleStream.cs b/FModel/PakReader/Parsers/OodleStream.cs index 497bc89c..1c94a868 100644 --- a/FModel/PakReader/Parsers/OodleStream.cs +++ b/FModel/PakReader/Parsers/OodleStream.cs @@ -3,7 +3,7 @@ using System.IO; using System.Runtime.InteropServices; using FModel.Utils; -namespace PakReader.Parsers +namespace FModel.PakReader.Parsers { /// /// https://gist.github.com/Scobalula/37229307de57de685d16ec621d5aceb5 diff --git a/FModel/PakReader/Parsers/PackageReader.cs b/FModel/PakReader/Parsers/PackageReader.cs index b3ba3fd2..8145086f 100644 --- a/FModel/PakReader/Parsers/PackageReader.cs +++ b/FModel/PakReader/Parsers/PackageReader.cs @@ -1,126 +1,19 @@ using System; using System.IO; -using System.Linq; using System.Runtime.CompilerServices; -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers +namespace FModel.PakReader.Parsers { - public sealed class PackageReader + public abstract class PackageReader { - BinaryReader Loader { get; } - - public FPackageFileSummary PackageFileSummary { get; } - FNameEntrySerialized[] NameMap { get; } - public FObjectImport[] ImportMap { get; } - public FObjectExport[] ExportMap { get; } - - public IUExport[] DataExports { get; } - public FName[] DataExportTypes { get; } - - public PackageReader(string uasset, string uexp, string ubulk) : this(File.OpenRead(uasset), File.OpenRead(uexp), File.Exists(ubulk) ? File.OpenRead(ubulk) : null) { } - public PackageReader(Stream uasset, Stream uexp, Stream ubulk) : this(new BinaryReader(uasset), new BinaryReader(uexp), ubulk) { } - - PackageReader(BinaryReader uasset, BinaryReader uexp, Stream ubulk) - { - Loader = uasset; - PackageFileSummary = new FPackageFileSummary(Loader); - - NameMap = SerializeNameMap(); - ImportMap = SerializeImportMap(); - ExportMap = SerializeExportMap(); - DataExports = new IUExport[ExportMap.Length]; - DataExportTypes = new FName[ExportMap.Length]; - Loader = uexp; - for(int i = 0; i < ExportMap.Length; i++) - { - FObjectExport Export = ExportMap[i]; - { - FName ExportType; - if (Export.ClassIndex.IsNull) - ExportType = DataExportTypes[i] = ReadFName(); // check if this is true, I don't know if Fortnite ever uses this - else if (Export.ClassIndex.IsExport) - ExportType = DataExportTypes[i] = ExportMap[Export.ClassIndex.AsExport].SuperIndex.Resource.ObjectName; - else if (Export.ClassIndex.IsImport) - ExportType = DataExportTypes[i] = ImportMap[Export.ClassIndex.AsImport].ObjectName; - else - throw new FileLoadException("Can't get class name"); // Shouldn't reach this unless the laws of math have bent to MagmaReef's will - - var pos = Position = Export.SerialOffset - PackageFileSummary.TotalHeaderSize; - DataExports[i] = ExportType.String switch - { - "Texture2D" => new UTexture2D(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), - "VirtualTexture2D" => new UTexture2D(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), - "CurveTable" => new UCurveTable(this), - "DataTable" => new UDataTable(this), - "FontFace" => new UFontFace(this, ubulk), - "SoundWave" => new USoundWave(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), - "StringTable" => new UStringTable(this), - "AkMediaAssetData" => new UAkMediaAssetData(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), - _ => new UObject(this), - }; - -#if DEBUG - if (pos + Export.SerialSize != Position) - { - System.Diagnostics.Debug.WriteLine($"[ExportType={ExportType.String}] Didn't read {Export.ObjectName} correctly (at {Position}, should be {pos + Export.SerialSize}, {pos + Export.SerialSize - Position} behind)"); - } -#endif - } - } - return; - } - - FNameEntrySerialized[] SerializeNameMap() - { - if (PackageFileSummary.NameCount > 0) - { - Loader.BaseStream.Position = PackageFileSummary.NameOffset; - - var OutNameMap = new FNameEntrySerialized[PackageFileSummary.NameCount]; - for (int NameMapIdx = 0; NameMapIdx < PackageFileSummary.NameCount; ++NameMapIdx) - { - // Read the name entry from the file. - OutNameMap[NameMapIdx] = new FNameEntrySerialized(Loader); - } - return OutNameMap; - } - return Array.Empty(); - } - - FObjectImport[] SerializeImportMap() - { - if (PackageFileSummary.ImportCount > 0) - { - Loader.BaseStream.Position = PackageFileSummary.ImportOffset; - - var OutImportMap = new FObjectImport[PackageFileSummary.ImportCount]; - for (int ImportMapIdx = 0; ImportMapIdx < PackageFileSummary.ImportCount; ++ImportMapIdx) - { - OutImportMap[ImportMapIdx] = new FObjectImport(this); - } - return OutImportMap; - } - return Array.Empty(); - } - - FObjectExport[] SerializeExportMap() - { - if (PackageFileSummary.ExportCount > 0) - { - Loader.BaseStream.Position = PackageFileSummary.ExportOffset; - - var OutExportMap = new FObjectExport[PackageFileSummary.ExportCount]; - for (int ExportMapIdx = 0; ExportMapIdx < PackageFileSummary.ExportCount; ++ExportMapIdx) - { - OutExportMap[ExportMapIdx] = new FObjectExport(this); - } - return OutExportMap; - } - return Array.Empty(); - } - + protected BinaryReader Loader { get; set; } + public abstract FNameEntrySerialized[] NameMap { get; } + public abstract IUExport[] DataExports { get; } + public abstract FName[] DataExportTypes { get; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public FName ReadFName() { @@ -169,7 +62,8 @@ namespace PakReader.Parsers public float ReadFloat() => Loader.ReadSingle(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public double ReadDouble() => Loader.ReadDouble(); + public void SkipBytes(int count) => Loader.BaseStream.Position += count; public long Position { get => Loader.BaseStream.Position; set => Loader.BaseStream.Position = value; } } -} +} \ No newline at end of file diff --git a/FModel/PakReader/Parsers/PropertyTagData/ArrayProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/ArrayProperty.cs index 5b5de5dd..0a2be946 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/ArrayProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/ArrayProperty.cs @@ -1,9 +1,13 @@ -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class ArrayProperty : BaseProperty { + internal ArrayProperty() + { + Value = new BaseProperty[0]; + } internal ArrayProperty(PackageReader reader, FPropertyTag tag) { Position = reader.Position; @@ -16,7 +20,7 @@ namespace PakReader.Parsers.PropertyTagData if (tag.InnerType.String == "StructProperty") { // Serialize a PropertyTag for the inner property of this array, allows us to validate the inner struct to see if it has changed - InnerTag = new FPropertyTag(reader); + InnerTag = reader is IoPackageReader ? tag : new FPropertyTag(reader); } for (int i = 0; i < length; i++) { diff --git a/FModel/PakReader/Parsers/PropertyTagData/BaseProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/BaseProperty.cs index f1227c78..ba211c18 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/BaseProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/BaseProperty.cs @@ -1,9 +1,43 @@ -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public class BaseProperty { + internal static BaseProperty ReadAsZeroObject(PackageReader reader, FPropertyTag tag, FName type) + { + BaseProperty prop = type.String switch + { + "ByteProperty" => new ByteProperty(), + "BoolProperty" => new BoolProperty(tag), + "IntProperty" => new IntProperty(), + "FloatProperty" => new FloatProperty(), + "ObjectProperty" => new ObjectProperty(reader, 0), + "NameProperty" => new NameProperty(), + "DelegateProperty" => new DelegateProperty(), + "DoubleProperty" => new DoubleProperty(), + "ArrayProperty" => new ArrayProperty(), + "StructProperty" => new StructProperty(tag), + "StrProperty" => new StrProperty(), + "TextProperty" => new TextProperty(), + "InterfaceProperty" => new InterfaceProperty(), + //"MulticastDelegateProperty" => new MulticastDelegateProperty(reader, tag), + //"LazyObjectProperty" => new LazyObjectProperty(reader, tag), + "SoftObjectProperty" => new SoftObjectProperty(), + "AssetObjectProperty" => new SoftObjectProperty(), + "UInt64Property" => new UInt64Property(), + "UInt32Property" => new UInt32Property(), + "UInt16Property" => new UInt16Property(), + "Int64Property" => new Int64Property(), + "Int16Property" => new Int16Property(), + "Int8Property" => new Int8Property(), + "MapProperty" => new MapProperty(), + "SetProperty" => new SetProperty(), + "EnumProperty" => new EnumProperty(tag), + _ => null, //throw new NotImplementedException($"Parsing of {type.String} types aren't supported yet."), + }; + return prop; + } internal static BaseProperty ReadAsObject(PackageReader reader, FPropertyTag tag, FName type, ReadType readType) { BaseProperty prop = type.String switch @@ -33,7 +67,7 @@ namespace PakReader.Parsers.PropertyTagData "Int8Property" => new Int8Property(reader), "MapProperty" => new MapProperty(reader, tag), "SetProperty" => new SetProperty(reader, tag), - "EnumProperty" => new EnumProperty(reader), + "EnumProperty" => new EnumProperty(reader, tag), _ => null, //throw new NotImplementedException($"Parsing of {type.String} types aren't supported yet."), }; return prop; @@ -68,7 +102,7 @@ namespace PakReader.Parsers.PropertyTagData "Int8Property" => new Int8Property(reader).Value, "MapProperty" => new MapProperty(reader, tag).Value, "SetProperty" => new SetProperty(reader, tag).Value, - "EnumProperty" => new EnumProperty(reader).Value, + "EnumProperty" => new EnumProperty(reader, tag).Value, _ => null, //throw new NotImplementedException($"Parsing of {type.String} types aren't supported yet."), }; return prop; diff --git a/FModel/PakReader/Parsers/PropertyTagData/BoolProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/BoolProperty.cs index 355856ec..bf10935b 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/BoolProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/BoolProperty.cs @@ -1,18 +1,23 @@ using System; -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class BoolProperty : BaseProperty { + internal BoolProperty(FPropertyTag tag) + { + Value = tag.BoolVal != 0; + } internal BoolProperty(PackageReader reader, FPropertyTag tag, ReadType readType) { switch (readType) { - case ReadType.NORMAL: + case ReadType.NORMAL when !(reader is IoPackageReader): Position = tag.Position; Value = tag.BoolVal != 0; break; + case ReadType.NORMAL: case ReadType.MAP: case ReadType.ARRAY: Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/ByteProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/ByteProperty.cs index 2a2fe8b7..c3f9fdff 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/ByteProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/ByteProperty.cs @@ -1,10 +1,15 @@ -using PakReader.Parsers.Objects; -using System; +using System; -namespace PakReader.Parsers.PropertyTagData +using FModel.PakReader.Parsers.Objects; + +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class ByteProperty : BaseProperty { + internal ByteProperty() + { + Value = 0; + } internal ByteProperty(PackageReader reader, FPropertyTag tag, ReadType readType) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/DelegateProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/DelegateProperty.cs index ae3f129b..286ffd2d 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/DelegateProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/DelegateProperty.cs @@ -1,13 +1,19 @@ -using PakReader.Parsers.Objects; -using System.Collections.Generic; +using System.Collections.Generic; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class DelegateProperty : BaseProperty { public int Object; public FName Name; + internal DelegateProperty() + { + Object = 0; + Name = new FName(); + } + internal DelegateProperty(PackageReader reader) { Object = reader.ReadInt32(); diff --git a/FModel/PakReader/Parsers/PropertyTagData/DoubleProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/DoubleProperty.cs index 220dbe61..dee86ea9 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/DoubleProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/DoubleProperty.cs @@ -1,7 +1,11 @@ -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class DoubleProperty : BaseProperty { + internal DoubleProperty() + { + Value = 0.0; + } internal DoubleProperty(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs index aa539a14..fc01386b 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs @@ -1,13 +1,45 @@ -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class EnumProperty : BaseProperty { - internal EnumProperty(PackageReader reader) + internal EnumProperty(FPropertyTag tag) + { + Value = new FName(ByteToEnum(tag.EnumName.String, 0)); + } + internal EnumProperty(PackageReader reader, FPropertyTag tag) { Position = reader.Position; - Value = reader.ReadFName(); + + if (reader is IoPackageReader) + { + var byteValue = reader.ReadByte(); + Value = new FName(ByteToEnum(tag.EnumName.String, byteValue)); + } + else + { + Value = reader.ReadFName(); + } + } + + private static string ByteToEnum(string enumName, byte value) + { + string result; + + if (enumName == null) + return value.ToString(); + + if (Globals.EnumMappings.TryGetValue(enumName, out var values)) + { + result = values.TryGetValue(value, out var member) ? string.Concat(enumName, "::", member) : string.Concat(enumName, "::", value); + } + else + { + result = string.Concat(enumName, "::", value); + } + + return result; } public string GetValue() => Value.String; diff --git a/FModel/PakReader/Parsers/PropertyTagData/FloatProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/FloatProperty.cs index 392869b0..7bddc6c3 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/FloatProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/FloatProperty.cs @@ -1,7 +1,11 @@ -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class FloatProperty : BaseProperty { + internal FloatProperty() + { + Value = 0f; + } internal FloatProperty(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/Int16Property.cs b/FModel/PakReader/Parsers/PropertyTagData/Int16Property.cs index a125c10b..4f8fed6d 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/Int16Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/Int16Property.cs @@ -1,7 +1,11 @@ -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class Int16Property : BaseProperty { + internal Int16Property() + { + Value = 0; + } internal Int16Property(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/Int64Property.cs b/FModel/PakReader/Parsers/PropertyTagData/Int64Property.cs index 88792973..ebaecc86 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/Int64Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/Int64Property.cs @@ -1,7 +1,11 @@ -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class Int64Property : BaseProperty { + internal Int64Property() + { + Value = 0; + } internal Int64Property(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/Int8Property.cs b/FModel/PakReader/Parsers/PropertyTagData/Int8Property.cs index 16638e73..e1bc19c1 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/Int8Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/Int8Property.cs @@ -1,7 +1,11 @@ -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class Int8Property : BaseProperty { + internal Int8Property() + { + Value = 0; + } internal Int8Property(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/IntProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/IntProperty.cs index ff03574c..28207241 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/IntProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/IntProperty.cs @@ -1,7 +1,11 @@ -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class IntProperty : BaseProperty { + internal IntProperty() + { + Value = 0; + } internal IntProperty(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/InterfaceProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/InterfaceProperty.cs index f6b263d1..cf6f3d65 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/InterfaceProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/InterfaceProperty.cs @@ -1,7 +1,11 @@ -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class InterfaceProperty : BaseProperty { + internal InterfaceProperty() + { + Value = 0; + } // Value is ObjectRef internal InterfaceProperty(PackageReader reader) { diff --git a/FModel/PakReader/Parsers/PropertyTagData/LazyObjectProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/LazyObjectProperty.cs index 93c7d0d3..a45fd754 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/LazyObjectProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/LazyObjectProperty.cs @@ -1,7 +1,7 @@ using System; -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class LazyObjectProperty : BaseProperty { diff --git a/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs index f02b4b84..9f818f0a 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs @@ -1,11 +1,15 @@ using System; using System.Collections.Generic; -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class MapProperty : BaseProperty> { + internal MapProperty() + { + Value = new Dictionary(); + } // https://github.com/EpicGames/UnrealEngine/blob/7d9919ac7bfd80b7483012eab342cb427d60e8c9/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertyMap.cpp#L243 internal MapProperty(PackageReader reader, FPropertyTag tag) { @@ -14,7 +18,12 @@ namespace PakReader.Parsers.PropertyTagData if (NumKeysToRemove != 0) { // Let me know if you find a package that has a non-zero NumKeysToRemove value - throw new NotImplementedException("Parsing of non-zero NumKeysToRemove maps aren't supported yet."); + //throw new NotImplementedException("Parsing of non-zero NumKeysToRemove maps aren't supported yet."); + + for (var i = 0; i < NumKeysToRemove; i++) + { + ReadAsValue(reader, tag, tag.InnerType, ReadType.MAP); + } } var NumEntries = reader.ReadInt32(); diff --git a/FModel/PakReader/Parsers/PropertyTagData/MulticastDelegateProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/MulticastDelegateProperty.cs index e9abc850..fc78efa6 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/MulticastDelegateProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/MulticastDelegateProperty.cs @@ -1,7 +1,7 @@ using System; -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class MulticastDelegateProperty : BaseProperty { diff --git a/FModel/PakReader/Parsers/PropertyTagData/NameProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/NameProperty.cs index 94dc8377..434afefc 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/NameProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/NameProperty.cs @@ -1,9 +1,13 @@ -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class NameProperty : BaseProperty { + internal NameProperty() + { + Value = new FName(); + } internal NameProperty(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/ObjectProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/ObjectProperty.cs index f7781922..e3b22e27 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/ObjectProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/ObjectProperty.cs @@ -1,9 +1,14 @@ -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class ObjectProperty : BaseProperty { + internal ObjectProperty(PackageReader reader, int index) + { + Value = new FPackageIndex(reader, index); + } + internal ObjectProperty(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/SetProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/SetProperty.cs index 67eae25f..2fdec43f 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/SetProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/SetProperty.cs @@ -1,9 +1,13 @@ -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class SetProperty : BaseProperty { + internal SetProperty() + { + Value = new object[0]; + } // https://github.com/EpicGames/UnrealEngine/blob/bf95c2cbc703123e08ab54e3ceccdd47e48d224a/Engine/Source/Runtime/CoreUObject/Private/UObject/PropertySet.cpp#L216 internal SetProperty(PackageReader reader, FPropertyTag tag) { diff --git a/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs index 87e6f1bf..ca4900a9 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs @@ -1,10 +1,14 @@ -using PakReader.Parsers.Objects; -using System.Collections.Generic; +using System.Collections.Generic; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class SoftObjectProperty : BaseProperty { + internal SoftObjectProperty() + { + Value = new FSoftObjectPath(); + } internal SoftObjectProperty(PackageReader reader, ReadType readType) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/StrProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/StrProperty.cs index 3e4d945c..e7ca9f21 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/StrProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/StrProperty.cs @@ -1,7 +1,11 @@ -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class StrProperty : BaseProperty { + internal StrProperty() + { + Value = null; + } internal StrProperty(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/StructProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/StructProperty.cs index eff74f1f..787b5fc1 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/StructProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/StructProperty.cs @@ -1,10 +1,15 @@ -using PakReader.Parsers.Class; -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class StructProperty : BaseProperty { + internal StructProperty(FPropertyTag tag) + { + Value = null; + Value = new UScriptStruct(tag.StructName.String).Struct; + } internal StructProperty(PackageReader reader, FPropertyTag tag) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/TextProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/TextProperty.cs index ede499ed..b921117a 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/TextProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/TextProperty.cs @@ -1,9 +1,13 @@ -using PakReader.Parsers.Objects; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class TextProperty : BaseProperty { + internal TextProperty() + { + Value = new FText(ETextFlag.Immutable, new FTextHistory.None()); + } internal TextProperty(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/UInt16Property.cs b/FModel/PakReader/Parsers/PropertyTagData/UInt16Property.cs index 67c6a7af..afce4d8f 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/UInt16Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/UInt16Property.cs @@ -1,7 +1,11 @@ -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class UInt16Property : BaseProperty { + internal UInt16Property() + { + Value = 0; + } internal UInt16Property(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/UInt32Property.cs b/FModel/PakReader/Parsers/PropertyTagData/UInt32Property.cs index a59b67fa..b79ff622 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/UInt32Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/UInt32Property.cs @@ -1,7 +1,11 @@ -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class UInt32Property : BaseProperty { + internal UInt32Property() + { + Value = 0; + } internal UInt32Property(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/Parsers/PropertyTagData/UInt64Property.cs b/FModel/PakReader/Parsers/PropertyTagData/UInt64Property.cs index 822cb589..1dc71601 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/UInt64Property.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/UInt64Property.cs @@ -1,7 +1,11 @@ -namespace PakReader.Parsers.PropertyTagData +namespace FModel.PakReader.Parsers.PropertyTagData { public sealed class UInt64Property : BaseProperty { + internal UInt64Property() + { + Value = 0; + } internal UInt64Property(PackageReader reader) { Position = reader.Position; diff --git a/FModel/PakReader/ReaderEntry.cs b/FModel/PakReader/ReaderEntry.cs new file mode 100644 index 00000000..bfe78ed2 --- /dev/null +++ b/FModel/PakReader/ReaderEntry.cs @@ -0,0 +1,54 @@ +using System.Runtime.CompilerServices; + +namespace FModel.PakReader +{ + public abstract class ReaderEntry + { + public abstract string Name { get; } + + public abstract string ContainerName { get; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsUE4Package() => Name[Name.LastIndexOf(".")..].Equals(".uasset"); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsLocres() => Name[Name.LastIndexOf(".")..].Equals(".locres"); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsUE4Map() => Name[Name.LastIndexOf(".")..].Equals(".umap"); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsUE4Font() => Name[Name.LastIndexOf(".")..].Equals(".ufont"); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public string GetExtension() => Name[Name.LastIndexOf(".")..]; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public string GetPathWithoutFile() + { + int stop = Name.LastIndexOf("/"); + if (stop <= -1) + stop = 0; + return Name.Substring(0, stop); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public string GetPathWithoutExtension() => Name.Substring(0, Name.LastIndexOf(".")); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public string GetNameWithExtension() => Name.Substring(Name.LastIndexOf("/") + 1); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public string GetNameWithoutExtension() + { + int start = Name.LastIndexOf("/") + 1; + int stop = Name.LastIndexOf(".") - start; + return Name.Substring(start, stop); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public string GetFirstFolder() => Name.Substring(Name.StartsWith('/') ? 1 : 0, Name.IndexOf('/')); + + public ReaderEntry Uexp = null; + public ReaderEntry Ubulk = null; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasUexp() => Uexp != null; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasUbulk() => Ubulk != null; + + public override string ToString() => Name; + } +} \ No newline at end of file diff --git a/FModel/PakReader/ReaderExtensions.cs b/FModel/PakReader/ReaderExtensions.cs index a486e2ee..fe3b46d6 100644 --- a/FModel/PakReader/ReaderExtensions.cs +++ b/FModel/PakReader/ReaderExtensions.cs @@ -3,7 +3,7 @@ using System.IO; using System.Runtime.CompilerServices; using System.Text; -namespace PakReader +namespace FModel.PakReader { static class ReaderExtensions { diff --git a/FModel/PakReader/Textures/ASTC/ASTCDecoder.cs b/FModel/PakReader/Textures/ASTC/ASTCDecoder.cs index 49f0aa56..08f627c0 100644 --- a/FModel/PakReader/Textures/ASTC/ASTCDecoder.cs +++ b/FModel/PakReader/Textures/ASTC/ASTCDecoder.cs @@ -3,7 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; -namespace PakReader.Textures.ASTC +namespace FModel.PakReader.Textures.ASTC { public class ASTCDecoderException : Exception { diff --git a/FModel/PakReader/Textures/ASTC/ASTCPixel.cs b/FModel/PakReader/Textures/ASTC/ASTCPixel.cs index 4edc7488..f7dfc893 100644 --- a/FModel/PakReader/Textures/ASTC/ASTCPixel.cs +++ b/FModel/PakReader/Textures/ASTC/ASTCPixel.cs @@ -1,6 +1,6 @@ using System; -namespace PakReader.Textures.ASTC +namespace FModel.PakReader.Textures.ASTC { class ASTCPixel { diff --git a/FModel/PakReader/Textures/ASTC/BitArrayStream.cs b/FModel/PakReader/Textures/ASTC/BitArrayStream.cs index 7f008c1e..9d8523a0 100644 --- a/FModel/PakReader/Textures/ASTC/BitArrayStream.cs +++ b/FModel/PakReader/Textures/ASTC/BitArrayStream.cs @@ -1,7 +1,7 @@ using System; using System.Collections; -namespace PakReader.Textures.ASTC +namespace FModel.PakReader.Textures.ASTC { public class BitArrayStream { diff --git a/FModel/PakReader/Textures/ASTC/IntegerEncoded.cs b/FModel/PakReader/Textures/ASTC/IntegerEncoded.cs index 925f306d..b3d40de1 100644 --- a/FModel/PakReader/Textures/ASTC/IntegerEncoded.cs +++ b/FModel/PakReader/Textures/ASTC/IntegerEncoded.cs @@ -1,7 +1,7 @@ using System.Collections; using System.Collections.Generic; -namespace PakReader.Textures.ASTC +namespace FModel.PakReader.Textures.ASTC { public struct IntegerEncoded { diff --git a/FModel/PakReader/Textures/BC/BCDecoder.cs b/FModel/PakReader/Textures/BC/BCDecoder.cs index a37fc96f..08919110 100644 --- a/FModel/PakReader/Textures/BC/BCDecoder.cs +++ b/FModel/PakReader/Textures/BC/BCDecoder.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace PakReader.Textures.BC +namespace FModel.PakReader.Textures.BC { public static class BCDecoder { diff --git a/FModel/PakReader/Textures/BC/Detex.cs b/FModel/PakReader/Textures/BC/Detex.cs index bcd032aa..1c50caf1 100644 --- a/FModel/PakReader/Textures/BC/Detex.cs +++ b/FModel/PakReader/Textures/BC/Detex.cs @@ -6,7 +6,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography; -namespace PakReader.Textures.BC +namespace FModel.PakReader.Textures.BC { public static class Detex { diff --git a/FModel/PakReader/Textures/BC/DetexCompressedTextureFormatIndex.cs b/FModel/PakReader/Textures/BC/DetexCompressedTextureFormatIndex.cs index 88d1b30c..d8133cd1 100644 --- a/FModel/PakReader/Textures/BC/DetexCompressedTextureFormatIndex.cs +++ b/FModel/PakReader/Textures/BC/DetexCompressedTextureFormatIndex.cs @@ -1,4 +1,4 @@ -namespace PakReader.Textures.BC +namespace FModel.PakReader.Textures.BC { internal enum DetexCompressedTextureFormatIndex : uint { diff --git a/FModel/PakReader/Textures/BC/DetexPixelFormat.cs b/FModel/PakReader/Textures/BC/DetexPixelFormat.cs index 9dcc2f0b..cb906c0f 100644 --- a/FModel/PakReader/Textures/BC/DetexPixelFormat.cs +++ b/FModel/PakReader/Textures/BC/DetexPixelFormat.cs @@ -1,4 +1,4 @@ -namespace PakReader.Textures.BC +namespace FModel.PakReader.Textures.BC { public enum DetexPixelFormat : uint { diff --git a/FModel/PakReader/Textures/BC/DetexTextureFormat.cs b/FModel/PakReader/Textures/BC/DetexTextureFormat.cs index 23247a13..5bb66c68 100644 --- a/FModel/PakReader/Textures/BC/DetexTextureFormat.cs +++ b/FModel/PakReader/Textures/BC/DetexTextureFormat.cs @@ -1,4 +1,4 @@ -namespace PakReader.Textures.BC +namespace FModel.PakReader.Textures.BC { public enum DetexTextureFormat : uint { diff --git a/FModel/PakReader/Textures/DXT/DXTDecoder.cs b/FModel/PakReader/Textures/DXT/DXTDecoder.cs index 10438af6..93cb90f8 100644 --- a/FModel/PakReader/Textures/DXT/DXTDecoder.cs +++ b/FModel/PakReader/Textures/DXT/DXTDecoder.cs @@ -1,4 +1,4 @@ -namespace PakReader.Textures.DXT +namespace FModel.PakReader.Textures.DXT { public static class DXTDecoder { diff --git a/FModel/PakReader/Textures/TextureDecoder.cs b/FModel/PakReader/Textures/TextureDecoder.cs index 835358b1..0605537e 100644 --- a/FModel/PakReader/Textures/TextureDecoder.cs +++ b/FModel/PakReader/Textures/TextureDecoder.cs @@ -1,13 +1,13 @@ using System; -using PakReader.Parsers.Objects; -using PakReader.Textures.ASTC; -using PakReader.Textures.BC; -using PakReader.Textures.DXT; +using FModel.PakReader.Parsers.Objects; +using FModel.PakReader.Textures.ASTC; +using FModel.PakReader.Textures.BC; +using FModel.PakReader.Textures.DXT; using SkiaSharp; -namespace PakReader.Textures +namespace FModel.PakReader.Textures { - static class TextureDecoder + public static class TextureDecoder { public static SKImage DecodeImage(byte[] sequence, int width, int height, int depth, EPixelFormat format) { diff --git a/FModel/PakReader/Textures/TextureFormatHelper.cs b/FModel/PakReader/Textures/TextureFormatHelper.cs index 622c04c6..2b5345b4 100644 --- a/FModel/PakReader/Textures/TextureFormatHelper.cs +++ b/FModel/PakReader/Textures/TextureFormatHelper.cs @@ -1,7 +1,7 @@ -using PakReader.Parsers.Objects; -using System.Collections.Generic; +using System.Collections.Generic; +using FModel.PakReader.Parsers.Objects; -namespace PakReader.Textures +namespace FModel.PakReader.Textures { public class TextureFormatHelper { diff --git a/FModel/PakReader/WwiseReader.cs b/FModel/PakReader/WwiseReader.cs index efd6eaea..ffa62ed5 100644 --- a/FModel/PakReader/WwiseReader.cs +++ b/FModel/PakReader/WwiseReader.cs @@ -1,10 +1,10 @@ -using FModel.Utils; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Text; +using FModel.Utils; -namespace PakReader +namespace FModel.PakReader { /// /// http://wiki.xentax.com/index.php/Wwise_SoundBank_(*.bnk) diff --git a/FModel/Utils/Assets.cs b/FModel/Utils/Assets.cs index 1ca584e7..061764bc 100644 --- a/FModel/Utils/Assets.cs +++ b/FModel/Utils/Assets.cs @@ -1,15 +1,11 @@ -using PakReader.Pak; using System; using System.Linq; using System.Collections.Generic; -using PakReader.Parsers.Class; using FModel.ViewModels.ImageBox; using Newtonsoft.Json; using FModel.Logger; -using PakReader.Parsers.Objects; using System.IO; using FModel.ViewModels.AvalonEdit; -using PakReader; using System.Threading.Tasks; using FModel.ViewModels.StatusBar; using System.Collections; @@ -26,6 +22,11 @@ using FModel.ViewModels.DataGrid; using ICSharpCode.AvalonEdit.Highlighting; using static FModel.Creator.Creator; using System.Runtime.CompilerServices; +using FModel.PakReader; +using FModel.PakReader.IO; +using FModel.PakReader.Pak; +using FModel.PakReader.Parsers.Class; +using FModel.PakReader.Parsers.Objects; namespace FModel.Utils { @@ -36,7 +37,7 @@ namespace FModel.Utils /// PakPackage to get the properties of the asset /// ArraySegment[] to export the raw data /// - private static readonly Dictionary[]>> _CachedFiles = new Dictionary[]>>(); + private static readonly Dictionary[]>> _CachedFiles = new Dictionary[]>>(); private static Stopwatch _timer; public static void ClearCachedFiles() => _CachedFiles.Clear(); @@ -67,10 +68,11 @@ namespace FModel.Utils Thread.Sleep(10); // this is actually useful because it smh unfreeze the ui so the user can cancel even tho it's a Task so... if (item is ListBoxViewModel selected) { - if (Globals.CachedPakFiles.TryGetValue(selected.PakEntry.PakFileName, out var r)) + FFileIoStoreReader io = null; + if (Globals.CachedPakFiles.TryGetValue(selected.ReaderEntry.ContainerName, out var r) || Globals.CachedIoStores.TryGetValue(selected.ReaderEntry.ContainerName, out io)) { - string mount = r.MountPoint; - string ext = selected.PakEntry.GetExtension(); + string mount = r != null ? r.MountPoint : io!.MountPoint; + string ext = selected.ReaderEntry.GetExtension(); switch (ext) { case ".ini": @@ -92,77 +94,77 @@ namespace FModel.Utils ".h" => AvalonEditVm.CppHighlighter, _ => AvalonEditVm.JsonHighlighter }; - using var asset = GetMemoryStream(selected.PakEntry.PakFileName, mount + selected.PakEntry.GetPathWithoutExtension()); + using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; using var reader = new StreamReader(asset); - AvalonEditVm.avalonEditViewModel.Set(reader.ReadToEnd(), mount + selected.PakEntry.Name, syntax); + AvalonEditVm.avalonEditViewModel.Set(reader.ReadToEnd(), mount + selected.ReaderEntry.Name, syntax); break; } case ".locmeta": { - using var asset = GetMemoryStream(selected.PakEntry.PakFileName, mount + selected.PakEntry.GetPathWithoutExtension()); + using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; - AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new LocMetaReader(asset), Formatting.Indented), mount + selected.PakEntry.Name); + AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new LocMetaReader(asset), Formatting.Indented), mount + selected.ReaderEntry.Name); break; } case ".locres": { - using var asset = GetMemoryStream(selected.PakEntry.PakFileName, mount + selected.PakEntry.GetPathWithoutExtension()); + using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; - AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new LocResReader(asset).Entries, Formatting.Indented), mount + selected.PakEntry.Name); + AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new LocResReader(asset).Entries, Formatting.Indented), mount + selected.ReaderEntry.Name); break; } case ".udic": { - using var asset = GetMemoryStream(selected.PakEntry.PakFileName, mount + selected.PakEntry.GetPathWithoutExtension()); + using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; - AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new FOodleDictionaryArchive(asset).Header, Formatting.Indented), mount + selected.PakEntry.Name); + AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new FOodleDictionaryArchive(asset).Header, Formatting.Indented), mount + selected.ReaderEntry.Name); break; } case ".bin": { if ( - !selected.PakEntry.Name.Equals("FortniteGame/AssetRegistry.bin") && // this file is 85mb... - selected.PakEntry.Name.Contains("AssetRegistry")) // only parse AssetRegistry (basically the ones in dynamic paks) + !selected.ReaderEntry.Name.Equals("FortniteGame/AssetRegistry.bin") && // this file is 85mb... + selected.ReaderEntry.Name.Contains("AssetRegistry")) // only parse AssetRegistry (basically the ones in dynamic paks) { - using var asset = GetMemoryStream(selected.PakEntry.PakFileName, mount + selected.PakEntry.GetPathWithoutExtension()); + using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; - AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new FAssetRegistryState(asset), Formatting.Indented), mount + selected.PakEntry.Name); + AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new FAssetRegistryState(asset), Formatting.Indented), mount + selected.ReaderEntry.Name); } break; } case ".bnk": case ".pck": { - using var asset = GetMemoryStream(selected.PakEntry.PakFileName, mount + selected.PakEntry.GetPathWithoutExtension()); + using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; WwiseReader bnk = new WwiseReader(new BinaryReader(asset)); Application.Current.Dispatcher.Invoke(delegate { - DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Window]", $"Opening Audio Player for {selected.PakEntry.GetNameWithExtension()}"); + DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Window]", $"Opening Audio Player for {selected.ReaderEntry.GetNameWithExtension()}"); if (!FWindows.IsWindowOpen(Properties.Resources.AudioPlayer)) - new AudioPlayer().LoadFiles(bnk.AudioFiles, mount + selected.PakEntry.GetPathWithoutFile()); + new AudioPlayer().LoadFiles(bnk.AudioFiles, mount + selected.ReaderEntry.GetPathWithoutFile()); else - ((AudioPlayer)FWindows.GetOpenedWindow(Properties.Resources.AudioPlayer)).LoadFiles(bnk.AudioFiles, mount + selected.PakEntry.GetPathWithoutFile()); + ((AudioPlayer)FWindows.GetOpenedWindow(Properties.Resources.AudioPlayer)).LoadFiles(bnk.AudioFiles, mount + selected.ReaderEntry.GetPathWithoutFile()); }); break; } case ".png": { - using var asset = GetMemoryStream(selected.PakEntry.PakFileName, mount + selected.PakEntry.GetPathWithoutExtension()); + using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension()); asset.Position = 0; - ImageBoxVm.imageBoxViewModel.Set(SKBitmap.Decode(asset), mount + selected.PakEntry.Name); + ImageBoxVm.imageBoxViewModel.Set(SKBitmap.Decode(asset), mount + selected.ReaderEntry.Name); break; } case ".ushaderbytecode": break; default: - AvalonEditVm.avalonEditViewModel.Set(GetJsonProperties(selected.PakEntry, mount, true), mount + selected.PakEntry.Name); + AvalonEditVm.avalonEditViewModel.Set(GetJsonProperties(selected.ReaderEntry, mount, true), mount + selected.ReaderEntry.Name); break; } if (Properties.Settings.Default.AutoExport) - Export(selected.PakEntry, true); + Export(selected.ReaderEntry, true); } } } @@ -189,14 +191,23 @@ namespace FModel.Utils return new MemoryStream(uasset.Array, uasset.Offset, uasset.Count); } } + } else if (Globals.CachedIoStores.TryGetValue(pakName, out var ioStore)) + { + if (ioStore.IsInitialized && ioStore.TryGetFile(pathWithoutExtension, out ArraySegment uasset, out _, out _)) + { + if (uasset != null) + { + return new MemoryStream(uasset.Array, uasset.Offset, uasset.Count); + } + } } return null; } - public static string GetJsonProperties(FPakEntry entry, string mount) => GetJsonProperties(entry, mount, false); - public static string GetJsonProperties(FPakEntry entry, string mount, bool loadContent) + public static string GetJsonProperties(ReaderEntry entry, string mount) => GetJsonProperties(entry, mount, false); + public static string GetJsonProperties(ReaderEntry entry, string mount, bool loadContent) { - PakPackage p = GetPakPackage(entry, mount, loadContent); + Package p = GetPackage(entry, mount, loadContent); if (!p.Equals(default)) { return p.JsonData; @@ -204,10 +215,10 @@ namespace FModel.Utils return string.Empty; } - public static PakPackage GetPakPackage(FPakEntry entry, string mount) => GetPakPackage(entry, mount, false); - public static PakPackage GetPakPackage(FPakEntry entry, string mount, bool loadContent) + public static Package GetPackage(ReaderEntry entry, string mount) => GetPackage(entry, mount, false); + public static Package GetPackage(ReaderEntry entry, string mount, bool loadContent) { - TryGetPakPackage(entry, mount, out var p); + TryGetPackage(entry, mount, out var p); if (loadContent) { @@ -302,7 +313,7 @@ namespace FModel.Utils return p; } - private static bool TryGetPakPackage(FPakEntry entry, string mount, out PakPackage package) + private static bool TryGetPackage(ReaderEntry entry, string mount, out Package package) { DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[Assets]", "[Package]", $"Searching for '{mount + entry.Name}'s package"); if (_CachedFiles.TryGetValue(entry, out var dict)) @@ -311,30 +322,47 @@ namespace FModel.Utils return true; } - if (Globals.CachedPakFiles.TryGetValue(entry.PakFileName, out PakFileReader pak)) + if (Globals.CachedPakFiles.TryGetValue(entry.ContainerName, out PakFileReader pak)) { if (pak.Initialized && pak.TryGetFile(mount + entry.GetPathWithoutExtension(), out ArraySegment uasset, out ArraySegment uexp, out ArraySegment ubulk)) { package = new PakPackage(uasset, uexp, ubulk); - _CachedFiles[entry] = new Dictionary[]> + _CachedFiles[entry] = new Dictionary[]> { [package] = new ArraySegment[] { uasset, uexp, ubulk } }; return true; } } + else if (entry is FIoStoreEntry ioStoreEntry) + { + var uasset = ioStoreEntry.GetData(); + var uexp = (ioStoreEntry.Uexp as FIoStoreEntry)?.GetData(); + var ubulk = (ioStoreEntry.Ubulk as FIoStoreEntry)?.GetData(); + if (uexp != null) + package = new PakPackage(uasset, uexp, ubulk); + else + package = new IoPackage(uasset, ubulk, ioStoreEntry); +#if !DEBUG + _CachedFiles[entry] = new Dictionary[]> + { + [package] = new ArraySegment[] { uasset, uexp, ubulk } + }; +#endif + return true; + } DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[Assets]", "[Package]", $"No package found for '{mount + entry.Name}'"); package = default; return false; } - public static ArraySegment[] GetArraySegmentByte(FPakEntry entry, string mount) + public static ArraySegment[] GetArraySegmentByte(ReaderEntry entry, string mount) { TryGetArraySegmentByte(entry, mount, out var b); return b; } - private static bool TryGetArraySegmentByte(FPakEntry entry, string mount, out ArraySegment[] arraySegment) + private static bool TryGetArraySegmentByte(ReaderEntry entry, string mount, out ArraySegment[] arraySegment) { DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[Assets]", "[ArraySegment]", $"Searching for '{mount + entry.Name}'s ArraySegment"); if (_CachedFiles.TryGetValue(entry, out var dict)) @@ -343,13 +371,20 @@ namespace FModel.Utils return true; } - if (Globals.CachedPakFiles.TryGetValue(entry.PakFileName, out PakFileReader pak)) + if (Globals.CachedPakFiles.TryGetValue(entry.ContainerName, out PakFileReader pak)) { if (pak.Initialized && pak.TryGetFile(mount + entry.GetPathWithoutExtension(), out ArraySegment uasset, out ArraySegment uexp, out ArraySegment ubulk)) { arraySegment = new ArraySegment[] { uasset, uexp, ubulk }; return true; } + } else if (entry is FIoStoreEntry ioStoreEntry) + { + var uasset = ioStoreEntry.GetData(); + var uexp = (ioStoreEntry.Uexp as FIoStoreEntry)?.GetData(); + var ubulk = (ioStoreEntry.Ubulk as FIoStoreEntry)?.GetData(); + arraySegment = new ArraySegment[] { uasset, uexp, ubulk }; + return true; } DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[Assets]", "[ArraySegment]", $"No ArraySegment found for '{mount + entry.Name}'"); @@ -368,16 +403,17 @@ namespace FModel.Utils bSearch = item.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0; } - public static void Export(FPakEntry entry, bool autoSave) + public static void Export(ReaderEntry entry, bool autoSave) { switch (entry.GetExtension()) { case ".uasset": // embedded data export case ".umap": // embedded data export { - if (Globals.CachedPakFiles.TryGetValue(entry.PakFileName, out var r)) + FFileIoStoreReader io = null; + if (Globals.CachedPakFiles.TryGetValue(entry.ContainerName, out var r) || Globals.CachedIoStores.TryGetValue(entry.ContainerName, out io)) { - string mount = r.MountPoint; + string mount = r != null ? r.MountPoint : io!.MountPoint; if (TryGetArraySegmentByte(entry, mount, out var data)) { string[] ext = string.Join(":", entry.GetExtension(), entry.Uexp?.GetExtension(), entry.Ubulk?.GetExtension()).Split(':'); @@ -411,14 +447,16 @@ namespace FModel.Utils } default: // single data export { - if (Globals.CachedPakFiles.TryGetValue(entry.PakFileName, out var r)) + FFileIoStoreReader io = null; + if (Globals.CachedPakFiles.TryGetValue(entry.ContainerName, out var r) || Globals.CachedIoStores.TryGetValue(entry.ContainerName, out io)) { - string basePath = Properties.Settings.Default.OutputPath + "\\Exports\\" + r.MountPoint[1..]; + string mount = r != null ? r.MountPoint : io!.MountPoint; + string basePath = Properties.Settings.Default.OutputPath + "\\Exports\\" + mount[1..]; string fullPath = basePath + entry.Name; string name = Path.GetFileName(fullPath); Directory.CreateDirectory(basePath + entry.GetPathWithoutFile()); - using var data = GetMemoryStream(entry.PakFileName, r.MountPoint + entry.GetPathWithoutExtension()); + using var data = GetMemoryStream(entry.ContainerName, mount + entry.GetPathWithoutExtension()); using var stream = new FileStream(fullPath, FileMode.Create, FileAccess.Write); data.WriteTo(stream); @@ -430,7 +468,7 @@ namespace FModel.Utils else Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.DataExported, name, string.Empty, fullPath)); } - } + } else {} break; } } @@ -443,7 +481,7 @@ namespace FModel.Utils { foreach (ListBoxViewModel selectedItem in entries) { - sb.AppendLine(Copy(selectedItem.PakEntry, mode)); + sb.AppendLine(Copy(selectedItem.ReaderEntry, mode)); } } else if (entries[0] is DataGridViewModel) @@ -456,11 +494,16 @@ namespace FModel.Utils Copy(sb.ToString().Trim()); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static string Copy(FPakEntry entry, ECopy mode) + public static string Copy(ReaderEntry entry, ECopy mode) { - if (Globals.CachedPakFiles.TryGetValue(entry.PakFileName, out var r)) + FFileIoStoreReader io = null; + if (Globals.CachedPakFiles.TryGetValue(entry.ContainerName, out var r) || Globals.CachedIoStores.TryGetValue(entry.ContainerName, out io)) { - string toCopy = r.MountPoint[1..]; + string toCopy; + if (r != null) + toCopy = r.MountPoint.Substring(1); + else + toCopy = io!.MountPoint[1..]; if (mode == ECopy.Path) toCopy += entry.Name; else if (mode == ECopy.PathNoExt) diff --git a/FModel/Utils/BitArrays.cs b/FModel/Utils/BitArrays.cs new file mode 100644 index 00000000..b70fc961 --- /dev/null +++ b/FModel/Utils/BitArrays.cs @@ -0,0 +1,19 @@ +using System.Collections; + +namespace FModel.Utils +{ + public static class BitArrays + { + + public static bool Contains(this BitArray array, bool search) + { + for (var i = 0; i < array.Count; i++) + { + if (array[i]) + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/FModel/Utils/ByteOrderSwap.cs b/FModel/Utils/ByteOrderSwap.cs new file mode 100644 index 00000000..c80053ae --- /dev/null +++ b/FModel/Utils/ByteOrderSwap.cs @@ -0,0 +1,12 @@ +namespace FModel.Utils +{ + public static class ByteOrderSwap + { + public static ulong IntelOrder64(this ulong value) + { + value = ((value << 8) & 0xFF00FF00FF00FF00UL ) | ((value >> 8) & 0x00FF00FF00FF00FFUL); + value = ((value << 16) & 0xFFFF0000FFFF0000UL ) | ((value >> 16) & 0x0000FFFF0000FFFFUL); + return (value << 32) | (value >> 32); + } + } +} \ No newline at end of file diff --git a/FModel/Utils/Commands.cs b/FModel/Utils/Commands.cs index 1b066a83..69e2754d 100644 --- a/FModel/Utils/Commands.cs +++ b/FModel/Utils/Commands.cs @@ -12,5 +12,6 @@ namespace FModel.Utils public static readonly RoutedUICommand AutoSaveImage = new RoutedUICommand(string.Empty, "AutoSaveImage", typeof(MainWindow)); public static readonly RoutedUICommand AutoOpenSounds = new RoutedUICommand(string.Empty, "AutoOpenSounds", typeof(MainWindow)); public static readonly RoutedUICommand OpenImageDoubleClick = new RoutedUICommand(string.Empty, "OpenImageDoubleClick", typeof(MainWindow)); + public static readonly RoutedUICommand ReloadTypeMappings = new RoutedUICommand(string.Empty, "ReloadTypeMappings", typeof(MainWindow)); } } diff --git a/FModel/Utils/EGL2.cs b/FModel/Utils/EGL2.cs index 1b760102..87a352c4 100644 --- a/FModel/Utils/EGL2.cs +++ b/FModel/Utils/EGL2.cs @@ -15,7 +15,7 @@ namespace FModel.Utils string configFile = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\EGL2\\config"; if (File.Exists(configFile)) { - using Stream stream = new BufferedStream(new FileInfo(configFile).Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); + using Stream stream = new FileInfo(configFile).Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using BinaryReader reader = new BinaryReader(stream, Encoding.Default); if (reader.ReadUInt32() != FILE_CONFIG_MAGIC) return string.Empty; diff --git a/FModel/Utils/Endpoints.cs b/FModel/Utils/Endpoints.cs index aa325ad3..e07932e8 100644 --- a/FModel/Utils/Endpoints.cs +++ b/FModel/Utils/Endpoints.cs @@ -14,6 +14,8 @@ namespace FModel.Utils static class Endpoints { public static readonly FortniteApi FortniteAPI = new FortniteApi($"FModel/{Assembly.GetExecutingAssembly().GetName().Version}"); + public const string FORTNITE_TYPE_MAPPINGS = "https://raw.githubusercontent.com/FabianFG/FortniteTypeMappings/master/TypeMappings.json"; + public const string FORTNITE_ENUM_MAPPINGS = "https://raw.githubusercontent.com/FabianFG/FortniteTypeMappings/master/EnumMappings.json"; public const string BENBOT_AES = "https://benbotfn.tk/api/v1/aes"; public const string BENBOT_HOTFIXES = "https://benbotfn.tk/api/v1/hotfixes"; public const string FMODEL_JSON = "https://dl.dropbox.com/s/sxyaqo6zu1drlea/FModel.json?dl=0"; @@ -54,11 +56,7 @@ namespace FModel.Utils try { using HttpResponseMessage httpResponseMessage = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false); - using Stream stream = await httpResponseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false); - if (httpResponseMessage.IsSuccessStatusCode) - { - return await Streams.StreamToStringAsync(stream).ConfigureAwait(false); - } + return await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); } catch (Exception) { diff --git a/FModel/Utils/Keys.cs b/FModel/Utils/Keys.cs index 72086496..4fc2023f 100644 --- a/FModel/Utils/Keys.cs +++ b/FModel/Utils/Keys.cs @@ -2,10 +2,10 @@ using FModel.ViewModels.MenuItem; using FModel.ViewModels.StatusBar; using Newtonsoft.Json; -using PakReader; -using PakReader.Parsers.Objects; using System; using System.Collections.Generic; +using FModel.PakReader; +using FModel.PakReader.Parsers.Objects; namespace FModel.Utils { @@ -21,7 +21,7 @@ namespace FModel.Utils if (MenuItems.pakFiles.AtLeastOnePak()) { if (disableAll) - foreach (PakMenuItemViewModel menuItem in MenuItems.pakFiles.GetMenuItemsWithPakFiles()) + foreach (PakMenuItemViewModel menuItem in MenuItems.pakFiles.GetMenuItemsWithReaders()) menuItem.IsEnabled = false; else { @@ -41,14 +41,21 @@ namespace FModel.Utils bool mainError = false; // used to avoid notifications about all static paks not working with the key StatusBarVm.statusBarViewModel.Reset(); - foreach (PakMenuItemViewModel menuItem in MenuItems.pakFiles.GetMenuItemsWithPakFiles()) + foreach (PakMenuItemViewModel menuItem in MenuItems.pakFiles.GetMenuItemsWithReaders()) { // reset everyone - menuItem.PakFile.AesKey = null; + + if (menuItem.IsPakFileReader) + menuItem.PakFile.AesKey = null; + else + menuItem.IoStore.AesKey = null; if (!mainError && isMainKey) { - if (menuItem.PakFile.Info.EncryptionKeyGuid.Equals(new FGuid(0u, 0u, 0u, 0u)) && + var encryptionKeyGuid = menuItem.IsPakFileReader + ? menuItem.PakFile.Info.EncryptionKeyGuid + : menuItem.IoStore.EncryptionKeyGuid; + if (encryptionKeyGuid.Equals(new FGuid(0u, 0u, 0u, 0u)) && staticKeys.TryGetValue(Globals.Game.ActualGame.ToString(), out var sKey)) { sKey = sKey.StartsWith("0x") ? sKey[2..].ToUpperInvariant() : sKey.ToUpperInvariant(); @@ -56,7 +63,10 @@ namespace FModel.Utils { // i can use TestAesKey here but that means it's gonna test here then right after to set the key // so a try catch when setting the key seems better - menuItem.PakFile.AesKey = sKey.Trim().ToBytesKey(); + if (menuItem.IsPakFileReader) + menuItem.PakFile.AesKey = sKey.Trim().ToBytesKey(); + else + menuItem.IoStore.AesKey = sKey.Trim().ToBytesKey(); } catch (System.Exception e) { @@ -71,12 +81,19 @@ namespace FModel.Utils } } + var fileName = menuItem.IsPakFileReader + ? menuItem.PakFile.FileName + : menuItem.IoStore.FileName; string trigger; { if (Properties.Settings.Default.PakPath.EndsWith(".manifest")) - trigger = $"{menuItem.PakFile.Directory.Replace('\\', '/')}/{menuItem.PakFile.FileName}"; + trigger = $"{menuItem.PakFile.Directory.Replace('\\', '/')}/{fileName}"; else - trigger = $"{Properties.Settings.Default.PakPath[Properties.Settings.Default.PakPath.LastIndexOf(Folders.GetGameName(), StringComparison.Ordinal)..].Replace("\\", "/")}/{menuItem.PakFile.FileName}"; + trigger = $"{Properties.Settings.Default.PakPath[Properties.Settings.Default.PakPath.LastIndexOf(Folders.GetGameName(), StringComparison.Ordinal)..].Replace("\\", "/")}/{fileName}"; + } + if (!trigger.EndsWith(".pak")) + { + trigger = trigger.Substring(0, trigger.LastIndexOf('.')) + ".pak"; } if (dynamicKeys.TryGetValue(Globals.Game.ActualGame.ToString(), out var gameDict) && gameDict.TryGetValue(trigger, out var key)) { @@ -85,17 +102,22 @@ namespace FModel.Utils { // i can use TestAesKey here but that means it's gonna test here then right after to set the key // so a try catch when setting the key seems better - menuItem.PakFile.AesKey = dKey.Trim().ToBytesKey(); + if (menuItem.IsPakFileReader) + menuItem.PakFile.AesKey = dKey.Trim().ToBytesKey(); + else + menuItem.IoStore.AesKey = dKey.Trim().ToBytesKey(); } catch (System.Exception e) { StatusBarVm.statusBarViewModel.Set(e.Message, Properties.Resources.Error); - FConsole.AppendText(string.Format(Properties.Resources.DynamicKeyNotWorking, $"0x{dKey}", menuItem.PakFile.FileName), FColors.Red, true); - DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[AES]", $"0x{dKey} is NOT!!!! working with {menuItem.PakFile.FileName}"); + FConsole.AppendText(string.Format(Properties.Resources.DynamicKeyNotWorking, $"0x{dKey}", fileName), FColors.Red, true); + DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[AES]", $"0x{dKey} is NOT!!!! working with {fileName}"); } } - menuItem.IsEnabled = menuItem.PakFile.AesKey != null || !menuItem.PakFile.Info.bEncryptedIndex; + menuItem.IsEnabled = menuItem.IsPakFileReader + ? menuItem.PakFile.AesKey != null || !menuItem.PakFile.Info.bEncryptedIndex + : menuItem.IoStore.HasDirectoryIndex && (menuItem.IoStore.AesKey != null || !menuItem.IoStore.IsEncrypted); } MenuItems.pakFiles[1].IsEnabled = MenuItems.pakFiles.AtLeastOnePakWithKey(); diff --git a/FModel/Utils/Localizations.cs b/FModel/Utils/Localizations.cs index b4ad30f8..dc5206c5 100644 --- a/FModel/Utils/Localizations.cs +++ b/FModel/Utils/Localizations.cs @@ -1,11 +1,11 @@ using FModel.Creator.Texts; using FModel.Logger; using FModel.ViewModels.StatusBar; -using PakReader; using System.Collections.Generic; using System.Net.NetworkInformation; using System.Text.RegularExpressions; using System.Threading.Tasks; +using FModel.PakReader; namespace FModel.Utils { @@ -64,7 +64,7 @@ namespace FModel.Utils if (m != null && m.Success) { - DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[Localizations]", "[GameDict]", $"Feeding with {KvP.Value.Name} from {KvP.Value.PakFileName} Miam Miam!"); + DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[Localizations]", "[GameDict]", $"Feeding with {KvP.Value.Name} from {KvP.Value.ContainerName} Miam Miam!"); using var asset = Assets.GetMemoryStream(fileReader.FileName, mount + KvP.Value.GetPathWithoutExtension()); asset.Position = 0; diff --git a/FModel/Utils/MathUtils.cs b/FModel/Utils/MathUtils.cs new file mode 100644 index 00000000..82638e89 --- /dev/null +++ b/FModel/Utils/MathUtils.cs @@ -0,0 +1,10 @@ +using System.Runtime.CompilerServices; + +namespace FModel.Utils +{ + public static class MathUtils + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int DivideAndRoundUp(this int dividend, int divisor) => (dividend + divisor - 1) / divisor; + } +} \ No newline at end of file diff --git a/FModel/Utils/Paks.cs b/FModel/Utils/Paks.cs index 6ea7dcc9..1e4a10fc 100644 --- a/FModel/Utils/Paks.cs +++ b/FModel/Utils/Paks.cs @@ -1,11 +1,11 @@ using FModel.Grabber.Paks; using FModel.Logger; using Newtonsoft.Json; -using PakReader.Parsers.Objects; using System.Collections.Generic; using System.IO; using System; using Windows.Management.Deployment; +using FModel.PakReader; namespace FModel.Utils { @@ -189,10 +189,10 @@ namespace FModel.Utils return string.Empty; } - public static void Merge(Dictionary tempFiles, out Dictionary files, string mount) + public static void Merge(Dictionary tempFiles, out Dictionary files, string mount) where T : ReaderEntry { - files = new Dictionary(); - foreach (FPakEntry entry in tempFiles.Values) + files = new Dictionary(); + foreach (var entry in tempFiles.Values) { if (files.ContainsKey(mount + entry.GetPathWithoutExtension()) || entry.GetExtension().Equals(".uptnl") || @@ -205,18 +205,18 @@ namespace FModel.Utils if (!tempFiles.ContainsKey(Path.ChangeExtension(entry.Name, ".umap"))) // but not including a .umap { string e = Path.ChangeExtension(entry.Name, ".uexp"); - FPakEntry uexp = tempFiles.ContainsKey(e) ? tempFiles[e] : null; // add its uexp + var uexp = tempFiles.ContainsKey(e) ? tempFiles[e] : null; // add its uexp if (uexp != null) entry.Uexp = uexp; string u = Path.ChangeExtension(entry.Name, ".ubulk"); - FPakEntry ubulk = tempFiles.ContainsKey(u) ? tempFiles[u] : null; // add its ubulk + var ubulk = tempFiles.ContainsKey(u) ? tempFiles[u] : null; // add its ubulk if (ubulk != null) entry.Ubulk = ubulk; else { string f = Path.ChangeExtension(entry.Name, ".ufont"); - FPakEntry ufont = tempFiles.ContainsKey(f) ? tempFiles[f] : null; // add its ufont + var ufont = tempFiles.ContainsKey(f) ? tempFiles[f] : null; // add its ufont if (ufont != null) entry.Ubulk = ufont; } @@ -226,10 +226,10 @@ namespace FModel.Utils { string e = Path.ChangeExtension(entry.Name, ".uexp"); string u = Path.ChangeExtension(entry.Name, ".ubulk"); - FPakEntry uexp = tempFiles.ContainsKey(e) ? tempFiles[e] : null; // add its uexp + var uexp = tempFiles.ContainsKey(e) ? tempFiles[e] : null; // add its uexp if (uexp != null) entry.Uexp = uexp; - FPakEntry ubulk = tempFiles.ContainsKey(u) ? tempFiles[u] : null; // add its ubulk + var ubulk = tempFiles.ContainsKey(u) ? tempFiles[u] : null; // add its ubulk if (ubulk != null) entry.Ubulk = ubulk; } diff --git a/FModel/Utils/Strings.cs b/FModel/Utils/Strings.cs index 57c2ec39..7bd6de43 100644 --- a/FModel/Utils/Strings.cs +++ b/FModel/Utils/Strings.cs @@ -4,7 +4,8 @@ using System.Text.RegularExpressions; namespace FModel.Utils { - static class Strings + + public static class Strings { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string GetReadableSize(double size) @@ -45,5 +46,72 @@ namespace FModel.Utils int sep = fixedPath.LastIndexOf('.'); return fixedPath.Substring(0, sep > 0 ? sep : fixedPath.Length); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string SubstringBefore(this string s, char delimiter) + { + var index = s.IndexOf(delimiter); + return index == -1 ? s : s.Substring(0, index); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string SubstringBefore(this string s, string delimiter, StringComparison comparisonType = StringComparison.Ordinal) + { + var index = s.IndexOf(delimiter, comparisonType); + return index == -1 ? s : s.Substring(0, index); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string SubstringAfter(this string s, char delimiter) + { + var index = s.IndexOf(delimiter); + return index == -1 ? s : s.Substring(index + 1, s.Length - index - 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string SubstringAfter(this string s, string delimiter, StringComparison comparisonType = StringComparison.Ordinal) + { + var index = s.IndexOf(delimiter, comparisonType); + return index == -1 ? s : s.Substring(index + delimiter.Length, s.Length - index - delimiter.Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string SubstringBeforeLast(this string s, char delimiter) + { + var index = s.LastIndexOf(delimiter); + return index == -1 ? s : s.Substring(0, index); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string SubstringBeforeWithLast(this string s, char delimiter) + { + var index = s.LastIndexOf(delimiter); + return index == -1 ? s : s.Substring(0, index + 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string SubstringBeforeLast(this string s, string delimiter, StringComparison comparisonType = StringComparison.Ordinal) + { + var index = s.LastIndexOf(delimiter, comparisonType); + return index == -1 ? s : s.Substring(0, index); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string SubstringAfterLast(this string s, char delimiter) + { + var index = s.LastIndexOf(delimiter); + return index == -1 ? s : s.Substring(index + 1, s.Length - index - 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string SubstringAfterLast(this string s, string delimiter, StringComparison comparisonType = StringComparison.Ordinal) + { + var index = s.LastIndexOf(delimiter, comparisonType); + return index == -1 ? s : s.Substring(index + delimiter.Length, s.Length - index - delimiter.Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool Contains(this string orig, string value, StringComparison comparisonType) => + orig.IndexOf(value, comparisonType) >= 0; } } diff --git a/FModel/ViewModels/DataGrid/DataGridViewModel.cs b/FModel/ViewModels/DataGrid/DataGridViewModel.cs index 3ba1fbaa..398e2a89 100644 --- a/FModel/ViewModels/DataGrid/DataGridViewModel.cs +++ b/FModel/ViewModels/DataGrid/DataGridViewModel.cs @@ -1,5 +1,4 @@ -using PakReader.Parsers.Objects; -using System.Collections.ObjectModel; +using System.Collections.ObjectModel; using System.Windows; namespace FModel.ViewModels.DataGrid @@ -8,7 +7,7 @@ namespace FModel.ViewModels.DataGrid { public static ObservableCollection dataGridViewModel = new ObservableCollection(); - public static void Add(this ObservableCollection vm, string name, string ext, string pakfile) + public static void Add(this ObservableCollection vm, string name, string ext, string containerFile) { Application.Current.Dispatcher.Invoke(delegate { @@ -16,7 +15,7 @@ namespace FModel.ViewModels.DataGrid { Name = name, Extensions = ext, - PakFile = pakfile + ContainerFile = containerFile }); }); } @@ -40,12 +39,12 @@ namespace FModel.ViewModels.DataGrid set { this.SetProperty(ref this._extensions, value); } } - private string _pakFile; - public string PakFile + private string _containerFile; + public string ContainerFile { - get { return _pakFile; } + get { return _containerFile; } - set { this.SetProperty(ref this._pakFile, value); } + set { this.SetProperty(ref this._containerFile, value); } } } } diff --git a/FModel/ViewModels/ListBox/ListBoxViewModel.cs b/FModel/ViewModels/ListBox/ListBoxViewModel.cs index 6bbd4bef..39533311 100644 --- a/FModel/ViewModels/ListBox/ListBoxViewModel.cs +++ b/FModel/ViewModels/ListBox/ListBoxViewModel.cs @@ -1,6 +1,6 @@ using FModel.Utils; -using PakReader.Parsers.Objects; using System; +using FModel.PakReader; namespace FModel.ViewModels.ListBox { @@ -27,12 +27,12 @@ namespace FModel.ViewModels.ListBox set { this.SetProperty(ref this._content, value); } } - private FPakEntry _pakEntry; - public FPakEntry PakEntry + private ReaderEntry _readerEntry; + public ReaderEntry ReaderEntry { - get { return _pakEntry; } + get { return _readerEntry; } - set { this.SetProperty(ref this._pakEntry, value); } + set { this.SetProperty(ref this._readerEntry, value); } } } diff --git a/FModel/ViewModels/MenuItem/BackupMenuItemViewModel.cs b/FModel/ViewModels/MenuItem/BackupMenuItemViewModel.cs index 5fbffcec..465a2f3c 100644 --- a/FModel/ViewModels/MenuItem/BackupMenuItemViewModel.cs +++ b/FModel/ViewModels/MenuItem/BackupMenuItemViewModel.cs @@ -5,7 +5,6 @@ using FModel.Windows.CustomNotifier; using FModel.Windows.DarkMessageBox; using K4os.Compression.LZ4; using K4os.Compression.LZ4.Streams; -using PakReader.Pak; using System; using System.Collections.ObjectModel; using System.Diagnostics; @@ -14,6 +13,8 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using FModel.PakReader.Pak; +using FModel.PakReader.Parsers.Objects; namespace FModel.ViewModels.MenuItem { @@ -172,26 +173,26 @@ namespace FModel.ViewModels.MenuItem writer.Write(entry.CompressionMethodIndex); // uexp - if (entry.Uexp != null) + if (entry.Uexp != null && entry.Uexp is FPakEntry uexp) { - writer.Write(entry.Uexp.Offset); - writer.Write(entry.Uexp.Size); - writer.Write(entry.Uexp.UncompressedSize); - writer.Write(entry.Uexp.Encrypted); - writer.Write(entry.Uexp.StructSize); + writer.Write(uexp.Offset); + writer.Write(uexp.Size); + writer.Write(uexp.UncompressedSize); + writer.Write(uexp.Encrypted); + writer.Write(uexp.StructSize); writer.Write(pakFile.MountPoint + entry.Uexp.Name); - writer.Write(entry.Uexp.CompressionMethodIndex); + writer.Write(uexp.CompressionMethodIndex); } // ubulk - if (entry.Ubulk != null) + if (entry.Ubulk != null && entry.Ubulk is FPakEntry ubulk) { - writer.Write(entry.Ubulk.Offset); - writer.Write(entry.Ubulk.Size); - writer.Write(entry.Ubulk.UncompressedSize); - writer.Write(entry.Ubulk.Encrypted); - writer.Write(entry.Ubulk.StructSize); + writer.Write(ubulk.Offset); + writer.Write(ubulk.Size); + writer.Write(ubulk.UncompressedSize); + writer.Write(ubulk.Encrypted); + writer.Write(ubulk.StructSize); writer.Write(pakFile.MountPoint + entry.Ubulk.Name); - writer.Write(entry.Ubulk.CompressionMethodIndex); + writer.Write(ubulk.CompressionMethodIndex); } } } diff --git a/FModel/ViewModels/MenuItem/MenuItems.cs b/FModel/ViewModels/MenuItem/MenuItems.cs index 5ec414d5..3bf6b1be 100644 --- a/FModel/ViewModels/MenuItem/MenuItems.cs +++ b/FModel/ViewModels/MenuItem/MenuItems.cs @@ -1,7 +1,5 @@ using FModel.Windows.UserInput; using Newtonsoft.Json; -using PakReader.Pak; -using PakReader.Parsers.Objects; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -9,6 +7,9 @@ using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; +using FModel.PakReader.IO; +using FModel.PakReader.Pak; +using FModel.PakReader.Parsers.Objects; namespace FModel.ViewModels.MenuItem { @@ -107,12 +108,20 @@ namespace FModel.ViewModels.MenuItem Application.Current.Dispatcher.Invoke(() => o.Any(x => !x.GetType().Equals(typeof(Separator)) && x.PakFile != null)); public static bool AtLeastOnePakWithKey(this ObservableCollection o) => Application.Current.Dispatcher.Invoke(() => o.Any(x => !x.GetType().Equals(typeof(Separator)) && x.PakFile != null && (x.PakFile.AesKey != null || !x.PakFile.Info.bEncryptedIndex))); + public static IEnumerable GetMenuItemsWithReaders(this ObservableCollection o) => + Application.Current.Dispatcher.Invoke(() => o.Where(x => !x.GetType().Equals(typeof(Separator)) && x.HasReader).Select(x => (PakMenuItemViewModel)x)); public static IEnumerable GetMenuItemsWithPakFiles(this ObservableCollection o) => - Application.Current.Dispatcher.Invoke(() => o.Where(x => !x.GetType().Equals(typeof(Separator)) && x.PakFile != null).Select(x => (PakMenuItemViewModel)x)); - public static int GetPakCount(this ObservableCollection o) => - Application.Current.Dispatcher.Invoke(() => o.GetMenuItemsWithPakFiles().Count()); + Application.Current.Dispatcher.Invoke(() => o.GetMenuItemsWithReaders().Where(x => x.IsPakFileReader)); + public static IEnumerable GetMenuItemsWithIoStores(this ObservableCollection o) => + Application.Current.Dispatcher.Invoke(() => o.GetMenuItemsWithReaders().Where(x => x.IsIoStoreReader)); + public static int GetReaderCount(this ObservableCollection o) => + Application.Current.Dispatcher.Invoke(() => o.GetMenuItemsWithReaders().Count()); public static IEnumerable GetPakFileReaders(this ObservableCollection o) => Application.Current.Dispatcher.Invoke(() => o.GetMenuItemsWithPakFiles().Select(x => x.PakFile)); + public static IEnumerable GetIoStoreReaders(this ObservableCollection o) => + Application.Current.Dispatcher.Invoke(() => o.GetMenuItemsWithIoStores().Select(x => x.IoStore)); + public static IEnumerable GetDynamicIoStoreReaders(this ObservableCollection o) => + Application.Current.Dispatcher.Invoke(() => o.GetIoStoreReaders().Where(x => x.IsEncrypted && !x.TocResource.Header.EncryptionKeyGuid.Equals(new FGuid(0u, 0u, 0u, 0u)))); public static IEnumerable GetDynamicPakFileReaders(this ObservableCollection o) => Application.Current.Dispatcher.Invoke(() => o.GetPakFileReaders().Where(x => x.Info.bEncryptedIndex && !x.Info.EncryptionKeyGuid.Equals(new FGuid(0u, 0u, 0u, 0u)))); } diff --git a/FModel/ViewModels/MenuItem/PakMenuItemViewModel.cs b/FModel/ViewModels/MenuItem/PakMenuItemViewModel.cs index 05aa1043..f25822bf 100644 --- a/FModel/ViewModels/MenuItem/PakMenuItemViewModel.cs +++ b/FModel/ViewModels/MenuItem/PakMenuItemViewModel.cs @@ -10,11 +10,10 @@ using FModel.ViewModels.TabControl; using FModel.ViewModels.Treeview; using K4os.Compression.LZ4.Streams; using Microsoft.Win32; -using PakReader.Pak; -using PakReader.Parsers.Objects; using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -22,6 +21,10 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; +using FModel.PakReader; +using FModel.PakReader.IO; +using FModel.PakReader.Pak; +using FModel.PakReader.Parsers.Objects; namespace FModel.ViewModels.MenuItem { @@ -34,13 +37,14 @@ namespace FModel.ViewModels.MenuItem private bool _staysOpenOnClick = false; private string _inputGestureText; private Image _icon; + private FFileIoStoreReader _ioStore; private PakFileReader _pakFile; private PakMenuItemViewModel _parent; private ObservableCollection _childrens; public string Header { - get { return PakFile != null ? PakFile.FileName : _header; } + get { return IsPakFileReader ? PakFile.FileName : IsIoStoreReader ? IoStore.FileName : _header; } set { this.SetProperty(ref this._header, value); } } @@ -72,7 +76,7 @@ namespace FModel.ViewModels.MenuItem { get { - long size = PakFile != null ? PakFile.Stream.Length : 0; + long size = IsPakFileReader ? PakFile.Stream.Length : (IsIoStoreReader ? IoStore.ContainerFile.FileSize : 0); if (size > 0) return Strings.GetReadableSize(size); else @@ -87,6 +91,16 @@ namespace FModel.ViewModels.MenuItem set { this.SetProperty(ref this._icon, value); } } + + + public bool HasReader => IsPakFileReader || IsIoStoreReader; + public bool IsPakFileReader => _pakFile != null; + public bool IsIoStoreReader => _ioStore != null; + public FFileIoStoreReader IoStore + { + get => _ioStore; + set => SetProperty(ref _ioStore, value); + } public PakFileReader PakFile { get { return _pakFile ?? null; } @@ -157,7 +171,7 @@ namespace FModel.ViewModels.MenuItem Header.Equals(Properties.Resources.NewModifiedFiles); private async void SinglePakLoader() => await LoadPakFiles(EPakLoader.Single).ConfigureAwait(false); - private bool SinglePakLoaderCanExecute() => PakFile != null; + private bool SinglePakLoaderCanExecute() => IsPakFileReader || IsIoStoreReader; private async void AllPaksLoader() => await LoadPakFiles(EPakLoader.All).ConfigureAwait(false); private bool AllPaksLoaderCanExecute() => Header.Equals(Properties.Resources.LoadAll); private async void NewFilesLoader() => await LoadPakFiles(EPakLoader.New).ConfigureAwait(false); @@ -182,8 +196,15 @@ namespace FModel.ViewModels.MenuItem { if (mode == EPakLoader.Single) { - StatusBarVm.statusBarViewModel.Set($"{Properties.Settings.Default.PakPath}\\{PakFile.FileName}", Properties.Resources.Loading); - DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PakMenuItemViewModel]", "[Loader]", $"{PakFile.FileName} was selected ({mode})"); + if (IsPakFileReader) + { + StatusBarVm.statusBarViewModel.Set($"{Properties.Settings.Default.PakPath}\\{PakFile.FileName}", Properties.Resources.Loading); + DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PakMenuItemViewModel]", "[Loader]", $"{PakFile.FileName} was selected ({mode})"); + } else if (IsIoStoreReader) + { + StatusBarVm.statusBarViewModel.Set($"{Properties.Settings.Default.PakPath}\\{IoStore.FileName}", Properties.Resources.Loading); + DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PakMenuItemViewModel]", "[Loader]", $"{IoStore.FileName} was selected ({mode})"); + } } else { @@ -206,13 +227,56 @@ namespace FModel.ViewModels.MenuItem } } - if (mode == EPakLoader.Single) PakPropertiesVm.pakPropertiesViewModel.Set(PakFile); + FFileIoStoreReader globalReader = null; + foreach (var 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; + + if (mode != EPakLoader.Single) + StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.MountedPakTo, ioStore.FileName, ioStore.MountPoint), Properties.Resources.Loading); + } + } + + if (globalReader != null) + { + try + { + Globals.GlobalData = new FIoGlobalData(globalReader, Globals.CachedIoStores.Values); + DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PakMenuItemViewModel]", + "[Loader]", + $"Loaded global io data with {Globals.GlobalData.GlobalNameMap.Length} names and {Globals.GlobalData.ScriptObjectByGlobalId.Count} script objects"); + } + catch (Exception e) + { + DebugHelper.WriteException(e, "Failed to load global io data"); + } + } + + if (mode == EPakLoader.Single) + { + if (IsPakFileReader) + PakPropertiesVm.pakPropertiesViewModel.Set(PakFile); + else if (IsIoStoreReader) + PakPropertiesVm.pakPropertiesViewModel.Set(IoStore); + } await Localizations.SetLocalization(Properties.Settings.Default.AssetsLanguage, false).ConfigureAwait(false); PopulateTreeviewViewModel(mode); }).ContinueWith(t => { DiscordIntegration.Update( - $"{Globals.CachedPakFiles.Count}/{MenuItems.pakFiles.GetPakCount()} {Properties.Resources.PakFiles}", + $"{Globals.CachedPakFiles.Count}/{MenuItems.pakFiles.GetReaderCount()} {Properties.Resources.PakFiles}", string.Format("{0} - {1}", Globals.Game.GetName(), mode == EPakLoader.All ? Properties.Resources.AllFiles : mode == EPakLoader.New ? Properties.Resources.NewFiles : @@ -220,14 +284,23 @@ namespace FModel.ViewModels.MenuItem mode == EPakLoader.NewModified ? Properties.Resources.NewModifiedFiles : mode == EPakLoader.Single ? Header : string.Empty - )); + )); if (t.Exception != null) Tasks.TaskCompleted(t.Exception); - else StatusBarVm.statusBarViewModel.Set( - mode == EPakLoader.Single ? - $"{Properties.Settings.Default.PakPath}\\{PakFile.FileName}" : - Properties.Settings.Default.PakPath, - Properties.Resources.Success); + else + { + if (mode == EPakLoader.Single) + { + if (IsPakFileReader) + StatusBarVm.statusBarViewModel.Set($"{Properties.Settings.Default.PakPath}\\{PakFile.FileName}", Properties.Resources.Success); + else if (IsIoStoreReader) + StatusBarVm.statusBarViewModel.Set($"{Properties.Settings.Default.PakPath}\\{IoStore.FileName}", Properties.Resources.Success); + } + else + { + StatusBarVm.statusBarViewModel.Set(Properties.Settings.Default.PakPath, Properties.Resources.Success); + } + } }, TaskScheduler.FromCurrentSynchronizationContext()); @@ -346,11 +419,16 @@ namespace FModel.ViewModels.MenuItem switch (mode) { case EPakLoader.Single: - PopulateProcess(Globals.CachedPakFiles[PakFile.FileName]); + if (IsPakFileReader) + PopulateProcess(Globals.CachedPakFiles[PakFile.FileName]); + else if (IsIoStoreReader) + PopulateProcess(Globals.CachedIoStores[IoStore.FileName]); break; case EPakLoader.All: foreach (var fileReader in Globals.CachedPakFiles) PopulateProcess(fileReader.Value); + foreach (var fileReader in Globals.CachedIoStores) + PopulateProcess(fileReader.Value); break; case EPakLoader.New: case EPakLoader.Modified: @@ -361,11 +439,11 @@ namespace FModel.ViewModels.MenuItem DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PakMenuItemViewModel]", "[Loader]", "Treeview populated"); } - private void PopulateProcess(IReadOnlyDictionary array) + private void PopulateProcess(IReadOnlyDictionary array) where T : ReaderEntry { Application.Current.Dispatcher.Invoke(delegate { - foreach (KeyValuePair entry in array) + foreach (KeyValuePair entry in array) { string path = entry.Key.Substring(1) + entry.Value.GetExtension(); Populate(SortedTreeviewVm.gameFilesPath, path.Substring(0, path.LastIndexOf("/")), path, entry.Value); @@ -378,11 +456,11 @@ namespace FModel.ViewModels.MenuItem entry.Value.GetExtension(), entry.Value.Uexp?.GetExtension(), entry.Value.Ubulk?.GetExtension()).TrimEnd(), - entry.Value.PakFileName); + entry.Value.ContainerName); } }); } - private void Populate(dynamic nodeList, string pathWithoutFile, string seqPath, FPakEntry entry) + private void Populate(dynamic nodeList, string pathWithoutFile, string seqPath, T entry) where T : ReaderEntry { string folder; int p = seqPath.IndexOf('/'); @@ -419,7 +497,7 @@ namespace FModel.ViewModels.MenuItem nodeList.GameFiles[pathWithoutFile].Add(new ListBoxViewModel { Content = folder, - PakEntry = entry + ReaderEntry = entry }); } } diff --git a/FModel/ViewModels/TabControl/AssetPropertiesViewModel.cs b/FModel/ViewModels/TabControl/AssetPropertiesViewModel.cs index 8ffbab24..f5e8588b 100644 --- a/FModel/ViewModels/TabControl/AssetPropertiesViewModel.cs +++ b/FModel/ViewModels/TabControl/AssetPropertiesViewModel.cs @@ -1,29 +1,55 @@ using FModel.Utils; -using PakReader.Parsers.Objects; using System.Windows; +using FModel.PakReader; +using FModel.PakReader.IO; +using FModel.PakReader.Parsers.Objects; namespace FModel.ViewModels.TabControl { static class AssetPropertiesVm { public static readonly AssetPropertiesViewModel assetPropertiesViewModel = new AssetPropertiesViewModel(); - public static void Set(this AssetPropertiesViewModel vm, FPakEntry entry) + public static void Set(this AssetPropertiesViewModel vm, ReaderEntry entry) { Application.Current.Dispatcher.Invoke(delegate { string ext = string.Join(" ", entry.GetExtension(), entry.Uexp?.GetExtension(), entry.Ubulk?.GetExtension()); - string offsets = string.Join(" ", "0x" + (entry.Offset + entry.StructSize).ToString("X2"), - entry.Uexp != null ? "0x" + (entry.Uexp.Offset + entry.StructSize).ToString("X2") : string.Empty, - entry.Ubulk != null ? "0x" + (entry.Ubulk.Offset + entry.StructSize).ToString("X2") : string.Empty); - string tSize = Strings.GetReadableSize(entry.Size + (entry.Uexp?.Size ?? 0) + (entry.Ubulk?.Size ?? 0)); + string offsets; + string tSize; + if (entry is FPakEntry pakEntry) + { + offsets = string.Join(" ", "0x" + (pakEntry.Offset + pakEntry.StructSize).ToString("X2"), + entry.Uexp != null ? "0x" + (((FPakEntry)pakEntry.Uexp).Offset + pakEntry.StructSize).ToString("X2") : string.Empty, + entry.Ubulk != null ? "0x" + (((FPakEntry)pakEntry.Ubulk).Offset + pakEntry.StructSize).ToString("X2") : string.Empty); + tSize = Strings.GetReadableSize(pakEntry.Size + ((pakEntry.Uexp as FPakEntry)?.Size ?? 0) + ((pakEntry.Ubulk as FPakEntry)?.Size ?? 0)); + } else if (entry is FIoStoreEntry ioEntry) + { + 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)); + } + else + { + offsets = string.Empty; + tSize = string.Empty; + } vm.AssetName = entry.GetNameWithExtension(); - vm.PartOf = entry.PakFileName; + vm.PartOf = entry.ContainerName; vm.IncludedExtensions = ext.TrimEnd(); vm.Offsets = offsets.TrimEnd(); vm.TotalSize = tSize; - vm.IsEncrypted = entry.Encrypted ? Properties.Resources.Yes : Properties.Resources.No; - vm.CompMethod = ((ECompressionFlags)entry.CompressionMethodIndex).ToString(); + if (entry is FPakEntry cast) + { + vm.IsEncrypted = cast.Encrypted ? Properties.Resources.Yes : Properties.Resources.No; + vm.CompMethod = ((ECompressionFlags)cast.CompressionMethodIndex).ToString(); + } + else + { + vm.IsEncrypted = Properties.Resources.No; + vm.CompMethod = ECompressionFlags.COMPRESS_None.ToString(); + } }); } public static void Reset(this AssetPropertiesViewModel vm) diff --git a/FModel/ViewModels/TabControl/PakPropertiesViewModel.cs b/FModel/ViewModels/TabControl/PakPropertiesViewModel.cs index 5e6de918..04eedaac 100644 --- a/FModel/ViewModels/TabControl/PakPropertiesViewModel.cs +++ b/FModel/ViewModels/TabControl/PakPropertiesViewModel.cs @@ -1,8 +1,9 @@ -using PakReader; -using PakReader.Pak; -using PakReader.Parsers.Objects; -using System.Collections.Generic; +using System.Collections.Generic; using System.Windows; +using FModel.PakReader; +using FModel.PakReader.IO; +using FModel.PakReader.Pak; +using FModel.PakReader.Parsers.Objects; namespace FModel.ViewModels.TabControl { @@ -21,6 +22,18 @@ namespace FModel.ViewModels.TabControl vm.FileCount = (pakFileReader as IReadOnlyDictionary).Count.ToString(); }); } + public static void Set(this PakPropertiesViewModel vm, FFileIoStoreReader ioReader) + { + Application.Current.Dispatcher.Invoke(delegate + { + vm.PakName = ioReader.FileName; + vm.Version = ((int)ioReader.TocResource.Header.Version).ToString(); + vm.MountPoint = ioReader.MountPoint; + vm.AesKey = ioReader.AesKey?.ToStringKey(); + vm.Guid = ioReader.EncryptionKeyGuid.Hex; + vm.FileCount = ioReader.Count.ToString(); + }); + } public static void Reset(this PakPropertiesViewModel vm) { Application.Current.Dispatcher.Invoke(delegate diff --git a/FModel/ViewModels/Treeview/SortedTreeviewViewModel.cs b/FModel/ViewModels/Treeview/SortedTreeviewViewModel.cs index 4fcb8258..62742431 100644 --- a/FModel/ViewModels/Treeview/SortedTreeviewViewModel.cs +++ b/FModel/ViewModels/Treeview/SortedTreeviewViewModel.cs @@ -3,7 +3,6 @@ using FModel.ViewModels.Buttons; using FModel.ViewModels.DataGrid; using FModel.ViewModels.ListBox; using FModel.ViewModels.StatusBar; -using PakReader.Pak; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; @@ -14,6 +13,7 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Windows.Data; +using FModel.PakReader.Pak; namespace FModel.ViewModels.Treeview { @@ -75,14 +75,14 @@ namespace FModel.ViewModels.Treeview var m = Regex.Match(entry.Name, $"{fullPath}/*", RegexOptions.IgnoreCase); if (m.Success) { - if (Globals.CachedPakFiles.TryGetValue(entry.PakFile, out PakFileReader pak)) + if (Globals.CachedPakFiles.TryGetValue(entry.ContainerFile, out PakFileReader pak)) { if (pak.TryGetValue("/" + entry.Name.Substring(0, entry.Name.LastIndexOf(".")), out var pakEntry)) // remove the extension to get the entry { entriesToExtract.Add(new ListBoxViewModel { Content = pakEntry.GetNameWithExtension(), - PakEntry = pakEntry + ReaderEntry = pakEntry }); } } @@ -112,7 +112,7 @@ namespace FModel.ViewModels.Treeview var m = Regex.Match(entry.Name, $"{fullPath}/*", RegexOptions.IgnoreCase); if (m.Success) { - if (Globals.CachedPakFiles.TryGetValue(entry.PakFile, out PakFileReader pak)) + if (Globals.CachedPakFiles.TryGetValue(entry.ContainerFile, out PakFileReader pak)) { if (pak.TryGetValue("/" + entry.Name.Substring(0, entry.Name.LastIndexOf(".")), out var pakEntry)) // remove the extension to get the entry { diff --git a/FModel/Windows/AESManager/AESManager.xaml.cs b/FModel/Windows/AESManager/AESManager.xaml.cs index fdca7758..9607f1d0 100644 --- a/FModel/Windows/AESManager/AESManager.xaml.cs +++ b/FModel/Windows/AESManager/AESManager.xaml.cs @@ -4,13 +4,13 @@ using FModel.Utils; using FModel.ViewModels.MenuItem; using FModel.Windows.CustomNotifier; using Newtonsoft.Json; -using PakReader.Pak; using System; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Media; +using FModel.PakReader.Pak; namespace FModel.Windows.AESManager { diff --git a/FModel/Windows/SoundPlayer/AudioPlayer.xaml.cs b/FModel/Windows/SoundPlayer/AudioPlayer.xaml.cs index 817a6e70..e54ceafd 100644 --- a/FModel/Windows/SoundPlayer/AudioPlayer.xaml.cs +++ b/FModel/Windows/SoundPlayer/AudioPlayer.xaml.cs @@ -5,7 +5,6 @@ using FModel.ViewModels.ListBox; using FModel.ViewModels.SoundPlayer; using FModel.Windows.SoundPlayer.Visualization; using Microsoft.Win32; -using PakReader; using System; using System.Collections.Generic; using System.Diagnostics; @@ -92,7 +91,7 @@ namespace FModel.Windows.SoundPlayer case ".bnk": case ".pck": Focus(); - WwiseReader bnk = new WwiseReader(new BinaryReader(new BufferedStream(new FileInfo(file).Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))); + WwiseReader bnk = new WwiseReader(new BinaryReader(new FileInfo(file).Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))); LoadFiles(bnk.AudioFiles, ""); break; default: