From 1b2f6c636f82c106da024308922527b0255ec357 Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 28 Oct 2020 21:41:53 +0100 Subject: [PATCH] Uhm ok so I guess that's the big commit - Added utoc/ucas (io store) loading support - Added new unversioned asset parsing support ONLY for asset we have mappings yet - Integrated that new parsing as good as possible into fmodel's old structure (which certainly wasn't prepared for such a change lol) - ONLY for new package format disabled caching of files in debug mode (was annoying) - Type and enum mappings while by default be loaded from a github repo BUT in debug mode it will first attempt to load them from local files (relative to the exe, also for debugging conveniance) but fallback to the ones from the repo - F12 hotkey for reloading current type mappings (Mainly made for debug but also works in release) --- FModel/Creator/Bases/BaseBBDefinition.cs | 4 +- FModel/Creator/Bases/BaseBundle.cs | 8 +- FModel/Creator/Bases/BaseGCosmetic.cs | 4 +- FModel/Creator/Bases/BaseIcon.cs | 10 +- FModel/Creator/Bases/BaseItemAccess.cs | 8 +- FModel/Creator/Bases/BaseMapUIData.cs | 4 +- FModel/Creator/Bases/BaseOffer.cs | 8 +- FModel/Creator/Bases/BaseOfferMaterial.cs | 8 +- FModel/Creator/Bases/BasePlaylist.cs | 6 +- FModel/Creator/Bases/BaseSeason.cs | 4 +- FModel/Creator/Bases/BaseUIData.cs | 4 +- FModel/Creator/Bases/BaseUserOption.cs | 6 +- FModel/Creator/Bundles/CompletionReward.cs | 2 +- FModel/Creator/Bundles/Header.cs | 8 +- FModel/Creator/Bundles/Quest.cs | 8 +- FModel/Creator/Bundles/Reward.cs | 16 +- FModel/Creator/Creator.cs | 4 +- FModel/Creator/Icons/DisplayAssetImage.cs | 10 +- FModel/Creator/Icons/LargeSmallImage.cs | 12 +- FModel/Creator/Icons/UserFacingFlag.cs | 10 +- FModel/Creator/Rarities/Rarity.cs | 18 +- FModel/Creator/Rarities/Serie.cs | 10 +- FModel/Creator/Stats/Statistics.cs | 14 +- FModel/Creator/Texts/GameplayTag.cs | 10 +- FModel/Creator/Texts/Text.cs | 14 +- FModel/Creator/Texts/Typefaces.cs | 45 ++++- FModel/Creator/Utils.cs | 56 +++++- FModel/FModel.csproj | 3 +- FModel/Globals.cs | 11 +- .../Grabber/Manifests/ValorantAPIManifest.cs | 4 +- FModel/Grabber/Paks/PaksGrabber.cs | 32 ++- FModel/MainWindow.xaml | 2 + FModel/MainWindow.xaml.cs | 57 +++++- FModel/PakReader/AESDecryptor.cs | 2 +- FModel/PakReader/BinaryHelper.cs | 2 +- FModel/PakReader/{Pak => }/IO/EIoChunkType.cs | 2 +- .../{Pak => }/IO/EIoContainerFlags.cs | 2 +- FModel/PakReader/IO/FArc.cs | 16 ++ FModel/PakReader/IO/FContainerHeader.cs | 37 ++++ FModel/PakReader/IO/FExportBundleEntry.cs | 25 +++ FModel/PakReader/IO/FExportDesc.cs | 16 ++ FModel/PakReader/IO/FExportMapEntry.cs | 37 ++++ .../{Pak => }/IO/FFileIoStoreContainerFile.cs | 4 +- .../{Pak => }/IO/FFileIoStoreReader.cs | 185 ++++++++++++++++-- FModel/PakReader/IO/FFragment.cs | 26 +++ FModel/PakReader/IO/FImportDesc.cs | 11 ++ FModel/PakReader/{Pak => }/IO/FIoChunkHash.cs | 2 +- FModel/PakReader/{Pak => }/IO/FIoChunkId.cs | 41 ++-- .../PakReader/{Pak => }/IO/FIoContainerId.cs | 2 +- .../{Pak => }/IO/FIoDirectoryIndexEntry.cs | 2 +- .../{Pak => }/IO/FIoDirectoryIndexHandle.cs | 3 +- .../{Pak => }/IO/FIoDirectoryIndexResource.cs | 12 +- .../{Pak => }/IO/FIoFileIndexEntry.cs | 2 +- FModel/PakReader/IO/FIoGlobalData.cs | 133 +++++++++++++ FModel/PakReader/IO/FIoOffsetAndLength.cs | 26 +++ FModel/PakReader/IO/FIoStoreEntry.cs | 28 +++ .../IO/FIoStoreTocCompressedBlockEntry.cs | 2 +- .../{Pak => }/IO/FIoStoreTocEntryMeta.cs | 2 +- .../{Pak => }/IO/FIoStoreTocEntryMetaFlags.cs | 2 +- .../{Pak => }/IO/FIoStoreTocHeader.cs | 4 +- .../{Pak => }/IO/FIoStoreTocResource.cs | 10 +- FModel/PakReader/IO/FIterator.cs | 74 +++++++ FModel/PakReader/IO/FMappedName.cs | 71 +++++++ FModel/PakReader/IO/FMinimalName.cs | 22 +++ FModel/PakReader/IO/FNameEntryId.cs | 45 +++++ FModel/PakReader/IO/FPackageDesc.cs | 18 ++ FModel/PakReader/IO/FPackageId.cs | 21 ++ FModel/PakReader/IO/FPackageLocation.cs | 10 + FModel/PakReader/IO/FPackageObjectIndex.cs | 71 +++++++ FModel/PakReader/IO/FPackageStoreEntry.cs | 36 ++++ FModel/PakReader/IO/FPackageSummary.cs | 39 ++++ FModel/PakReader/IO/FScriptObjectDesc.cs | 20 ++ FModel/PakReader/IO/FScriptObjectEntry.cs | 20 ++ FModel/PakReader/IO/FSerializedNameHeader.cs | 17 ++ FModel/PakReader/IO/FUnversionedHeader.cs | 65 ++++++ FModel/PakReader/IO/IoPackage.cs | 74 +++++++ FModel/PakReader/IO/PropertyInfo.cs | 31 +++ FModel/PakReader/LocMetaReader.cs | 4 +- FModel/PakReader/LocResReader.cs | 4 +- FModel/PakReader/Package.cs | 64 ++++++ FModel/PakReader/Pak/DefaultPakFilter.cs | 2 +- FModel/PakReader/Pak/IO/FIoOffsetAndLength.cs | 26 --- FModel/PakReader/Pak/IPakFilter.cs | 2 +- FModel/PakReader/Pak/PakFileReader.cs | 11 +- FModel/PakReader/Pak/PakFilter.cs | 2 +- FModel/PakReader/Pak/PakIndex.cs | 4 +- FModel/PakReader/Pak/PakPackage.cs | 89 ++------- FModel/PakReader/Parsers/Class/IUExport.cs | 6 +- .../Parsers/Class/UAkMediaAssetData.cs | 6 +- FModel/PakReader/Parsers/Class/UCurveTable.cs | 13 +- FModel/PakReader/Parsers/Class/UDataTable.cs | 57 +++++- FModel/PakReader/Parsers/Class/UFontFace.cs | 26 ++- FModel/PakReader/Parsers/Class/UObject.cs | 97 ++++++++- FModel/PakReader/Parsers/Class/USoundWave.cs | 21 +- .../PakReader/Parsers/Class/UStringTable.cs | 6 +- FModel/PakReader/Parsers/Class/UTexture2D.cs | 19 +- FModel/PakReader/Parsers/IoPackageReader.cs | 176 +++++++++++++++++ .../PakReader/Parsers/LegacyPackageReader.cs | 123 ++++++++++++ .../Objects/EAnimationCompressionFormat.cs | 2 +- .../Parsers/Objects/EAnimationKeyFormat.cs | 2 +- .../Objects/EAssetRegistryDependencyType.cs | 2 +- .../Parsers/Objects/EBulkDataFlags.cs | 2 +- .../Parsers/Objects/ECompressionFlags.cs | 2 +- .../Parsers/Objects/ECurveTableMode.cs | 2 +- .../Parsers/Objects/EDateTimeStyle.cs | 2 +- .../Parsers/Objects/EDecompressionType.cs | 2 +- .../Parsers/Objects/EExportFilterFlags.cs | 9 + .../Parsers/Objects/EExpressionType.cs | 2 +- .../Parsers/Objects/EFormatArgumentType.cs | 2 +- .../Parsers/Objects/EInitializationMode.cs | 2 +- .../Parsers/Objects/ELightingBuildQuality.cs | 2 +- .../PakReader/Parsers/Objects/EObjectFlags.cs | 6 +- .../Parsers/Objects/EPackageFlags.cs | 2 +- .../PakReader/Parsers/Objects/EPakVersion.cs | 2 +- .../PakReader/Parsers/Objects/EPixelFormat.cs | 2 +- .../Parsers/Objects/ERangeBoundType.cs | 2 +- .../Objects/ERichCurveCompressionFormat.cs | 2 +- .../Objects/ERichCurveExtrapolation.cs | 2 +- .../Parsers/Objects/ERichCurveInterpMode.cs | 2 +- .../ERichCurveKeyTimeCompressionFormat.cs | 2 +- .../Parsers/Objects/ERichCurveTangentMode.cs | 2 +- .../Objects/ERichCurveTangentWeightMode.cs | 2 +- .../PakReader/Parsers/Objects/ESoundGroup.cs | 2 +- .../Objects/ESoundWaveLoadingBehavior.cs | 2 +- .../Objects/ESoundWavePrecacheState.cs | 2 +- .../Objects/ESoundwaveSampleRateSettings.cs | 2 +- .../Objects/EStringTableLoadingPhase.cs | 2 +- FModel/PakReader/Parsers/Objects/ETextFlag.cs | 2 +- .../PakReader/Parsers/Objects/ETextGender.cs | 2 +- .../Parsers/Objects/ETextHistoryType.cs | 2 +- .../Parsers/Objects/ETransformType.cs | 2 +- .../EUnrealEngineObjectLicenseeUE4Version.cs | 2 +- .../Objects/EUnrealEngineObjectUE4Version.cs | 2 +- .../Parsers/Objects/EVirtualTextureCodec.cs | 2 +- .../Parsers/Objects/FAkMediaDataChunk.cs | 2 +- .../PakReader/Parsers/Objects/FAssetData.cs | 2 +- .../Objects/FAssetDataTagMapSharedView.cs | 2 +- .../Parsers/Objects/FAssetIdentifier.cs | 2 +- .../Parsers/Objects/FAssetPackageData.cs | 2 +- .../Parsers/Objects/FAssetRegistryState.cs | 2 +- .../Parsers/Objects/FAssetRegistryVersion.cs | 2 +- .../Parsers/Objects/FBodyInstance.cs | 2 +- FModel/PakReader/Parsers/Objects/FBox.cs | 2 +- FModel/PakReader/Parsers/Objects/FBox2D.cs | 2 +- .../Parsers/Objects/FByteBulkData.cs | 2 +- .../PakReader/Parsers/Objects/FChunkHeader.cs | 2 +- FModel/PakReader/Parsers/Objects/FColor.cs | 2 +- .../Parsers/Objects/FColorMaterialInput.cs | 2 +- .../Parsers/Objects/FCompressedChunk.cs | 2 +- .../Parsers/Objects/FCompressedOffsetData.cs | 2 +- .../Parsers/Objects/FCompressedSegment.cs | 2 +- .../Parsers/Objects/FCustomVersion.cs | 2 +- .../Objects/FCustomVersionContainer.cs | 2 +- FModel/PakReader/Parsers/Objects/FDateTime.cs | 2 +- .../PakReader/Parsers/Objects/FDependsNode.cs | 2 +- .../Parsers/Objects/FDictionaryHeader.cs | 2 +- .../Parsers/Objects/FEngineVersion.cs | 2 +- FModel/PakReader/Parsers/Objects/FEntry.cs | 2 +- .../Objects/FEvaluationTreeEntryHandle.cs | 2 +- .../PakReader/Parsers/Objects/FFactChunk.cs | 2 +- .../Parsers/Objects/FFormatArgumentData.cs | 2 +- .../Parsers/Objects/FFormatArgumentValue.cs | 2 +- .../Parsers/Objects/FFormatContainer.cs | 2 +- .../PakReader/Parsers/Objects/FFrameNumber.cs | 2 +- .../Parsers/Objects/FGameplayTagContainer.cs | 4 +- .../Parsers/Objects/FGenerationInfo.cs | 2 +- FModel/PakReader/Parsers/Objects/FGuid.cs | 2 +- FModel/PakReader/Parsers/Objects/FIntPoint.cs | 2 +- .../FLevelSequenceLegacyObjectReference.cs | 2 +- .../FLevelSequenceObjectReferenceMap.cs | 2 +- .../PakReader/Parsers/Objects/FLinearColor.cs | 2 +- FModel/PakReader/Parsers/Objects/FMD5Hash.cs | 2 +- .../Parsers/Objects/FMaterialInput.cs | 2 +- .../Objects/FMovieSceneEvaluationKey.cs | 2 +- .../Objects/FMovieSceneEvaluationTemplate.cs | 2 +- .../Objects/FMovieSceneEvaluationTree.cs | 2 +- .../Objects/FMovieSceneEvaluationTreeNode.cs | 2 +- .../FMovieSceneEvaluationTreeNodeHandle.cs | 2 +- .../Objects/FMovieSceneFloatChannel.cs | 2 +- .../Parsers/Objects/FMovieSceneFrameRange.cs | 2 +- .../Parsers/Objects/FMovieSceneSegment.cs | 2 +- FModel/PakReader/Parsers/Objects/FName.cs | 20 +- .../Parsers/Objects/FNameEntrySerialized.cs | 44 ++++- .../Objects/FNameTableArchiveReader.cs | 2 +- .../Objects/FNavAgentSelectorCustomization.cs | 2 +- .../Parsers/Objects/FObjectExport.cs | 23 ++- .../Parsers/Objects/FObjectImport.cs | 2 +- .../Parsers/Objects/FObjectResource.cs | 13 +- .../Parsers/Objects/FOodleCompressedData.cs | 2 +- .../Objects/FOodleDictionaryArchive.cs | 2 +- .../Parsers/Objects/FPackageFileSummary.cs | 2 +- .../Parsers/Objects/FPackageIndex.cs | 45 ++++- .../Parsers/Objects/FPakCompressedBlock.cs | 2 +- .../Parsers/Objects/FPakDirectoryEntry.cs | 3 +- FModel/PakReader/Parsers/Objects/FPakEntry.cs | 67 ++----- FModel/PakReader/Parsers/Objects/FPakInfo.cs | 2 +- .../Parsers/Objects/FPathHashIndexEntry.cs | 3 +- .../Parsers/Objects/FPerPlatformFloat.cs | 2 +- .../Parsers/Objects/FPerPlatformInt.cs | 2 +- .../PakReader/Parsers/Objects/FPropertyTag.cs | 21 +- FModel/PakReader/Parsers/Objects/FQuat.cs | 2 +- .../Parsers/Objects/FRichCurveKey.cs | 4 +- .../Parsers/Objects/FRiffWaveHeader.cs | 2 +- FModel/PakReader/Parsers/Objects/FRotator.cs | 2 +- FModel/PakReader/Parsers/Objects/FSHAHash.cs | 2 +- .../PakReader/Parsers/Objects/FSampleChunk.cs | 2 +- .../PakReader/Parsers/Objects/FSampleLoop.cs | 2 +- .../Objects/FSectionEvaluationDataTree.cs | 2 +- .../Parsers/Objects/FSimpleCurveKey.cs | 2 +- ...SkeletalMeshAreaWeightedTriangleSampler.cs | 2 +- .../FSkeletalMeshSamplingLODBuiltData.cs | 2 +- .../PakReader/Parsers/Objects/FSmartName.cs | 2 +- .../Parsers/Objects/FSoftObjectPath.cs | 2 +- .../Parsers/Objects/FStreamedAudioChunk.cs | 2 +- .../PakReader/Parsers/Objects/FStringTable.cs | 6 +- .../Parsers/Objects/FStripDataFlags.cs | 2 +- FModel/PakReader/Parsers/Objects/FText.cs | 12 +- .../PakReader/Parsers/Objects/FTextHistory.cs | 2 +- .../Objects/FTextHistoryArgumentDataFormat.cs | 2 +- .../Parsers/Objects/FTextHistoryAsDate.cs | 2 +- .../Parsers/Objects/FTextHistoryAsTime.cs | 2 +- .../Parsers/Objects/FTextHistoryBase.cs | 2 +- .../Parsers/Objects/FTextHistoryDateTime.cs | 2 +- .../Objects/FTextHistoryFormatNumber.cs | 2 +- .../Parsers/Objects/FTextHistoryNone.cs | 7 +- .../Objects/FTextHistoryOrderedFormat.cs | 2 +- .../Objects/FTextHistoryStringTableEntry.cs | 2 +- .../Parsers/Objects/FTextHistoryTransform.cs | 2 +- FModel/PakReader/Parsers/Objects/FTextKey.cs | 2 +- .../Parsers/Objects/FTexture2DMipMap.cs | 2 +- .../Parsers/Objects/FTexturePlatformData.cs | 4 +- .../Parsers/Objects/FUniqueObjectGuid.cs | 2 +- FModel/PakReader/Parsers/Objects/FVector.cs | 2 +- FModel/PakReader/Parsers/Objects/FVector2D.cs | 2 +- FModel/PakReader/Parsers/Objects/FVector4.cs | 2 +- .../Parsers/Objects/FVectorMaterialInput.cs | 2 +- .../Objects/FVirtualTextureBuiltData.cs | 2 +- .../Objects/FVirtualTextureDataChunk.cs | 2 +- FModel/PakReader/Parsers/Objects/IUStruct.cs | 2 +- .../Objects/TEvaluationTreeEntryContainer.cs | 2 +- .../Objects/TMovieSceneEvaluationTree.cs | 2 +- FModel/PakReader/Parsers/Objects/TRange.cs | 2 +- .../PakReader/Parsers/Objects/TRangeBound.cs | 2 +- .../Parsers/Objects/UScriptStruct.cs | 77 +++++++- FModel/PakReader/Parsers/OodleStream.cs | 2 +- FModel/PakReader/Parsers/PackageReader.cs | 130 ++---------- .../Parsers/PropertyTagData/ArrayProperty.cs | 10 +- .../Parsers/PropertyTagData/BaseProperty.cs | 42 +++- .../Parsers/PropertyTagData/BoolProperty.cs | 11 +- .../Parsers/PropertyTagData/ByteProperty.cs | 11 +- .../PropertyTagData/DelegateProperty.cs | 12 +- .../Parsers/PropertyTagData/DoubleProperty.cs | 6 +- .../Parsers/PropertyTagData/EnumProperty.cs | 40 +++- .../Parsers/PropertyTagData/FloatProperty.cs | 6 +- .../Parsers/PropertyTagData/Int16Property.cs | 6 +- .../Parsers/PropertyTagData/Int64Property.cs | 6 +- .../Parsers/PropertyTagData/Int8Property.cs | 6 +- .../Parsers/PropertyTagData/IntProperty.cs | 6 +- .../PropertyTagData/InterfaceProperty.cs | 6 +- .../PropertyTagData/LazyObjectProperty.cs | 4 +- .../Parsers/PropertyTagData/MapProperty.cs | 15 +- .../MulticastDelegateProperty.cs | 4 +- .../Parsers/PropertyTagData/NameProperty.cs | 8 +- .../Parsers/PropertyTagData/ObjectProperty.cs | 9 +- .../Parsers/PropertyTagData/SetProperty.cs | 8 +- .../PropertyTagData/SoftObjectProperty.cs | 10 +- .../Parsers/PropertyTagData/StrProperty.cs | 6 +- .../Parsers/PropertyTagData/StructProperty.cs | 11 +- .../Parsers/PropertyTagData/TextProperty.cs | 8 +- .../Parsers/PropertyTagData/UInt16Property.cs | 6 +- .../Parsers/PropertyTagData/UInt32Property.cs | 6 +- .../Parsers/PropertyTagData/UInt64Property.cs | 6 +- FModel/PakReader/ReaderEntry.cs | 54 +++++ FModel/PakReader/ReaderExtensions.cs | 2 +- FModel/PakReader/Textures/ASTC/ASTCDecoder.cs | 2 +- FModel/PakReader/Textures/ASTC/ASTCPixel.cs | 2 +- .../PakReader/Textures/ASTC/BitArrayStream.cs | 2 +- .../PakReader/Textures/ASTC/IntegerEncoded.cs | 2 +- FModel/PakReader/Textures/BC/BCDecoder.cs | 2 +- FModel/PakReader/Textures/BC/Detex.cs | 2 +- .../BC/DetexCompressedTextureFormatIndex.cs | 2 +- .../PakReader/Textures/BC/DetexPixelFormat.cs | 2 +- .../Textures/BC/DetexTextureFormat.cs | 2 +- FModel/PakReader/Textures/DXT/DXTDecoder.cs | 2 +- FModel/PakReader/Textures/TextureDecoder.cs | 12 +- .../PakReader/Textures/TextureFormatHelper.cs | 6 +- FModel/PakReader/WwiseReader.cs | 6 +- FModel/Utils/Assets.cs | 145 +++++++++----- FModel/Utils/BitArrays.cs | 19 ++ FModel/Utils/ByteOrderSwap.cs | 12 ++ FModel/Utils/Commands.cs | 1 + FModel/Utils/EGL2.cs | 2 +- FModel/Utils/Endpoints.cs | 8 +- FModel/Utils/Keys.cs | 48 +++-- FModel/Utils/Localizations.cs | 4 +- FModel/Utils/MathUtils.cs | 10 + FModel/Utils/Paks.cs | 18 +- FModel/Utils/Strings.cs | 70 ++++++- .../ViewModels/DataGrid/DataGridViewModel.cs | 15 +- FModel/ViewModels/ListBox/ListBoxViewModel.cs | 10 +- .../MenuItem/BackupMenuItemViewModel.cs | 31 +-- FModel/ViewModels/MenuItem/MenuItems.cs | 19 +- .../MenuItem/PakMenuItemViewModel.cs | 120 ++++++++++-- .../TabControl/AssetPropertiesViewModel.cs | 44 ++++- .../TabControl/PakPropertiesViewModel.cs | 21 +- .../Treeview/SortedTreeviewViewModel.cs | 8 +- FModel/Windows/AESManager/AESManager.xaml.cs | 2 +- .../Windows/SoundPlayer/AudioPlayer.xaml.cs | 3 +- 308 files changed, 3250 insertions(+), 933 deletions(-) rename FModel/PakReader/{Pak => }/IO/EIoChunkType.cs (92%) rename FModel/PakReader/{Pak => }/IO/EIoContainerFlags.cs (84%) create mode 100644 FModel/PakReader/IO/FArc.cs create mode 100644 FModel/PakReader/IO/FContainerHeader.cs create mode 100644 FModel/PakReader/IO/FExportBundleEntry.cs create mode 100644 FModel/PakReader/IO/FExportDesc.cs create mode 100644 FModel/PakReader/IO/FExportMapEntry.cs rename FModel/PakReader/{Pak => }/IO/FFileIoStoreContainerFile.cs (88%) rename FModel/PakReader/{Pak => }/IO/FFileIoStoreReader.cs (61%) create mode 100644 FModel/PakReader/IO/FFragment.cs create mode 100644 FModel/PakReader/IO/FImportDesc.cs rename FModel/PakReader/{Pak => }/IO/FIoChunkHash.cs (86%) rename FModel/PakReader/{Pak => }/IO/FIoChunkId.cs (51%) rename FModel/PakReader/{Pak => }/IO/FIoContainerId.cs (86%) rename FModel/PakReader/{Pak => }/IO/FIoDirectoryIndexEntry.cs (94%) rename FModel/PakReader/{Pak => }/IO/FIoDirectoryIndexHandle.cs (91%) rename FModel/PakReader/{Pak => }/IO/FIoDirectoryIndexResource.cs (78%) rename FModel/PakReader/{Pak => }/IO/FIoFileIndexEntry.cs (92%) create mode 100644 FModel/PakReader/IO/FIoGlobalData.cs create mode 100644 FModel/PakReader/IO/FIoOffsetAndLength.cs create mode 100644 FModel/PakReader/IO/FIoStoreEntry.cs rename FModel/PakReader/{Pak => }/IO/FIoStoreTocCompressedBlockEntry.cs (98%) rename FModel/PakReader/{Pak => }/IO/FIoStoreTocEntryMeta.cs (93%) rename FModel/PakReader/{Pak => }/IO/FIoStoreTocEntryMetaFlags.cs (80%) rename FModel/PakReader/{Pak => }/IO/FIoStoreTocHeader.cs (96%) rename FModel/PakReader/{Pak => }/IO/FIoStoreTocResource.cs (96%) create mode 100644 FModel/PakReader/IO/FIterator.cs create mode 100644 FModel/PakReader/IO/FMappedName.cs create mode 100644 FModel/PakReader/IO/FMinimalName.cs create mode 100644 FModel/PakReader/IO/FNameEntryId.cs create mode 100644 FModel/PakReader/IO/FPackageDesc.cs create mode 100644 FModel/PakReader/IO/FPackageId.cs create mode 100644 FModel/PakReader/IO/FPackageLocation.cs create mode 100644 FModel/PakReader/IO/FPackageObjectIndex.cs create mode 100644 FModel/PakReader/IO/FPackageStoreEntry.cs create mode 100644 FModel/PakReader/IO/FPackageSummary.cs create mode 100644 FModel/PakReader/IO/FScriptObjectDesc.cs create mode 100644 FModel/PakReader/IO/FScriptObjectEntry.cs create mode 100644 FModel/PakReader/IO/FSerializedNameHeader.cs create mode 100644 FModel/PakReader/IO/FUnversionedHeader.cs create mode 100644 FModel/PakReader/IO/IoPackage.cs create mode 100644 FModel/PakReader/IO/PropertyInfo.cs create mode 100644 FModel/PakReader/Package.cs delete mode 100644 FModel/PakReader/Pak/IO/FIoOffsetAndLength.cs create mode 100644 FModel/PakReader/Parsers/IoPackageReader.cs create mode 100644 FModel/PakReader/Parsers/LegacyPackageReader.cs create mode 100644 FModel/PakReader/Parsers/Objects/EExportFilterFlags.cs create mode 100644 FModel/PakReader/ReaderEntry.cs create mode 100644 FModel/Utils/BitArrays.cs create mode 100644 FModel/Utils/ByteOrderSwap.cs create mode 100644 FModel/Utils/MathUtils.cs 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: