From 9b1385fdf185f7d36500c4e858c456c3a57bb5df Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Thu, 14 May 2020 17:12:20 +0200 Subject: [PATCH] FModel 3.1 --- FModel.sln | 18 +- FModel/App.config | 213 - FModel/App.xaml | 10 +- FModel/App.xaml.cs | 72 +- FModel/AssemblyInfo.cs | 10 + FModel/Commands/FModel_Commands.cs | 12 - FModel/Creator/BaseBundle.cs | 102 + FModel/Creator/BaseIcon.cs | 126 + FModel/Creator/BaseUserOption.cs | 166 + FModel/Creator/Bundles/CompletionReward.cs | 60 + FModel/Creator/Bundles/Header.cs | 106 + FModel/Creator/Bundles/HeaderStyle.cs | 98 + FModel/Creator/Bundles/Quest.cs | 94 + FModel/Creator/Bundles/QuestStyle.cs | 174 + FModel/Creator/Bundles/Reward.cs | 134 + FModel/Creator/Creator.cs | 180 + FModel/Creator/Icons/DisplayAssetImage.cs | 55 + FModel/Creator/Icons/LargeSmallImage.cs | 41 + FModel/Creator/Icons/UserFacingFlag.cs | 72 + FModel/Creator/Icons/Watermark.cs | 31 + FModel/Creator/Rarities/EFortRarity.cs | 15 + FModel/Creator/Rarities/Rarity.cs | 171 + FModel/Creator/Rarities/Serie.cs | 40 + FModel/Creator/Stats/Statistic.cs | 10 + FModel/Creator/Stats/Statistics.cs | 203 + FModel/Creator/Texts/ETextSide.cs | 9 + FModel/Creator/Texts/GameplayTag.cs | 72 + FModel/Creator/Texts/Helper.cs | 110 + FModel/Creator/Texts/Text.cs | 217 + FModel/Creator/Texts/Typefaces.cs | 105 + FModel/Creator/Utils.cs | 78 + FModel/Discord/DiscordIntegration.cs | 66 + FModel/Enums.cs | 60 + FModel/FModel.csproj | 820 +-- FModel/FModel.ico | Bin 0 -> 48051 bytes FModel/FModel_Main.xaml | 196 - FModel/FModel_Main.xaml.cs | 385 -- FModel/Forms/AESManager.xaml | 40 - FModel/Forms/AESManager.xaml.cs | 145 - .../Forms/ColorPicker/Code/ColorSwatchItem.cs | 15 - FModel/Forms/ColorPicker/ColorPickRow.xaml | 26 - .../Forms/ColorPicker/ColorPickerControl.xaml | 89 - .../Forms/ColorPicker/ColorPickerSwatch.xaml | 27 - .../Forms/ColorPicker/ColorPickerWindow.xaml | 23 - FModel/Forms/FModel_About.xaml.cs | 15 - FModel/Forms/FModel_ImagesMerger.xaml | 34 - FModel/Forms/FModel_ImagesMerger.xaml.cs | 308 -- FModel/Forms/FModel_SearchFiles.xaml | 50 - FModel/Forms/FModel_SearchFiles.xaml.cs | 284 - FModel/Forms/FModel_Settings.xaml | 107 - FModel/Forms/FModel_Settings.xaml.cs | 602 -- FModel/Forms/FModel_UpdateMode.xaml | 72 - FModel/Forms/FModel_UpdateMode.xaml.cs | 382 -- FModel/Forms/HexViewer/BaseByte.cs | 559 -- FModel/Forms/HexViewer/BrushesDictionary.xaml | 15 - FModel/Forms/HexViewer/Core/BookMark.cs | 40 - .../HexViewer/Core/Bytes/ByteConverters.cs | 255 - .../HexViewer/Core/Bytes/ByteModified.cs | 100 - .../HexViewer/Core/Bytes/ByteProvider.cs | 1725 ------ FModel/Forms/HexViewer/Core/Caret.cs | 277 - .../HexViewer/Core/CharacterTable/DTE.cs | 164 - .../HexViewer/Core/CharacterTable/Enum.cs | 30 - .../Core/CharacterTable/TBLStream.cs | 406 -- .../Forms/HexViewer/Core/ConstantReadOnly.cs | 23 - .../Core/Converters/BoolInverterConverter.cs | 36 - .../BooleanToVisibilityConverter.cs | 36 - .../Converters/HexToLongStringConverter.cs | 29 - .../Converters/LongToHexStringConverter.cs | 30 - .../Converters/PathToFilenameConverter.cs | 25 - FModel/Forms/HexViewer/Core/Enumeration.cs | 209 - .../HexViewer/Core/GenericStaticInstance.cs | 17 - .../HexViewer/Core/Interfaces/IByteControl.cs | 52 - .../Core/Interfaces/IByteModified.cs | 26 - FModel/Forms/HexViewer/Core/KeyValidator.cs | 179 - .../MethodExtention/ApplicationExtention.cs | 44 - .../MethodExtention/ByteArrayExtention.cs | 47 - .../Core/MethodExtention/DoubleExtension.cs | 14 - .../Core/MethodExtention/StringExtension.cs | 34 - .../Core/MethodExtention/TrackExtention.cs | 60 - .../HexViewer/Core/Native/NativeMethods.cs | 33 - .../Core/Xcbb/CustomBackgroundBlock.cs | 83 - FModel/Forms/HexViewer/Core/Xcbb/ExeFile.cs | 61 - FModel/Forms/HexViewer/Core/Xcbb/Exefile.xcbb | 95 - .../Core/Xcbb/XcbbExpressionParser.cs | 46 - .../HexViewer/Core/Xcbb/XcbbFileParser.cs | 24 - FModel/Forms/HexViewer/FastTextLine.cs | 127 - FModel/Forms/HexViewer/FindReplaceWindow.xaml | 229 - .../Forms/HexViewer/FindReplaceWindow.xaml.cs | 84 - FModel/Forms/HexViewer/FindWindow.xaml | 119 - FModel/Forms/HexViewer/FindWindow.xaml.cs | 60 - FModel/Forms/HexViewer/GiveByteWindow.xaml | 56 - FModel/Forms/HexViewer/GiveByteWindow.xaml.cs | 14 - FModel/Forms/HexViewer/HexBox.xaml | 87 - FModel/Forms/HexViewer/HexBox.xaml.cs | 174 - FModel/Forms/HexViewer/HexByte.cs | 218 - FModel/Forms/HexViewer/HexEditor.xaml | 425 -- FModel/Forms/HexViewer/HexEditor.xaml.cs | 4892 ----------------- FModel/Forms/HexViewer/HexViewer.xaml | 286 - FModel/Forms/HexViewer/HexViewer.xaml.cs | 217 - .../HexViewer/MiscelanousDictionary.xaml | 18 - FModel/Forms/HexViewer/ReplaceByteWindow.xaml | 70 - .../Forms/HexViewer/ReplaceByteWindow.xaml.cs | 14 - FModel/Forms/HexViewer/StringByte.cs | 299 - FModel/Forms/HexViewer/ToolTipDictionary.xaml | 86 - FModel/Globals.cs | 48 + FModel/Grabber/Aes/AesData.cs | 37 + FModel/Grabber/Aes/AesGrabber.cs | 64 + FModel/Grabber/Cdn/CdnData.cs | 53 + FModel/Grabber/Cdn/CdnDataGrabber.cs | 99 + FModel/Grabber/Paks/InstallsJson.cs | 11 + FModel/Grabber/Paks/LauncherDat.cs | 14 + FModel/Grabber/Paks/PaksGrabber.cs | 115 + FModel/Logger/DebugHelper.cs | 41 + .../{Methods/Utilities => Logger}/Logger.cs | 66 +- FModel/Logo.ico | Bin 25486 -> 0 bytes FModel/MainWindow.xaml | 499 ++ FModel/MainWindow.xaml.cs | 431 ++ .../Methods/AESManager/DynamicKeysChecker.cs | 92 - FModel/Methods/AESManager/KeysManager.cs | 40 - FModel/Methods/Assets/AssetInformations.cs | 60 - FModel/Methods/Assets/AssetTranslations.cs | 289 - FModel/Methods/Assets/AssetsLoader.cs | 291 - .../IconCreator/AthenaID/CosmeticSeason.cs | 29 - .../IconCreator/AthenaID/CosmeticSet.cs | 54 - .../AthenaID/IconUserFacingFlags.cs | 232 - .../ChallengeID/ChallengeBundleInfos.cs | 307 -- .../ChallengeID/ChallengeCompletionRewards.cs | 246 - .../ChallengeID/ChallengeIconDesign.cs | 362 -- .../ChallengeID/ChallengeRewards.cs | 269 - .../HeroID/HeroGameplayDefinition.cs | 193 - .../Methods/Assets/IconCreator/IconCreator.cs | 76 - .../Methods/Assets/IconCreator/IconImage.cs | 290 - FModel/Methods/Assets/IconCreator/IconText.cs | 390 -- .../Assets/IconCreator/IconWatermark.cs | 42 - FModel/Methods/Assets/IconCreator/Rarity.cs | 346 -- .../IconCreator/WeaponID/IconAmmoData.cs | 87 - .../IconCreator/WeaponID/WeaponStats.cs | 162 - FModel/Methods/Auth/AuthFlow.cs | 40 - FModel/Methods/Auth/Requests.cs | 20 - .../RegisterDownloadedBackups.cs | 83 - FModel/Methods/FVar.cs | 129 - .../FindReplace/FindReplaceDialog.xaml | 65 - FModel/Methods/PAKs/BackupPAKs.cs | 97 - FModel/Methods/PAKs/PAKsLoader.cs | 394 -- FModel/Methods/PAKs/RegisterFromPath.cs | 146 - FModel/Methods/PakReader/AssetRegReader.cs | 325 -- FModel/Methods/PakReader/DDSDecoder.cs | 2082 ------- .../PakReader/ExportObject/AssetReader.cs | 736 --- .../PakReader/ExportObject/ExportObject.cs | 4 - .../ExportObject/FontFace/FontFace.cs | 22 - .../ExportObject/Texture2D/Texture2D.cs | 50 - .../UAnimSequence/UAnimSequence.cs | 350 -- .../UCurveTable/ECurveTableMode.cs | 9 - .../ExportObject/UCurveTable/UCurveTable.cs | 42 - .../ExportObject/UDataTable/UDataTable.cs | 23 - .../FDictionaryHeader/FDictionaryHeader.cs | 24 - .../FDictionaryHeader/FOodleCompressedData.cs | 18 - .../ExportObject/UDictionary/UDictionary.cs | 54 - .../PakReader/ExportObject/UObject/UObject.cs | 35 - .../ExportObject/UScript/UScriptArray.cs | 48 - .../ExportObject/UScript/UScriptMap.cs | 28 - .../UScript/UScriptStruct/FAnimKeyHeader.cs | 32 - .../UScript/UScriptStruct/FBoxSphereBounds.cs | 18 - .../UScript/UScriptStruct/FByteBulkData.cs | 36 - .../UScriptStruct/FByteBulkDataHeader.cs | 20 - .../UScript/UScriptStruct/FColor.cs | 27 - .../UScriptStruct/FCompressedOffsetData.cs | 8 - .../UScriptStruct/FCompressedSegment.cs | 24 - .../UScript/UScriptStruct/FDateTime.cs | 14 - .../UScriptStruct/FGameplayTagContainer.cs | 21 - .../UScript/UScriptStruct/FGuid.cs | 41 - .../UScript/UScriptStruct/FIntPoint.cs | 16 - .../FLevelSequenceLegacyObjectReference.cs | 19 - .../FLevelSequenceObjectReferenceMap.cs | 19 - .../UScript/UScriptStruct/FLinearColor.cs | 28 - .../UScriptStruct/FNameEntrySerialized.cs | 19 - .../UScript/UScriptStruct/FObjectExport.cs | 53 - .../UScript/UScriptStruct/FObjectImport.cs | 21 - .../UScript/UScriptStruct/FPackageIndex.cs | 31 - .../FPropertyTag/FPropertyTag.cs | 32 - .../FPropertyTag/FPropertyTagType.cs | 25 - .../UScript/UScriptStruct/FQuat.cs | 51 - .../UScript/UScriptStruct/FReferencePose.cs | 17 - .../FReferenceSkeleton/FMeshBoneInfo.cs | 17 - .../FReferenceSkeleton/FReferenceSkeleton.cs | 24 - .../FReferenceSkeleton/FTransform.cs | 18 - .../UScript/UScriptStruct/FRichCurveKey.cs | 28 - .../UScript/UScriptStruct/FRotator.cs | 18 - .../UScript/UScriptStruct/FScriptDelegate.cs | 17 - .../UScript/UScriptStruct/FSimpleCurveKey.cs | 16 - .../FSkeletalMaterial/FMeshUVChannelInfo.cs | 22 - .../FSkeletalMaterial/FSkeletalMaterial.cs | 25 - .../UScriptStruct/FSkeletalMeshLODInfo.cs | 10 - .../UScript/UScriptStruct/FSmartName.cs | 15 - .../UScript/UScriptStruct/FSoftObjectPath.cs | 17 - .../UScriptStruct/FSoftObjectPathMap.cs | 17 - .../UScript/UScriptStruct/FSoundFormatData.cs | 17 - .../FStaticLODModel/FColorVertexBuffer.cs | 24 - .../FMultisizeIndexContainer.cs | 29 - .../FStaticLODModel/FPositionVertexBuffer.cs | 19 - .../FApexClothPhysToRenderVertData.cs | 22 - .../FSkelMeshSection/FClothingSectionData.cs | 16 - .../FDuplicatedVerticesBuffer.cs | 16 - .../FIndexLengthPair.cs | 16 - .../FSkelMeshSection/FSkelMeshSection.cs | 40 - .../FGPUVert4/FGPUVert4Float.cs | 11 - .../FGPUVert4/FGPUVert4Half.cs | 11 - .../FGPUVert4/FMeshUV/FMeshUVFloat.cs | 25 - .../FGPUVert4/FMeshUV/FMeshUVHalf.cs | 25 - .../FGPUVert4/FPackedNormal.cs | 35 - .../FSkeletalMeshVertexBuffer.cs | 26 - .../FSkeletalMeshVertexClothBuffer.cs | 30 - .../FRuntimeSkinWeightProfileData.cs | 22 - .../FSkinWeightOverrideInfo.cs | 16 - .../FSkinWeightProfilesData.cs | 19 - .../FSkinWeightInfo.cs | 16 - .../FSkinWeightVertexBuffer.cs | 27 - .../FStaticLODModel/FStaticLODModel.cs | 86 - .../FStaticMeshUVItem4/FPackedRGBA16N.cs | 32 - .../FStaticMeshUVItem4/FStaticMeshUVItem4.cs | 45 - .../FStaticMeshVertexBuffer.cs | 70 - .../UScriptStruct/FStaticLODModel/FVector4.cs | 17 - .../UScriptStruct/FStreamedAudioChunk.cs | 27 - .../UScript/UScriptStruct/FStripDataFlags.cs | 20 - .../UScript/UScriptStruct/FStructFallback.cs | 29 - .../UScript/UScriptStruct/FText.cs | 41 - .../FTexturePlatformData/FTexture2DMipMap.cs | 28 - .../FTexturePlatformData.cs | 35 - .../UScript/UScriptStruct/FTrack.cs | 12 - .../UScript/UScriptStruct/FVector.cs | 76 - .../UScript/UScriptStruct/FVector2D.cs | 16 - .../UScript/UScriptStruct/UScriptStruct.cs | 102 - .../USkeletalMesh/USkeletalMesh.cs | 96 - .../ExportObject/USkeleton/USkeleton.cs | 24 - .../ExportObject/USoundWave/USoundWave.cs | 87 - FModel/Methods/PakReader/ImageExporter.cs | 170 - FModel/Methods/PakReader/LocReader.cs | 259 - FModel/Methods/PakReader/MeshExporter.cs | 1329 ----- FModel/Methods/PakReader/Objects.cs | 845 --- FModel/Methods/PakReader/PakReader.cs | 346 -- FModel/Methods/PakReader/SigReader.cs | 41 - .../SyntaxHighlighter/ResourceLoader.cs | 18 - .../TreeViewModel/PropertyChangedBase.cs | 51 - .../SortedTreeViewWindowViewModel.cs | 49 - FModel/Methods/TreeViewModel/TreeViewModel.cs | 32 - FModel/Methods/Utilities/AESUtility.cs | 41 - FModel/Methods/Utilities/AssetsUtility.cs | 549 -- FModel/Methods/Utilities/ChallengesUtility.cs | 157 - FModel/Methods/Utilities/DebugHelper.cs | 81 - FModel/Methods/Utilities/EndpointsUtility.cs | 121 - FModel/Methods/Utilities/FoldersUtility.cs | 142 - FModel/Methods/Utilities/ImagesUtility.cs | 137 - FModel/Methods/Utilities/ListBoxUtility.cs | 137 - FModel/Methods/Utilities/MBoxesUtility.cs | 31 - FModel/Methods/Utilities/PAKsUtility.cs | 86 - FModel/Methods/Utilities/TasksUtility.cs | 28 - FModel/Methods/Utilities/TextsUtility.cs | 13 - FModel/Methods/Utilities/TreeViewUtility.cs | 105 - FModel/Methods/Utilities/UIUtility.cs | 285 - .../{Methods => }/PakReader/AESDecryptor.cs | 2 +- FModel/PakReader/BinaryHelper.cs | 47 + FModel/{Methods => }/PakReader/LICENSE | 0 FModel/PakReader/LocMetaReader.cs | 43 + FModel/PakReader/LocResReader.cs | 184 + FModel/PakReader/Pak/DefaultPakFilter.cs | 7 + FModel/PakReader/Pak/IPakFilter.cs | 7 + FModel/PakReader/Pak/PakFileReader.cs | 497 ++ FModel/PakReader/Pak/PakFilter.cs | 63 + FModel/PakReader/Pak/PakIndex.cs | 190 + FModel/PakReader/Pak/PakPackage.cs | 89 + FModel/PakReader/Parsers/Class/IUExport.cs | 24 + FModel/PakReader/Parsers/Class/UCurveTable.cs | 37 + FModel/PakReader/Parsers/Class/UDataTable.cs | 48 + FModel/PakReader/Parsers/Class/UFontFace.cs | 39 + FModel/PakReader/Parsers/Class/UObject.cs | 95 + FModel/PakReader/Parsers/Class/USoundWave.cs | 94 + .../PakReader/Parsers/Class/UStringTable.cs | 32 + FModel/PakReader/Parsers/Class/UTexture2D.cs | 45 + .../Objects/EAssetRegistryDependencyType.cs | 20 + .../Parsers/Objects/EBulkDataFlags.cs | 41 + .../Parsers/Objects/ECompressionFlags.cs | 33 + .../Parsers/Objects/ECurveTableMode.cs | 12 + .../Parsers/Objects/EDateTimeStyle.cs | 12 + .../Parsers/Objects/EDecompressionType.cs | 15 + .../Parsers/Objects/EExpressionType.cs | 12 + .../Parsers/Objects/EFormatArgumentType.cs | 14 + .../Parsers/Objects/EInitializationMode.cs | 12 + .../Parsers/Objects/ELightingBuildQuality.cs | 11 + .../PakReader/Parsers/Objects/EObjectFlags.cs | 52 + .../Parsers/Objects/EPackageFlags.cs | 38 + .../PakReader/Parsers/Objects/EPakVersion.cs | 23 + .../PakReader/Parsers/Objects/EPixelFormat.cs | 76 + .../Parsers/Objects/ERangeBoundType.cs | 9 + .../Objects/ERichCurveCompressionFormat.cs | 17 + .../Parsers/Objects/ERichCurveInterpMode.cs | 15 + .../ERichCurveKeyTimeCompressionFormat.cs | 11 + .../Parsers/Objects/ERichCurveTangentMode.cs | 15 + .../Objects/ERichCurveTangentWeightMode.cs | 15 + .../PakReader/Parsers/Objects/ESoundGroup.cs | 32 + .../Objects/ESoundWaveLoadingBehavior.cs | 18 + .../Objects/ESoundWavePrecacheState.cs | 10 + .../Objects/ESoundwaveSampleRateSettings.cs | 13 + .../Objects/EStringTableLoadingPhase.cs | 12 + FModel/PakReader/Parsers/Objects/ETextFlag.cs | 11 + .../Parsers/Objects/ETextHistoryType.cs | 22 + .../EUnrealEngineObjectLicenseeUE4Version.cs | 10 + .../Objects/EUnrealEngineObjectUE4Version.cs | 629 +++ .../PakReader/Parsers/Objects/FAssetData.cs | 36 + .../Objects/FAssetDataTagMapSharedView.cs | 19 + .../Parsers/Objects/FAssetIdentifier.cs | 40 + .../Parsers/Objects/FAssetPackageData.cs | 24 + .../Parsers/Objects/FAssetRegistryState.cs | 121 + .../Parsers/Objects/FAssetRegistryVersion.cs | 32 + .../Parsers/Objects/FBodyInstance.cs | 12 + FModel/PakReader/Parsers/Objects/FBox2D.cs | 19 + .../Parsers/Objects/FByteBulkData.cs | 37 + FModel/PakReader/Parsers/Objects/FColor.cs | 23 + .../Parsers/Objects/FColorMaterialInput.cs | 18 + .../Parsers/Objects/FCompressedChunk.cs | 20 + .../Parsers/Objects/FCustomVersion.cs | 17 + .../Objects/FCustomVersionContainer.cs | 14 + FModel/PakReader/Parsers/Objects/FDateTime.cs | 17 + .../PakReader/Parsers/Objects/FDependsNode.cs | 68 + .../Parsers/Objects/FDictionaryHeader.cs | 30 + .../Parsers/Objects/FEngineVersion.cs | 25 + FModel/PakReader/Parsers/Objects/FEntry.cs | 19 + .../Objects/FEvaluationTreeEntryHandle.cs | 12 + .../Parsers/Objects/FFormatArgumentValue.cs | 24 + .../Parsers/Objects/FFormatContainer.cs | 16 + .../PakReader/Parsers/Objects/FFrameNumber.cs | 12 + .../Parsers/Objects/FGameplayTagContainer.cs | 44 + .../Parsers/Objects/FGenerationInfo.cs | 16 + FModel/PakReader/Parsers/Objects/FGuid.cs | 63 + FModel/PakReader/Parsers/Objects/FIntPoint.cs | 16 + .../FLevelSequenceLegacyObjectReference.cs | 16 + .../FLevelSequenceObjectReferenceMap.cs | 18 + .../PakReader/Parsers/Objects/FLinearColor.cs | 24 + FModel/PakReader/Parsers/Objects/FMD5Hash.cs | 14 + .../Parsers/Objects/FMaterialInput.cs | 37 + .../Objects/FMovieSceneEvaluationKey.cs | 16 + .../Objects/FMovieSceneEvaluationTemplate.cs | 13 + .../Objects/FMovieSceneEvaluationTree.cs | 14 + .../Objects/FMovieSceneEvaluationTreeNode.cs | 18 + .../FMovieSceneEvaluationTreeNodeHandle.cs | 14 + .../Parsers/Objects/FMovieSceneFrameRange.cs | 12 + .../Parsers/Objects/FMovieSceneSegment.cs | 25 + FModel/PakReader/Parsers/Objects/FName.cs | 27 + .../Parsers/Objects/FNameEntrySerialized.cs | 23 + .../Objects/FNameTableArchiveReader.cs | 40 + .../Objects/FNavAgentSelectorCustomization.cs | 12 + .../Parsers/Objects/FObjectExport.cs | 91 + .../Parsers/Objects/FObjectImport.cs | 23 + .../Parsers/Objects/FObjectResource.cs | 8 + .../Parsers/Objects/FOodleCompressedData.cs | 21 + .../Objects/FOodleDictionaryArchive.cs | 16 + .../Parsers/Objects/FPackageFileSummary.cs | 197 + .../Parsers/Objects/FPackageIndex.cs | 45 + .../Parsers/Objects/FPakCompressedBlock.cs | 22 + .../Parsers/Objects/FPakDirectoryEntry.cs | 18 + FModel/PakReader/Parsers/Objects/FPakEntry.cs | 216 + FModel/PakReader/Parsers/Objects/FPakInfo.cs | 90 + .../Parsers/Objects/FPathHashIndexEntry.cs | 18 + .../Parsers/Objects/FPerPlatformFloat.cs | 13 + .../Parsers/Objects/FPerPlatformInt.cs | 13 + .../PakReader/Parsers/Objects/FPropertyTag.cs | 87 + FModel/PakReader/Parsers/Objects/FQuat.cs | 20 + .../Parsers/Objects/FRichCurveKey.cs | 39 + FModel/PakReader/Parsers/Objects/FRotator.cs | 18 + FModel/PakReader/Parsers/Objects/FSHAHash.cs | 14 + .../Objects/FSectionEvaluationDataTree.cs | 12 + .../Parsers/Objects/FSimpleCurveKey.cs | 16 + ...SkeletalMeshAreaWeightedTriangleSampler.cs | 19 + .../FSkeletalMeshSamplingLODBuiltData.cs | 13 + .../PakReader/Parsers/Objects/FSmartName.cs | 13 + .../Parsers/Objects/FSoftObjectPath.cs | 16 + .../Parsers/Objects/FStreamedAudioChunk.cs | 30 + .../PakReader/Parsers/Objects/FStringTable.cs | 29 + .../Parsers/Objects/FStripDataFlags.cs | 36 + FModel/PakReader/Parsers/Objects/FText.cs | 60 + .../PakReader/Parsers/Objects/FTextHistory.cs | 8 + .../Parsers/Objects/FTextHistoryBase.cs | 22 + .../Parsers/Objects/FTextHistoryDateTime.cs | 25 + .../Objects/FTextHistoryFormatNumber.cs | 21 + .../Parsers/Objects/FTextHistoryNone.cs | 19 + .../Objects/FTextHistoryOrderedFormat.cs | 23 + .../Objects/FTextHistoryStringTableEntry.cs | 19 + FModel/PakReader/Parsers/Objects/FTextKey.cs | 22 + .../Parsers/Objects/FTexture2DMipMap.cs | 21 + .../Parsers/Objects/FTexturePlatformData.cs | 32 + .../Parsers/Objects/FUniqueObjectGuid.cs | 13 + FModel/PakReader/Parsers/Objects/FVector.cs | 18 + FModel/PakReader/Parsers/Objects/FVector2D.cs | 16 + FModel/PakReader/Parsers/Objects/FVector4.cs | 24 + .../Parsers/Objects/FVectorMaterialInput.cs | 18 + FModel/PakReader/Parsers/Objects/IUStruct.cs | 5 + .../Objects/TEvaluationTreeEntryContainer.cs | 14 + .../Objects/TMovieSceneEvaluationTree.cs | 14 + FModel/PakReader/Parsers/Objects/TRange.cs | 14 + .../PakReader/Parsers/Objects/TRangeBound.cs | 14 + .../Parsers/Objects/UScriptStruct.cs | 58 + FModel/PakReader/Parsers/PackageReader.cs | 158 + FModel/PakReader/Parsers/PropertyAttribute.cs | 13 + .../Parsers/PropertyTagData/ArrayProperty.cs | 27 + .../Parsers/PropertyTagData/BaseProperty.cs | 57 + .../Parsers/PropertyTagData/BoolProperty.cs | 26 + .../Parsers/PropertyTagData/ByteProperty.cs | 20 + .../PropertyTagData/DelegateProperty.cs | 16 + .../Parsers/PropertyTagData/DoubleProperty.cs | 13 + .../Parsers/PropertyTagData/EnumProperty.cs | 13 + .../Parsers/PropertyTagData/FloatProperty.cs | 13 + .../Parsers/PropertyTagData/Int16Property.cs | 13 + .../Parsers/PropertyTagData/Int64Property.cs | 13 + .../Parsers/PropertyTagData/Int8Property.cs | 13 + .../Parsers/PropertyTagData/IntProperty.cs | 13 + .../PropertyTagData/InterfaceProperty.cs | 14 + .../PropertyTagData/LazyObjectProperty.cs | 13 + .../Parsers/PropertyTagData/MapProperty.cs | 29 + .../MulticastDelegateProperty.cs | 13 + .../Parsers/PropertyTagData/NameProperty.cs | 13 + .../Parsers/PropertyTagData/ObjectProperty.cs | 13 + .../Parsers/PropertyTagData/SetProperty.cs | 27 + .../PropertyTagData/SoftObjectProperty.cs | 15 + .../Parsers/PropertyTagData/StrProperty.cs | 13 + .../Parsers/PropertyTagData/StructProperty.cs | 13 + .../Parsers/PropertyTagData/TextProperty.cs | 13 + .../Parsers/PropertyTagData/UInt16Property.cs | 13 + .../Parsers/PropertyTagData/UInt32Property.cs | 13 + .../Parsers/PropertyTagData/UInt64Property.cs | 13 + FModel/PakReader/Parsers/ReflectionHelper.cs | 57 + .../ReaderExtensions.cs} | 36 +- FModel/PakReader/TextureDecoder.cs | 432 ++ FModel/Program.cs | 118 - FModel/Properties/AssemblyInfo.cs | 55 - FModel/Properties/Resources.Designer.cs | 2955 ++++++++-- FModel/Properties/Resources.ar.resx | 808 +++ FModel/Properties/Resources.de-DE.resx | 843 +++ FModel/Properties/Resources.fr-FR.resx | 850 +++ FModel/Properties/Resources.it-IT.resx | 808 +++ FModel/Properties/Resources.ja-JP.resx | 808 +++ FModel/Properties/Resources.resx | 1127 +++- FModel/Properties/Settings.Designer.cs | 552 +- FModel/Properties/Settings.cs | 55 + FModel/Properties/Settings.settings | 233 +- .../Resources/BurbankBigCondensed-Black.ttf | Bin 287616 -> 0 bytes .../{colorpicker1.png => ColorPickerOne.png} | Bin .../{colorpicker2.png => ColorPickerTwo.png} | Bin FModel/Resources/EBCDIC-NoSpecialChar.tbl | 256 - FModel/Resources/EBCDIC.tbl | 256 - FModel/Resources/EIconDesign_Default.png | Bin 0 -> 39703 bytes FModel/Resources/EIconDesign_Flat.png | Bin 0 -> 22474 bytes FModel/Resources/EIconDesign_Mini.png | Bin 0 -> 37047 bytes FModel/Resources/EIconDesign_NoText.png | Bin 0 -> 32367 bytes .../SyntaxHighlighter => Resources}/Ini.xshd | 0 .../SyntaxHighlighter => Resources}/Json.xshd | 22 +- FModel/Resources/Logo-Icon.ico | Bin 99678 -> 0 bytes FModel/Resources/Logo.png | Bin 20768 -> 0 bytes ...TT-JTCじゃんけんU & TT-JTCじゃんけんUP.TTC | Bin 1134904 -> 0 bytes FModel/Resources/T_ClipSize_Weapon_Stats.png | Bin 0 -> 1840 bytes .../T_DamagePerBullet_Weapon_Stats.png | Bin 0 -> 1381 bytes .../T_Placeholder_Challenge_Image.png | Bin 0 -> 17334 bytes FModel/Resources/T_Placeholder_Item_Image.png | Bin 0 -> 8639 bytes .../Resources/T_ReloadTime_Weapon_Stats.png | Bin 0 -> 2197 bytes FModel/Resources/Template_AC_F.png | Bin 69526 -> 0 bytes FModel/Resources/Template_AC_N.png | Bin 46218 -> 0 bytes FModel/Resources/Template_Challenge.png | Bin 19568 -> 0 bytes FModel/Resources/Template_D_F.png | Bin 35378 -> 0 bytes FModel/Resources/Template_D_N.png | Bin 27926 -> 0 bytes FModel/Resources/Template_F_F.png | Bin 25046 -> 0 bytes FModel/Resources/Template_F_N.png | Bin 22061 -> 0 bytes FModel/Resources/Template_M_F.png | Bin 35166 -> 0 bytes FModel/Resources/Template_M_N.png | Bin 27434 -> 0 bytes FModel/Resources/alert.ico | Bin 0 -> 9662 bytes FModel/Resources/alpha-a-box.png | Bin 0 -> 633 bytes FModel/Resources/api-off.ico | Bin 0 -> 9662 bytes FModel/Resources/api.ico | Bin 0 -> 9662 bytes FModel/Resources/backup-restore.png | Bin 0 -> 647 bytes FModel/Resources/bug.png | Bin 0 -> 529 bytes FModel/Resources/cast-audio.png | Bin 0 -> 1219 bytes FModel/Resources/challenge-theme-creator.png | Bin 0 -> 459 bytes FModel/Resources/check-circle.ico | Bin 0 -> 9662 bytes FModel/Resources/clipSize64.png | Bin 2249 -> 0 bytes FModel/Resources/close_file_16x.png | Bin 1053 -> 0 bytes FModel/Resources/content-copy.png | Bin 0 -> 593 bytes FModel/Resources/content-save.png | Bin 0 -> 487 bytes FModel/Resources/delete-forever.png | Bin 0 -> 671 bytes FModel/Resources/discord.png | Bin 0 -> 696 bytes FModel/Resources/dmg64.png | Bin 3572 -> 0 bytes FModel/Resources/egl2.ico | Bin 0 -> 39453 bytes FModel/Resources/file-export.png | Bin 0 -> 527 bytes FModel/Resources/file-image.ico | Bin 0 -> 9662 bytes FModel/Resources/file-multiple.png | Bin 0 -> 461 bytes FModel/Resources/file-restore.png | Bin 0 -> 588 bytes FModel/Resources/file.png | Bin 0 -> 428 bytes FModel/Resources/fmodel.png | Bin 0 -> 284049 bytes FModel/Resources/folder-download.png | Bin 0 -> 490 bytes FModel/Resources/folder-open.png | Bin 0 -> 508 bytes FModel/Resources/folder_16x.png | Bin 930 -> 0 bytes FModel/Resources/fortnite.ico | Bin 0 -> 41662 bytes FModel/Resources/gamepad-variant.png | Bin 0 -> 855 bytes FModel/Resources/github-circle.png | Bin 0 -> 740 bytes FModel/Resources/icon-creator.png | Bin 0 -> 375 bytes FModel/Resources/image-filter-black-white.png | Bin 0 -> 490 bytes FModel/Resources/image-move.png | Bin 0 -> 904 bytes FModel/Resources/image-plus.png | Bin 0 -> 756 bytes FModel/Resources/image-remove.png | Bin 0 -> 878 bytes FModel/Resources/info_16x.png | Bin 1994 -> 0 bytes FModel/Resources/information.png | Bin 0 -> 576 bytes FModel/Resources/key.png | Bin 0 -> 498 bytes FModel/Resources/lock-open-variant.ico | Bin 0 -> 9662 bytes FModel/Resources/magnify.png | Bin 0 -> 562 bytes FModel/Resources/open-in-new.png | Bin 0 -> 659 bytes FModel/Resources/open_16x.png | Bin 556 -> 0 bytes FModel/Resources/pause.png | Bin 0 -> 398 bytes FModel/Resources/paypal.png | Bin 0 -> 675 bytes FModel/Resources/pencil.png | Bin 0 -> 474 bytes FModel/Resources/play.png | Bin 0 -> 580 bytes FModel/Resources/playlist-plus.png | Bin 0 -> 435 bytes FModel/Resources/power.png | Bin 0 -> 603 bytes FModel/Resources/progress-download.png | Bin 0 -> 737 bytes FModel/Resources/refresh.png | Bin 0 -> 581 bytes FModel/Resources/reload64.png | Bin 1311 -> 0 bytes FModel/Resources/save_16x.png | Bin 715 -> 0 bytes FModel/Resources/settings.png | Bin 0 -> 657 bytes FModel/Resources/settings_16x.png | Bin 2227 -> 0 bytes FModel/Resources/share-all.png | Bin 0 -> 732 bytes FModel/Resources/share.png | Bin 0 -> 503 bytes FModel/Resources/sign-direction-plus.png | Bin 0 -> 533 bytes FModel/Resources/sign-direction-remove.png | Bin 0 -> 514 bytes FModel/Resources/sign-direction.png | Bin 0 -> 518 bytes FModel/Resources/stop.png | Bin 0 -> 391 bytes FModel/Resources/unknown512.png | Bin 7746 -> 0 bytes FModel/Resources/valorant.live.ico | Bin 0 -> 92398 bytes FModel/Resources/view-dashboard.png | Bin 0 -> 396 bytes FModel/Resources/volume-minus.png | Bin 0 -> 491 bytes FModel/Resources/volume-mute.png | Bin 0 -> 616 bytes FModel/Resources/volume-plus.png | Bin 0 -> 506 bytes FModel/Resources/wifi-strength-off.ico | Bin 0 -> 9662 bytes FModel/Resources/zip-box.png | Bin 0 -> 434 bytes .../LeftMarginMultiplierConverter.cs | 7 +- .../{Themes/Styles.xaml => Theme/Style.xaml} | 268 +- .../TreeViewItemExtensions.cs | 6 +- FModel/Utils/Assets.cs | 420 ++ FModel/Utils/Commands.cs | 15 + FModel/Utils/EGL2.cs | 24 + FModel/Utils/Endpoints.cs | 76 + FModel/Utils/FConsole.cs | 42 + .../FormsUtility.cs => Utils/FWindows.cs} | 7 +- FModel/Utils/Folders.cs | 107 + .../Utils/HttpClientDownloadWithProgress.cs | 109 + FModel/Utils/Keys.cs | 91 + FModel/Utils/Localizations.cs | 166 + FModel/Utils/ObservableSortedList.cs | 203 + FModel/Utils/Paks.cs | 167 + FModel/Utils/Streams.cs | 35 + FModel/Utils/Strings.cs | 30 + FModel/Utils/Tasks.cs | 23 + FModel/Utils/Updater.cs | 74 + .../AvalonEdit/AvalonEditViewModel.cs | 141 + .../Buttons/ExtractStopViewModel.cs | 35 + .../ViewModels/ComboBox/ComboBoxViewModel.cs | 63 + .../ViewModels/DataGrid/DataGridViewModel.cs | 51 + .../ViewModels/ImageBox/ImageBoxViewModel.cs | 163 + FModel/ViewModels/ListBox/ListBoxViewModel.cs | 37 + .../MenuItem/BackupMenuItemViewModel.cs | 219 + FModel/ViewModels/MenuItem/CommandHandler.cs | 49 + .../MenuItem/GotoMenuItemViewModel.cs | 177 + FModel/ViewModels/MenuItem/MenuItems.cs | 71 + .../MenuItem/PakMenuItemViewModel.cs | 412 ++ .../ViewModels/Notifier/NotifierViewModel.cs | 63 + FModel/ViewModels/PropertyChangedBase.cs | 19 + .../SoundPlayer/InputFileViewModel.cs | 79 + .../StatusBar/StatusBarViewModel.cs | 69 + .../TabControl/AssetPropertiesViewModel.cs | 96 + .../TabControl/PakPropertiesViewModel.cs | 83 + .../Treeview/SortedTreeviewViewModel.cs | 103 + .../Treeview}/TreeViewItemBehavior.cs | 25 +- .../ViewModels/Treeview/TreeviewViewModel.cs | 65 + FModel/Windows/AESManager/AESManager.xaml | 79 + FModel/Windows/AESManager/AESManager.xaml.cs | 160 + .../About/FAbout.xaml} | 42 +- FModel/Windows/About/FAbout.xaml.cs | 15 + .../AvalonEditFindReplace.xaml | 70 + .../AvalonEditFindReplace.xaml.cs} | 13 +- .../AvalonEditFindReplaceHelper.cs} | 75 +- .../ColorPicker}/ColorPalette.cs | 4 +- FModel/Windows/ColorPicker/ColorPickRow.xaml | 32 + .../ColorPicker/ColorPickRow.xaml.cs | 12 +- .../ColorPicker/ColorPickerControl.xaml | 100 + .../ColorPicker/ColorPickerControl.xaml.cs | 29 +- .../ColorPicker}/ColorPickerDialogOptions.cs | 6 +- .../ColorPicker/ColorPickerSettings.cs | 3 +- .../ColorPicker/ColorPickerSwatch.xaml | 25 + .../ColorPicker/ColorPickerSwatch.xaml.cs | 16 +- .../ColorPicker/ColorPickerWindow.xaml | 27 + .../ColorPicker/ColorPickerWindow.xaml.cs | 19 +- FModel/Windows/ColorPicker/ColorSwatchItem.cs | 10 + .../ColorPicker/SliderRow.xaml | 13 +- .../ColorPicker/SliderRow.xaml.cs | 12 +- .../Code => Windows/ColorPicker}/Util.cs | 41 +- .../CustomNotifier/CustomNotifier.xaml | 31 + .../CustomNotifier/CustomNotifier.xaml.cs | 17 + .../CustomNotifier/CustomNotifierHelper.cs | 14 + .../DarkMessageBox/DarkMessageBox.xaml} | 24 +- .../DarkMessageBox/DarkMessageBox.xaml.cs} | 49 +- .../DarkMessageBox/DarkMessageBoxHelper.cs} | 116 +- FModel/Windows/DependencyObjects.cs | 49 + FModel/Windows/ImagesMerger/ImagesMerger.xaml | 81 + .../Windows/ImagesMerger/ImagesMerger.xaml.cs | 287 + FModel/Windows/Launcher/FLauncher.xaml | 75 + FModel/Windows/Launcher/FLauncher.xaml.cs | 87 + FModel/Windows/Search/Search.xaml | 67 + FModel/Windows/Search/Search.xaml.cs | 146 + .../Settings/ChallengeBundlesCreator.xaml | 137 + .../Settings/ChallengeBundlesCreator.xaml.cs | 132 + FModel/Windows/Settings/General.xaml | 138 + FModel/Windows/Settings/General.xaml.cs | 96 + FModel/Windows/Settings/IconCreator.xaml | 220 + FModel/Windows/Settings/IconCreator.xaml.cs | 156 + FModel/Windows/SoundPlayer/AudioPlayer.xaml | 113 + .../Windows/SoundPlayer/AudioPlayer.xaml.cs | 111 + FModel/Windows/SoundPlayer/ISample.cs | 7 + FModel/Windows/SoundPlayer/NVorbisSource.cs | 76 + .../UserControls/SpectrumAnalyzer.xaml | 11 + .../UserControls/SpectrumAnalyzer.xaml.cs | 22 + .../SoundPlayer/UserControls/Timeclock.xaml | 11 + .../UserControls/Timeclock.xaml.cs | 17 + .../SoundPlayer/UserControls/Timeline.xaml | 11 + .../SoundPlayer/UserControls/Timeline.xaml.cs | 17 + .../Visualization/BasicSpectrumProvider.cs | 51 + .../SoundPlayer/Visualization/Device.cs | 126 + .../SoundPlayer/Visualization/EClockType.cs | 8 + .../SoundPlayer/Visualization/EDeviceType.cs | 8 + .../Visualization/EScalingStrategy.cs | 9 + .../Visualization/ESourceEventType.cs | 8 + .../Visualization/ESourceProperty.cs | 11 + .../SoundPlayer/Visualization/ISource.cs | 26 + .../Visualization/ISpectrumProvider.cs | 8 + .../SoundPlayer/Visualization/OutputSource.cs | 511 ++ .../Visualization/SourceEventArgs.cs | 9 + .../SourcePropertyChangedEventArgs.cs | 10 + .../Visualization/SpectrumAnalyzer.cs | 725 +++ .../SoundPlayer/Visualization/Timeclock.cs | 624 +++ .../SoundPlayer/Visualization/Timeline.cs | 528 ++ FModel/Windows/UserInput/GoToUserInput.xaml | 45 + .../Windows/UserInput/GoToUserInput.xaml.cs | 54 + FModel/packages.config | 16 - Images/FModel.png | Bin 49737 -> 0 bytes Images/FModel_Demo.gif | Bin 8974453 -> 0 bytes Images/Logo.png | Bin 20768 -> 0 bytes README.md | 183 +- 650 files changed, 28477 insertions(+), 34023 deletions(-) delete mode 100644 FModel/App.config create mode 100644 FModel/AssemblyInfo.cs delete mode 100644 FModel/Commands/FModel_Commands.cs create mode 100644 FModel/Creator/BaseBundle.cs create mode 100644 FModel/Creator/BaseIcon.cs create mode 100644 FModel/Creator/BaseUserOption.cs create mode 100644 FModel/Creator/Bundles/CompletionReward.cs create mode 100644 FModel/Creator/Bundles/Header.cs create mode 100644 FModel/Creator/Bundles/HeaderStyle.cs create mode 100644 FModel/Creator/Bundles/Quest.cs create mode 100644 FModel/Creator/Bundles/QuestStyle.cs create mode 100644 FModel/Creator/Bundles/Reward.cs create mode 100644 FModel/Creator/Creator.cs create mode 100644 FModel/Creator/Icons/DisplayAssetImage.cs create mode 100644 FModel/Creator/Icons/LargeSmallImage.cs create mode 100644 FModel/Creator/Icons/UserFacingFlag.cs create mode 100644 FModel/Creator/Icons/Watermark.cs create mode 100644 FModel/Creator/Rarities/EFortRarity.cs create mode 100644 FModel/Creator/Rarities/Rarity.cs create mode 100644 FModel/Creator/Rarities/Serie.cs create mode 100644 FModel/Creator/Stats/Statistic.cs create mode 100644 FModel/Creator/Stats/Statistics.cs create mode 100644 FModel/Creator/Texts/ETextSide.cs create mode 100644 FModel/Creator/Texts/GameplayTag.cs create mode 100644 FModel/Creator/Texts/Helper.cs create mode 100644 FModel/Creator/Texts/Text.cs create mode 100644 FModel/Creator/Texts/Typefaces.cs create mode 100644 FModel/Creator/Utils.cs create mode 100644 FModel/Discord/DiscordIntegration.cs create mode 100644 FModel/Enums.cs create mode 100644 FModel/FModel.ico delete mode 100644 FModel/FModel_Main.xaml delete mode 100644 FModel/FModel_Main.xaml.cs delete mode 100644 FModel/Forms/AESManager.xaml delete mode 100644 FModel/Forms/AESManager.xaml.cs delete mode 100644 FModel/Forms/ColorPicker/Code/ColorSwatchItem.cs delete mode 100644 FModel/Forms/ColorPicker/ColorPickRow.xaml delete mode 100644 FModel/Forms/ColorPicker/ColorPickerControl.xaml delete mode 100644 FModel/Forms/ColorPicker/ColorPickerSwatch.xaml delete mode 100644 FModel/Forms/ColorPicker/ColorPickerWindow.xaml delete mode 100644 FModel/Forms/FModel_About.xaml.cs delete mode 100644 FModel/Forms/FModel_ImagesMerger.xaml delete mode 100644 FModel/Forms/FModel_ImagesMerger.xaml.cs delete mode 100644 FModel/Forms/FModel_SearchFiles.xaml delete mode 100644 FModel/Forms/FModel_SearchFiles.xaml.cs delete mode 100644 FModel/Forms/FModel_Settings.xaml delete mode 100644 FModel/Forms/FModel_Settings.xaml.cs delete mode 100644 FModel/Forms/FModel_UpdateMode.xaml delete mode 100644 FModel/Forms/FModel_UpdateMode.xaml.cs delete mode 100644 FModel/Forms/HexViewer/BaseByte.cs delete mode 100644 FModel/Forms/HexViewer/BrushesDictionary.xaml delete mode 100644 FModel/Forms/HexViewer/Core/BookMark.cs delete mode 100644 FModel/Forms/HexViewer/Core/Bytes/ByteConverters.cs delete mode 100644 FModel/Forms/HexViewer/Core/Bytes/ByteModified.cs delete mode 100644 FModel/Forms/HexViewer/Core/Bytes/ByteProvider.cs delete mode 100644 FModel/Forms/HexViewer/Core/Caret.cs delete mode 100644 FModel/Forms/HexViewer/Core/CharacterTable/DTE.cs delete mode 100644 FModel/Forms/HexViewer/Core/CharacterTable/Enum.cs delete mode 100644 FModel/Forms/HexViewer/Core/CharacterTable/TBLStream.cs delete mode 100644 FModel/Forms/HexViewer/Core/ConstantReadOnly.cs delete mode 100644 FModel/Forms/HexViewer/Core/Converters/BoolInverterConverter.cs delete mode 100644 FModel/Forms/HexViewer/Core/Converters/BooleanToVisibilityConverter.cs delete mode 100644 FModel/Forms/HexViewer/Core/Converters/HexToLongStringConverter.cs delete mode 100644 FModel/Forms/HexViewer/Core/Converters/LongToHexStringConverter.cs delete mode 100644 FModel/Forms/HexViewer/Core/Converters/PathToFilenameConverter.cs delete mode 100644 FModel/Forms/HexViewer/Core/Enumeration.cs delete mode 100644 FModel/Forms/HexViewer/Core/GenericStaticInstance.cs delete mode 100644 FModel/Forms/HexViewer/Core/Interfaces/IByteControl.cs delete mode 100644 FModel/Forms/HexViewer/Core/Interfaces/IByteModified.cs delete mode 100644 FModel/Forms/HexViewer/Core/KeyValidator.cs delete mode 100644 FModel/Forms/HexViewer/Core/MethodExtention/ApplicationExtention.cs delete mode 100644 FModel/Forms/HexViewer/Core/MethodExtention/ByteArrayExtention.cs delete mode 100644 FModel/Forms/HexViewer/Core/MethodExtention/DoubleExtension.cs delete mode 100644 FModel/Forms/HexViewer/Core/MethodExtention/StringExtension.cs delete mode 100644 FModel/Forms/HexViewer/Core/MethodExtention/TrackExtention.cs delete mode 100644 FModel/Forms/HexViewer/Core/Native/NativeMethods.cs delete mode 100644 FModel/Forms/HexViewer/Core/Xcbb/CustomBackgroundBlock.cs delete mode 100644 FModel/Forms/HexViewer/Core/Xcbb/ExeFile.cs delete mode 100644 FModel/Forms/HexViewer/Core/Xcbb/Exefile.xcbb delete mode 100644 FModel/Forms/HexViewer/Core/Xcbb/XcbbExpressionParser.cs delete mode 100644 FModel/Forms/HexViewer/Core/Xcbb/XcbbFileParser.cs delete mode 100644 FModel/Forms/HexViewer/FastTextLine.cs delete mode 100644 FModel/Forms/HexViewer/FindReplaceWindow.xaml delete mode 100644 FModel/Forms/HexViewer/FindReplaceWindow.xaml.cs delete mode 100644 FModel/Forms/HexViewer/FindWindow.xaml delete mode 100644 FModel/Forms/HexViewer/FindWindow.xaml.cs delete mode 100644 FModel/Forms/HexViewer/GiveByteWindow.xaml delete mode 100644 FModel/Forms/HexViewer/GiveByteWindow.xaml.cs delete mode 100644 FModel/Forms/HexViewer/HexBox.xaml delete mode 100644 FModel/Forms/HexViewer/HexBox.xaml.cs delete mode 100644 FModel/Forms/HexViewer/HexByte.cs delete mode 100644 FModel/Forms/HexViewer/HexEditor.xaml delete mode 100644 FModel/Forms/HexViewer/HexEditor.xaml.cs delete mode 100644 FModel/Forms/HexViewer/HexViewer.xaml delete mode 100644 FModel/Forms/HexViewer/HexViewer.xaml.cs delete mode 100644 FModel/Forms/HexViewer/MiscelanousDictionary.xaml delete mode 100644 FModel/Forms/HexViewer/ReplaceByteWindow.xaml delete mode 100644 FModel/Forms/HexViewer/ReplaceByteWindow.xaml.cs delete mode 100644 FModel/Forms/HexViewer/StringByte.cs delete mode 100644 FModel/Forms/HexViewer/ToolTipDictionary.xaml create mode 100644 FModel/Globals.cs create mode 100644 FModel/Grabber/Aes/AesData.cs create mode 100644 FModel/Grabber/Aes/AesGrabber.cs create mode 100644 FModel/Grabber/Cdn/CdnData.cs create mode 100644 FModel/Grabber/Cdn/CdnDataGrabber.cs create mode 100644 FModel/Grabber/Paks/InstallsJson.cs create mode 100644 FModel/Grabber/Paks/LauncherDat.cs create mode 100644 FModel/Grabber/Paks/PaksGrabber.cs create mode 100644 FModel/Logger/DebugHelper.cs rename FModel/{Methods/Utilities => Logger}/Logger.cs (78%) delete mode 100644 FModel/Logo.ico create mode 100644 FModel/MainWindow.xaml create mode 100644 FModel/MainWindow.xaml.cs delete mode 100644 FModel/Methods/AESManager/DynamicKeysChecker.cs delete mode 100644 FModel/Methods/AESManager/KeysManager.cs delete mode 100644 FModel/Methods/Assets/AssetInformations.cs delete mode 100644 FModel/Methods/Assets/AssetTranslations.cs delete mode 100644 FModel/Methods/Assets/AssetsLoader.cs delete mode 100644 FModel/Methods/Assets/IconCreator/AthenaID/CosmeticSeason.cs delete mode 100644 FModel/Methods/Assets/IconCreator/AthenaID/CosmeticSet.cs delete mode 100644 FModel/Methods/Assets/IconCreator/AthenaID/IconUserFacingFlags.cs delete mode 100644 FModel/Methods/Assets/IconCreator/ChallengeID/ChallengeBundleInfos.cs delete mode 100644 FModel/Methods/Assets/IconCreator/ChallengeID/ChallengeCompletionRewards.cs delete mode 100644 FModel/Methods/Assets/IconCreator/ChallengeID/ChallengeIconDesign.cs delete mode 100644 FModel/Methods/Assets/IconCreator/ChallengeID/ChallengeRewards.cs delete mode 100644 FModel/Methods/Assets/IconCreator/HeroID/HeroGameplayDefinition.cs delete mode 100644 FModel/Methods/Assets/IconCreator/IconCreator.cs delete mode 100644 FModel/Methods/Assets/IconCreator/IconImage.cs delete mode 100644 FModel/Methods/Assets/IconCreator/IconText.cs delete mode 100644 FModel/Methods/Assets/IconCreator/IconWatermark.cs delete mode 100644 FModel/Methods/Assets/IconCreator/Rarity.cs delete mode 100644 FModel/Methods/Assets/IconCreator/WeaponID/IconAmmoData.cs delete mode 100644 FModel/Methods/Assets/IconCreator/WeaponID/WeaponStats.cs delete mode 100644 FModel/Methods/Auth/AuthFlow.cs delete mode 100644 FModel/Methods/Auth/Requests.cs delete mode 100644 FModel/Methods/BackupsManager/RegisterDownloadedBackups.cs delete mode 100644 FModel/Methods/FVar.cs delete mode 100644 FModel/Methods/FindReplace/FindReplaceDialog.xaml delete mode 100644 FModel/Methods/PAKs/BackupPAKs.cs delete mode 100644 FModel/Methods/PAKs/PAKsLoader.cs delete mode 100644 FModel/Methods/PAKs/RegisterFromPath.cs delete mode 100644 FModel/Methods/PakReader/AssetRegReader.cs delete mode 100644 FModel/Methods/PakReader/DDSDecoder.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/AssetReader.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/ExportObject.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/FontFace/FontFace.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/Texture2D/Texture2D.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UAnimSequence/UAnimSequence.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UCurveTable/ECurveTableMode.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UCurveTable/UCurveTable.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UDataTable/UDataTable.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UDictionary/FDictionaryHeader/FDictionaryHeader.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UDictionary/FDictionaryHeader/FOodleCompressedData.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UDictionary/UDictionary.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UObject/UObject.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptArray.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptMap.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FAnimKeyHeader.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FBoxSphereBounds.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FByteBulkData.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FByteBulkDataHeader.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FColor.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FCompressedOffsetData.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FCompressedSegment.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FDateTime.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FGameplayTagContainer.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FGuid.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FIntPoint.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FLevelSequenceObjectReferenceMap/FLevelSequenceLegacyObjectReference.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FLevelSequenceObjectReferenceMap/FLevelSequenceObjectReferenceMap.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FLinearColor.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FNameEntrySerialized.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FObjectExport.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FObjectImport.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FPackageIndex.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FPropertyTag/FPropertyTag.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FPropertyTag/FPropertyTagType.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FQuat.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FReferencePose.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FReferenceSkeleton/FMeshBoneInfo.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FReferenceSkeleton/FReferenceSkeleton.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FReferenceSkeleton/FTransform.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FRichCurveKey.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FRotator.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FScriptDelegate.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FSimpleCurveKey.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FSkeletalMaterial/FMeshUVChannelInfo.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FSkeletalMaterial/FSkeletalMaterial.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FSkeletalMeshLODInfo.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FSmartName.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FSoftObjectPath.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FSoftObjectPathMap.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FSoundFormatData.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FColorVertexBuffer.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FMultisizeIndexContainer.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FPositionVertexBuffer.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkelMeshSection/FApexClothPhysToRenderVertData.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkelMeshSection/FClothingSectionData.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkelMeshSection/FDuplicatedVerticesBuffer/FDuplicatedVerticesBuffer.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkelMeshSection/FDuplicatedVerticesBuffer/FIndexLengthPair.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkelMeshSection/FSkelMeshSection.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkeletalMeshVertexBuffer/FGPUVert4/FGPUVert4Float.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkeletalMeshVertexBuffer/FGPUVert4/FGPUVert4Half.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkeletalMeshVertexBuffer/FGPUVert4/FMeshUV/FMeshUVFloat.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkeletalMeshVertexBuffer/FGPUVert4/FMeshUV/FMeshUVHalf.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkeletalMeshVertexBuffer/FGPUVert4/FPackedNormal.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkeletalMeshVertexBuffer/FSkeletalMeshVertexBuffer.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkeletalMeshVertexClothBuffer.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkinWeightProfilesData/FRuntimeSkinWeightProfileData/FRuntimeSkinWeightProfileData.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkinWeightProfilesData/FRuntimeSkinWeightProfileData/FSkinWeightOverrideInfo.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkinWeightProfilesData/FSkinWeightProfilesData.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkinWeightVertexBuffer/FSkinWeightInfo.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FSkinWeightVertexBuffer/FSkinWeightVertexBuffer.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FStaticLODModel.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FStaticMeshVertexBuffer/FStaticMeshUVItem4/FPackedRGBA16N.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FStaticMeshVertexBuffer/FStaticMeshUVItem4/FStaticMeshUVItem4.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FStaticMeshVertexBuffer/FStaticMeshVertexBuffer.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStaticLODModel/FVector4.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStreamedAudioChunk.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStripDataFlags.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FStructFallback.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FText.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FTexturePlatformData/FTexture2DMipMap.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FTexturePlatformData/FTexturePlatformData.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FTrack.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FVector.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/FVector2D.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/UScript/UScriptStruct/UScriptStruct.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/USkeletalMesh/USkeletalMesh.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/USkeleton/USkeleton.cs delete mode 100644 FModel/Methods/PakReader/ExportObject/USoundWave/USoundWave.cs delete mode 100644 FModel/Methods/PakReader/ImageExporter.cs delete mode 100644 FModel/Methods/PakReader/LocReader.cs delete mode 100644 FModel/Methods/PakReader/MeshExporter.cs delete mode 100644 FModel/Methods/PakReader/Objects.cs delete mode 100644 FModel/Methods/PakReader/PakReader.cs delete mode 100644 FModel/Methods/PakReader/SigReader.cs delete mode 100644 FModel/Methods/SyntaxHighlighter/ResourceLoader.cs delete mode 100644 FModel/Methods/TreeViewModel/PropertyChangedBase.cs delete mode 100644 FModel/Methods/TreeViewModel/SortedTreeViewWindowViewModel.cs delete mode 100644 FModel/Methods/TreeViewModel/TreeViewModel.cs delete mode 100644 FModel/Methods/Utilities/AESUtility.cs delete mode 100644 FModel/Methods/Utilities/AssetsUtility.cs delete mode 100644 FModel/Methods/Utilities/ChallengesUtility.cs delete mode 100644 FModel/Methods/Utilities/DebugHelper.cs delete mode 100644 FModel/Methods/Utilities/EndpointsUtility.cs delete mode 100644 FModel/Methods/Utilities/FoldersUtility.cs delete mode 100644 FModel/Methods/Utilities/ImagesUtility.cs delete mode 100644 FModel/Methods/Utilities/ListBoxUtility.cs delete mode 100644 FModel/Methods/Utilities/MBoxesUtility.cs delete mode 100644 FModel/Methods/Utilities/PAKsUtility.cs delete mode 100644 FModel/Methods/Utilities/TasksUtility.cs delete mode 100644 FModel/Methods/Utilities/TextsUtility.cs delete mode 100644 FModel/Methods/Utilities/TreeViewUtility.cs delete mode 100644 FModel/Methods/Utilities/UIUtility.cs rename FModel/{Methods => }/PakReader/AESDecryptor.cs (98%) create mode 100644 FModel/PakReader/BinaryHelper.cs rename FModel/{Methods => }/PakReader/LICENSE (100%) create mode 100644 FModel/PakReader/LocMetaReader.cs create mode 100644 FModel/PakReader/LocResReader.cs create mode 100644 FModel/PakReader/Pak/DefaultPakFilter.cs create mode 100644 FModel/PakReader/Pak/IPakFilter.cs create mode 100644 FModel/PakReader/Pak/PakFileReader.cs create mode 100644 FModel/PakReader/Pak/PakFilter.cs create mode 100644 FModel/PakReader/Pak/PakIndex.cs create mode 100644 FModel/PakReader/Pak/PakPackage.cs create mode 100644 FModel/PakReader/Parsers/Class/IUExport.cs create mode 100644 FModel/PakReader/Parsers/Class/UCurveTable.cs create mode 100644 FModel/PakReader/Parsers/Class/UDataTable.cs create mode 100644 FModel/PakReader/Parsers/Class/UFontFace.cs create mode 100644 FModel/PakReader/Parsers/Class/UObject.cs create mode 100644 FModel/PakReader/Parsers/Class/USoundWave.cs create mode 100644 FModel/PakReader/Parsers/Class/UStringTable.cs create mode 100644 FModel/PakReader/Parsers/Class/UTexture2D.cs create mode 100644 FModel/PakReader/Parsers/Objects/EAssetRegistryDependencyType.cs create mode 100644 FModel/PakReader/Parsers/Objects/EBulkDataFlags.cs create mode 100644 FModel/PakReader/Parsers/Objects/ECompressionFlags.cs create mode 100644 FModel/PakReader/Parsers/Objects/ECurveTableMode.cs create mode 100644 FModel/PakReader/Parsers/Objects/EDateTimeStyle.cs create mode 100644 FModel/PakReader/Parsers/Objects/EDecompressionType.cs create mode 100644 FModel/PakReader/Parsers/Objects/EExpressionType.cs create mode 100644 FModel/PakReader/Parsers/Objects/EFormatArgumentType.cs create mode 100644 FModel/PakReader/Parsers/Objects/EInitializationMode.cs create mode 100644 FModel/PakReader/Parsers/Objects/ELightingBuildQuality.cs create mode 100644 FModel/PakReader/Parsers/Objects/EObjectFlags.cs create mode 100644 FModel/PakReader/Parsers/Objects/EPackageFlags.cs create mode 100644 FModel/PakReader/Parsers/Objects/EPakVersion.cs create mode 100644 FModel/PakReader/Parsers/Objects/EPixelFormat.cs create mode 100644 FModel/PakReader/Parsers/Objects/ERangeBoundType.cs create mode 100644 FModel/PakReader/Parsers/Objects/ERichCurveCompressionFormat.cs create mode 100644 FModel/PakReader/Parsers/Objects/ERichCurveInterpMode.cs create mode 100644 FModel/PakReader/Parsers/Objects/ERichCurveKeyTimeCompressionFormat.cs create mode 100644 FModel/PakReader/Parsers/Objects/ERichCurveTangentMode.cs create mode 100644 FModel/PakReader/Parsers/Objects/ERichCurveTangentWeightMode.cs create mode 100644 FModel/PakReader/Parsers/Objects/ESoundGroup.cs create mode 100644 FModel/PakReader/Parsers/Objects/ESoundWaveLoadingBehavior.cs create mode 100644 FModel/PakReader/Parsers/Objects/ESoundWavePrecacheState.cs create mode 100644 FModel/PakReader/Parsers/Objects/ESoundwaveSampleRateSettings.cs create mode 100644 FModel/PakReader/Parsers/Objects/EStringTableLoadingPhase.cs create mode 100644 FModel/PakReader/Parsers/Objects/ETextFlag.cs create mode 100644 FModel/PakReader/Parsers/Objects/ETextHistoryType.cs create mode 100644 FModel/PakReader/Parsers/Objects/EUnrealEngineObjectLicenseeUE4Version.cs create mode 100644 FModel/PakReader/Parsers/Objects/EUnrealEngineObjectUE4Version.cs create mode 100644 FModel/PakReader/Parsers/Objects/FAssetData.cs create mode 100644 FModel/PakReader/Parsers/Objects/FAssetDataTagMapSharedView.cs create mode 100644 FModel/PakReader/Parsers/Objects/FAssetIdentifier.cs create mode 100644 FModel/PakReader/Parsers/Objects/FAssetPackageData.cs create mode 100644 FModel/PakReader/Parsers/Objects/FAssetRegistryState.cs create mode 100644 FModel/PakReader/Parsers/Objects/FAssetRegistryVersion.cs create mode 100644 FModel/PakReader/Parsers/Objects/FBodyInstance.cs create mode 100644 FModel/PakReader/Parsers/Objects/FBox2D.cs create mode 100644 FModel/PakReader/Parsers/Objects/FByteBulkData.cs create mode 100644 FModel/PakReader/Parsers/Objects/FColor.cs create mode 100644 FModel/PakReader/Parsers/Objects/FColorMaterialInput.cs create mode 100644 FModel/PakReader/Parsers/Objects/FCompressedChunk.cs create mode 100644 FModel/PakReader/Parsers/Objects/FCustomVersion.cs create mode 100644 FModel/PakReader/Parsers/Objects/FCustomVersionContainer.cs create mode 100644 FModel/PakReader/Parsers/Objects/FDateTime.cs create mode 100644 FModel/PakReader/Parsers/Objects/FDependsNode.cs create mode 100644 FModel/PakReader/Parsers/Objects/FDictionaryHeader.cs create mode 100644 FModel/PakReader/Parsers/Objects/FEngineVersion.cs create mode 100644 FModel/PakReader/Parsers/Objects/FEntry.cs create mode 100644 FModel/PakReader/Parsers/Objects/FEvaluationTreeEntryHandle.cs create mode 100644 FModel/PakReader/Parsers/Objects/FFormatArgumentValue.cs create mode 100644 FModel/PakReader/Parsers/Objects/FFormatContainer.cs create mode 100644 FModel/PakReader/Parsers/Objects/FFrameNumber.cs create mode 100644 FModel/PakReader/Parsers/Objects/FGameplayTagContainer.cs create mode 100644 FModel/PakReader/Parsers/Objects/FGenerationInfo.cs create mode 100644 FModel/PakReader/Parsers/Objects/FGuid.cs create mode 100644 FModel/PakReader/Parsers/Objects/FIntPoint.cs create mode 100644 FModel/PakReader/Parsers/Objects/FLevelSequenceLegacyObjectReference.cs create mode 100644 FModel/PakReader/Parsers/Objects/FLevelSequenceObjectReferenceMap.cs create mode 100644 FModel/PakReader/Parsers/Objects/FLinearColor.cs create mode 100644 FModel/PakReader/Parsers/Objects/FMD5Hash.cs create mode 100644 FModel/PakReader/Parsers/Objects/FMaterialInput.cs create mode 100644 FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationKey.cs create mode 100644 FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTemplate.cs create mode 100644 FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTree.cs create mode 100644 FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTreeNode.cs create mode 100644 FModel/PakReader/Parsers/Objects/FMovieSceneEvaluationTreeNodeHandle.cs create mode 100644 FModel/PakReader/Parsers/Objects/FMovieSceneFrameRange.cs create mode 100644 FModel/PakReader/Parsers/Objects/FMovieSceneSegment.cs create mode 100644 FModel/PakReader/Parsers/Objects/FName.cs create mode 100644 FModel/PakReader/Parsers/Objects/FNameEntrySerialized.cs create mode 100644 FModel/PakReader/Parsers/Objects/FNameTableArchiveReader.cs create mode 100644 FModel/PakReader/Parsers/Objects/FNavAgentSelectorCustomization.cs create mode 100644 FModel/PakReader/Parsers/Objects/FObjectExport.cs create mode 100644 FModel/PakReader/Parsers/Objects/FObjectImport.cs create mode 100644 FModel/PakReader/Parsers/Objects/FObjectResource.cs create mode 100644 FModel/PakReader/Parsers/Objects/FOodleCompressedData.cs create mode 100644 FModel/PakReader/Parsers/Objects/FOodleDictionaryArchive.cs create mode 100644 FModel/PakReader/Parsers/Objects/FPackageFileSummary.cs create mode 100644 FModel/PakReader/Parsers/Objects/FPackageIndex.cs create mode 100644 FModel/PakReader/Parsers/Objects/FPakCompressedBlock.cs create mode 100644 FModel/PakReader/Parsers/Objects/FPakDirectoryEntry.cs create mode 100644 FModel/PakReader/Parsers/Objects/FPakEntry.cs create mode 100644 FModel/PakReader/Parsers/Objects/FPakInfo.cs create mode 100644 FModel/PakReader/Parsers/Objects/FPathHashIndexEntry.cs create mode 100644 FModel/PakReader/Parsers/Objects/FPerPlatformFloat.cs create mode 100644 FModel/PakReader/Parsers/Objects/FPerPlatformInt.cs create mode 100644 FModel/PakReader/Parsers/Objects/FPropertyTag.cs create mode 100644 FModel/PakReader/Parsers/Objects/FQuat.cs create mode 100644 FModel/PakReader/Parsers/Objects/FRichCurveKey.cs create mode 100644 FModel/PakReader/Parsers/Objects/FRotator.cs create mode 100644 FModel/PakReader/Parsers/Objects/FSHAHash.cs create mode 100644 FModel/PakReader/Parsers/Objects/FSectionEvaluationDataTree.cs create mode 100644 FModel/PakReader/Parsers/Objects/FSimpleCurveKey.cs create mode 100644 FModel/PakReader/Parsers/Objects/FSkeletalMeshAreaWeightedTriangleSampler.cs create mode 100644 FModel/PakReader/Parsers/Objects/FSkeletalMeshSamplingLODBuiltData.cs create mode 100644 FModel/PakReader/Parsers/Objects/FSmartName.cs create mode 100644 FModel/PakReader/Parsers/Objects/FSoftObjectPath.cs create mode 100644 FModel/PakReader/Parsers/Objects/FStreamedAudioChunk.cs create mode 100644 FModel/PakReader/Parsers/Objects/FStringTable.cs create mode 100644 FModel/PakReader/Parsers/Objects/FStripDataFlags.cs create mode 100644 FModel/PakReader/Parsers/Objects/FText.cs create mode 100644 FModel/PakReader/Parsers/Objects/FTextHistory.cs create mode 100644 FModel/PakReader/Parsers/Objects/FTextHistoryBase.cs create mode 100644 FModel/PakReader/Parsers/Objects/FTextHistoryDateTime.cs create mode 100644 FModel/PakReader/Parsers/Objects/FTextHistoryFormatNumber.cs create mode 100644 FModel/PakReader/Parsers/Objects/FTextHistoryNone.cs create mode 100644 FModel/PakReader/Parsers/Objects/FTextHistoryOrderedFormat.cs create mode 100644 FModel/PakReader/Parsers/Objects/FTextHistoryStringTableEntry.cs create mode 100644 FModel/PakReader/Parsers/Objects/FTextKey.cs create mode 100644 FModel/PakReader/Parsers/Objects/FTexture2DMipMap.cs create mode 100644 FModel/PakReader/Parsers/Objects/FTexturePlatformData.cs create mode 100644 FModel/PakReader/Parsers/Objects/FUniqueObjectGuid.cs create mode 100644 FModel/PakReader/Parsers/Objects/FVector.cs create mode 100644 FModel/PakReader/Parsers/Objects/FVector2D.cs create mode 100644 FModel/PakReader/Parsers/Objects/FVector4.cs create mode 100644 FModel/PakReader/Parsers/Objects/FVectorMaterialInput.cs create mode 100644 FModel/PakReader/Parsers/Objects/IUStruct.cs create mode 100644 FModel/PakReader/Parsers/Objects/TEvaluationTreeEntryContainer.cs create mode 100644 FModel/PakReader/Parsers/Objects/TMovieSceneEvaluationTree.cs create mode 100644 FModel/PakReader/Parsers/Objects/TRange.cs create mode 100644 FModel/PakReader/Parsers/Objects/TRangeBound.cs create mode 100644 FModel/PakReader/Parsers/Objects/UScriptStruct.cs create mode 100644 FModel/PakReader/Parsers/PackageReader.cs create mode 100644 FModel/PakReader/Parsers/PropertyAttribute.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/ArrayProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/BaseProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/BoolProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/ByteProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/DelegateProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/DoubleProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/FloatProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/Int16Property.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/Int64Property.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/Int8Property.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/IntProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/InterfaceProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/LazyObjectProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/MulticastDelegateProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/NameProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/ObjectProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/SetProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/StrProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/StructProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/TextProperty.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/UInt16Property.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/UInt32Property.cs create mode 100644 FModel/PakReader/Parsers/PropertyTagData/UInt64Property.cs create mode 100644 FModel/PakReader/Parsers/ReflectionHelper.cs rename FModel/{Methods/PakReader/Extensions.cs => PakReader/ReaderExtensions.cs} (55%) create mode 100644 FModel/PakReader/TextureDecoder.cs delete mode 100644 FModel/Program.cs delete mode 100644 FModel/Properties/AssemblyInfo.cs create mode 100644 FModel/Properties/Resources.ar.resx create mode 100644 FModel/Properties/Resources.de-DE.resx create mode 100644 FModel/Properties/Resources.fr-FR.resx create mode 100644 FModel/Properties/Resources.it-IT.resx create mode 100644 FModel/Properties/Resources.ja-JP.resx create mode 100644 FModel/Properties/Settings.cs delete mode 100644 FModel/Resources/BurbankBigCondensed-Black.ttf rename FModel/Resources/{colorpicker1.png => ColorPickerOne.png} (100%) rename FModel/Resources/{colorpicker2.png => ColorPickerTwo.png} (100%) delete mode 100644 FModel/Resources/EBCDIC-NoSpecialChar.tbl delete mode 100644 FModel/Resources/EBCDIC.tbl create mode 100644 FModel/Resources/EIconDesign_Default.png create mode 100644 FModel/Resources/EIconDesign_Flat.png create mode 100644 FModel/Resources/EIconDesign_Mini.png create mode 100644 FModel/Resources/EIconDesign_NoText.png rename FModel/{Methods/SyntaxHighlighter => Resources}/Ini.xshd (100%) rename FModel/{Methods/SyntaxHighlighter => Resources}/Json.xshd (69%) delete mode 100644 FModel/Resources/Logo-Icon.ico delete mode 100644 FModel/Resources/Logo.png delete mode 100644 FModel/Resources/TT-JTCじゃんけんU & TT-JTCじゃんけんUP.TTC create mode 100644 FModel/Resources/T_ClipSize_Weapon_Stats.png create mode 100644 FModel/Resources/T_DamagePerBullet_Weapon_Stats.png create mode 100644 FModel/Resources/T_Placeholder_Challenge_Image.png create mode 100644 FModel/Resources/T_Placeholder_Item_Image.png create mode 100644 FModel/Resources/T_ReloadTime_Weapon_Stats.png delete mode 100644 FModel/Resources/Template_AC_F.png delete mode 100644 FModel/Resources/Template_AC_N.png delete mode 100644 FModel/Resources/Template_Challenge.png delete mode 100644 FModel/Resources/Template_D_F.png delete mode 100644 FModel/Resources/Template_D_N.png delete mode 100644 FModel/Resources/Template_F_F.png delete mode 100644 FModel/Resources/Template_F_N.png delete mode 100644 FModel/Resources/Template_M_F.png delete mode 100644 FModel/Resources/Template_M_N.png create mode 100644 FModel/Resources/alert.ico create mode 100644 FModel/Resources/alpha-a-box.png create mode 100644 FModel/Resources/api-off.ico create mode 100644 FModel/Resources/api.ico create mode 100644 FModel/Resources/backup-restore.png create mode 100644 FModel/Resources/bug.png create mode 100644 FModel/Resources/cast-audio.png create mode 100644 FModel/Resources/challenge-theme-creator.png create mode 100644 FModel/Resources/check-circle.ico delete mode 100644 FModel/Resources/clipSize64.png delete mode 100644 FModel/Resources/close_file_16x.png create mode 100644 FModel/Resources/content-copy.png create mode 100644 FModel/Resources/content-save.png create mode 100644 FModel/Resources/delete-forever.png create mode 100644 FModel/Resources/discord.png delete mode 100644 FModel/Resources/dmg64.png create mode 100644 FModel/Resources/egl2.ico create mode 100644 FModel/Resources/file-export.png create mode 100644 FModel/Resources/file-image.ico create mode 100644 FModel/Resources/file-multiple.png create mode 100644 FModel/Resources/file-restore.png create mode 100644 FModel/Resources/file.png create mode 100644 FModel/Resources/fmodel.png create mode 100644 FModel/Resources/folder-download.png create mode 100644 FModel/Resources/folder-open.png delete mode 100644 FModel/Resources/folder_16x.png create mode 100644 FModel/Resources/fortnite.ico create mode 100644 FModel/Resources/gamepad-variant.png create mode 100644 FModel/Resources/github-circle.png create mode 100644 FModel/Resources/icon-creator.png create mode 100644 FModel/Resources/image-filter-black-white.png create mode 100644 FModel/Resources/image-move.png create mode 100644 FModel/Resources/image-plus.png create mode 100644 FModel/Resources/image-remove.png delete mode 100644 FModel/Resources/info_16x.png create mode 100644 FModel/Resources/information.png create mode 100644 FModel/Resources/key.png create mode 100644 FModel/Resources/lock-open-variant.ico create mode 100644 FModel/Resources/magnify.png create mode 100644 FModel/Resources/open-in-new.png delete mode 100644 FModel/Resources/open_16x.png create mode 100644 FModel/Resources/pause.png create mode 100644 FModel/Resources/paypal.png create mode 100644 FModel/Resources/pencil.png create mode 100644 FModel/Resources/play.png create mode 100644 FModel/Resources/playlist-plus.png create mode 100644 FModel/Resources/power.png create mode 100644 FModel/Resources/progress-download.png create mode 100644 FModel/Resources/refresh.png delete mode 100644 FModel/Resources/reload64.png delete mode 100644 FModel/Resources/save_16x.png create mode 100644 FModel/Resources/settings.png delete mode 100644 FModel/Resources/settings_16x.png create mode 100644 FModel/Resources/share-all.png create mode 100644 FModel/Resources/share.png create mode 100644 FModel/Resources/sign-direction-plus.png create mode 100644 FModel/Resources/sign-direction-remove.png create mode 100644 FModel/Resources/sign-direction.png create mode 100644 FModel/Resources/stop.png delete mode 100644 FModel/Resources/unknown512.png create mode 100644 FModel/Resources/valorant.live.ico create mode 100644 FModel/Resources/view-dashboard.png create mode 100644 FModel/Resources/volume-minus.png create mode 100644 FModel/Resources/volume-mute.png create mode 100644 FModel/Resources/volume-plus.png create mode 100644 FModel/Resources/wifi-strength-off.ico create mode 100644 FModel/Resources/zip-box.png rename FModel/{Themes => Theme}/LeftMarginMultiplierConverter.cs (80%) rename FModel/{Themes/Styles.xaml => Theme/Style.xaml} (94%) rename FModel/{Themes => Theme}/TreeViewItemExtensions.cs (89%) create mode 100644 FModel/Utils/Assets.cs create mode 100644 FModel/Utils/Commands.cs create mode 100644 FModel/Utils/EGL2.cs create mode 100644 FModel/Utils/Endpoints.cs create mode 100644 FModel/Utils/FConsole.cs rename FModel/{Methods/Utilities/FormsUtility.cs => Utils/FWindows.cs} (86%) create mode 100644 FModel/Utils/Folders.cs create mode 100644 FModel/Utils/HttpClientDownloadWithProgress.cs create mode 100644 FModel/Utils/Keys.cs create mode 100644 FModel/Utils/Localizations.cs create mode 100644 FModel/Utils/ObservableSortedList.cs create mode 100644 FModel/Utils/Paks.cs create mode 100644 FModel/Utils/Streams.cs create mode 100644 FModel/Utils/Strings.cs create mode 100644 FModel/Utils/Tasks.cs create mode 100644 FModel/Utils/Updater.cs create mode 100644 FModel/ViewModels/AvalonEdit/AvalonEditViewModel.cs create mode 100644 FModel/ViewModels/Buttons/ExtractStopViewModel.cs create mode 100644 FModel/ViewModels/ComboBox/ComboBoxViewModel.cs create mode 100644 FModel/ViewModels/DataGrid/DataGridViewModel.cs create mode 100644 FModel/ViewModels/ImageBox/ImageBoxViewModel.cs create mode 100644 FModel/ViewModels/ListBox/ListBoxViewModel.cs create mode 100644 FModel/ViewModels/MenuItem/BackupMenuItemViewModel.cs create mode 100644 FModel/ViewModels/MenuItem/CommandHandler.cs create mode 100644 FModel/ViewModels/MenuItem/GotoMenuItemViewModel.cs create mode 100644 FModel/ViewModels/MenuItem/MenuItems.cs create mode 100644 FModel/ViewModels/MenuItem/PakMenuItemViewModel.cs create mode 100644 FModel/ViewModels/Notifier/NotifierViewModel.cs create mode 100644 FModel/ViewModels/PropertyChangedBase.cs create mode 100644 FModel/ViewModels/SoundPlayer/InputFileViewModel.cs create mode 100644 FModel/ViewModels/StatusBar/StatusBarViewModel.cs create mode 100644 FModel/ViewModels/TabControl/AssetPropertiesViewModel.cs create mode 100644 FModel/ViewModels/TabControl/PakPropertiesViewModel.cs create mode 100644 FModel/ViewModels/Treeview/SortedTreeviewViewModel.cs rename FModel/{Methods/TreeViewModel => ViewModels/Treeview}/TreeViewItemBehavior.cs (66%) create mode 100644 FModel/ViewModels/Treeview/TreeviewViewModel.cs create mode 100644 FModel/Windows/AESManager/AESManager.xaml create mode 100644 FModel/Windows/AESManager/AESManager.xaml.cs rename FModel/{Forms/FModel_About.xaml => Windows/About/FAbout.xaml} (52%) create mode 100644 FModel/Windows/About/FAbout.xaml.cs create mode 100644 FModel/Windows/AvalonEditFindReplace/AvalonEditFindReplace.xaml rename FModel/{Methods/FindReplace/FindReplaceDialog.xaml.cs => Windows/AvalonEditFindReplace/AvalonEditFindReplace.xaml.cs} (71%) rename FModel/{Methods/FindReplace/FindReplace.cs => Windows/AvalonEditFindReplace/AvalonEditFindReplaceHelper.cs} (89%) rename FModel/{Forms/ColorPicker/Code => Windows/ColorPicker}/ColorPalette.cs (98%) create mode 100644 FModel/Windows/ColorPicker/ColorPickRow.xaml rename FModel/{Forms => Windows}/ColorPicker/ColorPickRow.xaml.cs (76%) create mode 100644 FModel/Windows/ColorPicker/ColorPickerControl.xaml rename FModel/{Forms => Windows}/ColorPicker/ColorPickerControl.xaml.cs (95%) rename FModel/{Forms/ColorPicker/Code => Windows/ColorPicker}/ColorPickerDialogOptions.cs (52%) rename FModel/{Forms => Windows}/ColorPicker/ColorPickerSettings.cs (92%) create mode 100644 FModel/Windows/ColorPicker/ColorPickerSwatch.xaml rename FModel/{Forms => Windows}/ColorPicker/ColorPickerSwatch.xaml.cs (79%) create mode 100644 FModel/Windows/ColorPicker/ColorPickerWindow.xaml rename FModel/{Forms => Windows}/ColorPicker/ColorPickerWindow.xaml.cs (83%) create mode 100644 FModel/Windows/ColorPicker/ColorSwatchItem.cs rename FModel/{Forms => Windows}/ColorPicker/SliderRow.xaml (65%) rename FModel/{Forms => Windows}/ColorPicker/SliderRow.xaml.cs (87%) rename FModel/{Forms/ColorPicker/Code => Windows/ColorPicker}/Util.cs (89%) create mode 100644 FModel/Windows/CustomNotifier/CustomNotifier.xaml create mode 100644 FModel/Windows/CustomNotifier/CustomNotifier.xaml.cs create mode 100644 FModel/Windows/CustomNotifier/CustomNotifierHelper.cs rename FModel/{Forms/FModel_CustomMB.xaml => Windows/DarkMessageBox/DarkMessageBox.xaml} (79%) rename FModel/{Forms/FModel_CustomMB.xaml.cs => Windows/DarkMessageBox/DarkMessageBox.xaml.cs} (79%) rename FModel/{Methods/MessageBox/DarkMessageBox.cs => Windows/DarkMessageBox/DarkMessageBoxHelper.cs} (80%) create mode 100644 FModel/Windows/DependencyObjects.cs create mode 100644 FModel/Windows/ImagesMerger/ImagesMerger.xaml create mode 100644 FModel/Windows/ImagesMerger/ImagesMerger.xaml.cs create mode 100644 FModel/Windows/Launcher/FLauncher.xaml create mode 100644 FModel/Windows/Launcher/FLauncher.xaml.cs create mode 100644 FModel/Windows/Search/Search.xaml create mode 100644 FModel/Windows/Search/Search.xaml.cs create mode 100644 FModel/Windows/Settings/ChallengeBundlesCreator.xaml create mode 100644 FModel/Windows/Settings/ChallengeBundlesCreator.xaml.cs create mode 100644 FModel/Windows/Settings/General.xaml create mode 100644 FModel/Windows/Settings/General.xaml.cs create mode 100644 FModel/Windows/Settings/IconCreator.xaml create mode 100644 FModel/Windows/Settings/IconCreator.xaml.cs create mode 100644 FModel/Windows/SoundPlayer/AudioPlayer.xaml create mode 100644 FModel/Windows/SoundPlayer/AudioPlayer.xaml.cs create mode 100644 FModel/Windows/SoundPlayer/ISample.cs create mode 100644 FModel/Windows/SoundPlayer/NVorbisSource.cs create mode 100644 FModel/Windows/SoundPlayer/UserControls/SpectrumAnalyzer.xaml create mode 100644 FModel/Windows/SoundPlayer/UserControls/SpectrumAnalyzer.xaml.cs create mode 100644 FModel/Windows/SoundPlayer/UserControls/Timeclock.xaml create mode 100644 FModel/Windows/SoundPlayer/UserControls/Timeclock.xaml.cs create mode 100644 FModel/Windows/SoundPlayer/UserControls/Timeline.xaml create mode 100644 FModel/Windows/SoundPlayer/UserControls/Timeline.xaml.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/BasicSpectrumProvider.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/Device.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/EClockType.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/EDeviceType.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/EScalingStrategy.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/ESourceEventType.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/ESourceProperty.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/ISource.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/ISpectrumProvider.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/OutputSource.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/SourceEventArgs.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/SourcePropertyChangedEventArgs.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/SpectrumAnalyzer.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/Timeclock.cs create mode 100644 FModel/Windows/SoundPlayer/Visualization/Timeline.cs create mode 100644 FModel/Windows/UserInput/GoToUserInput.xaml create mode 100644 FModel/Windows/UserInput/GoToUserInput.xaml.cs delete mode 100644 FModel/packages.config delete mode 100644 Images/FModel.png delete mode 100644 Images/FModel_Demo.gif delete mode 100644 Images/Logo.png diff --git a/FModel.sln b/FModel.sln index fb6bcab7..840c08ec 100644 --- a/FModel.sln +++ b/FModel.sln @@ -1,25 +1,29 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.452 +VisualStudioVersion = 16.0.29806.167 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FModel", "FModel\FModel.csproj", "{8AAB27BD-18D7-4164-8BBC-AB534D55D30F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FModel", "FModel\FModel.csproj", "{A42F8737-D056-4FA5-BEB5-AA96E1639F8A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8AAB27BD-18D7-4164-8BBC-AB534D55D30F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8AAB27BD-18D7-4164-8BBC-AB534D55D30F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8AAB27BD-18D7-4164-8BBC-AB534D55D30F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8AAB27BD-18D7-4164-8BBC-AB534D55D30F}.Release|Any CPU.Build.0 = Release|Any CPU + {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Debug|Any CPU.ActiveCfg = Debug|x64 + {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Debug|x64.ActiveCfg = Debug|x64 + {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Debug|x64.Build.0 = Debug|x64 + {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Release|Any CPU.ActiveCfg = Release|x64 + {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Release|x64.ActiveCfg = Release|x64 + {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {42CA5618-EB78-4DDF-95A4-BD589CC52791} + SolutionGuid = {FE6EA91D-BBB8-4FBC-875C-25AD92EDB519} EndGlobalSection EndGlobal diff --git a/FModel/App.config b/FModel/App.config deleted file mode 100644 index c897b019..00000000 --- a/FModel/App.config +++ /dev/null @@ -1,213 +0,0 @@ - - - - -
- - - - - - - - - - - - - - - - - - Default - - - English - - - False - - - False - - - - - - 0 - - - 0 - - - 3 - - - 3 - - - {BundleName} - {Date} - - - False - - - - - - 0 - - - False - - - True - - - False - - - True - - - 21:32:43 - - - 29:161:242 - - - True - - - True - - - True - - - False - - - False - - - False - - - { - "[BR] Cosmetics": { - "Path": "/FortniteGame/Content/Athena/Items/Cosmetics/", - "isChecked": "True" - }, - "[BR] Cosmetics Variants": { - "Path": "/FortniteGame/Content/Athena/Items/CosmeticVariantTokens/", - "isChecked": "True" - }, - "[BR] Banners": { - "Path": "/FortniteGame/Content/Athena/Items/BannerToken/", - "isChecked": "True" - }, - "[BR] Challenges": { - "Path": "/FortniteGame/Content/Athena/Items/ChallengeBundles/", - "isChecked": "True" - }, - "[BR] Consumables": { - "Path": "/FortniteGame/Content/Athena/Items/Consumables/", - "isChecked": "False" - }, - "[BR] Traps": { - "Path": "/FortniteGame/Content/Athena/Items/Traps/", - "isChecked": "False" - }, - "[BR] Weapons": { - "Path": "/FortniteGame/Content/Athena/Items/Weapons/", - "isChecked": "True" - }, - "[BR] 2D Assets": { - "Path": "/FortniteGame/Content/2dAssets/", - "isChecked": "True" - }, - "[BR] Featured Images": { - "Path": "/FortniteGame/Content/UI/Foundation/Textures/BattleRoyale/FeaturedItems/", - "isChecked": "False" - }, - "[STW] Heroes": { - "Path": "/FortniteGame/Content/Heroes/", - "isChecked": "False" - }, - "[STW] Defenders": { - "Path": "/FortniteGame/Content/Items/Defenders/", - "isChecked": "False" - }, - "[STW] Schematics": { - "Path": "/FortniteGame/Content/Items/Schematics/", - "isChecked": "False" - }, - "[STW] Traps": { - "Path": "/FortniteGame/Content/Items/Traps/", - "isChecked": "False" - }, - "[STW] Weapons": { - "Path": "/FortniteGame/Content/Items/Weapons/", - "isChecked": "False" - }, - "[STW] Ingredients": { - "Path": "/FortniteGame/Content/Items/Ingredients/", - "isChecked": "False" - }, - "[STW] Persistent Resources": { - "Path": "/FortniteGame/Content/Items/PersistentResources/", - "isChecked": "False" - }, - "[STW] CardPacks": { - "Path": "/FortniteGame/Content/Items/CardPacks/", - "isChecked": "False" - }, - "Tokens": { - "Path": "/FortniteGame/Content/Items/Tokens/", - "isChecked": "False" - }, - "Icons": { - "Path": "/FortniteGame/Content/UI/Foundation/Textures/Icons/", - "isChecked": "False" - }, - "Additional Banners": { - "Path": "/FortniteGame/Content/UI/Foundation/Textures/Banner/", - "isChecked": "False" - }, - "Additional Loading Screens": { - "Path": "/FortniteGame/Content/UI/Foundation/Textures/LoadingScreens/", - "isChecked": "False" - } -} - - - - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FModel/App.xaml b/FModel/App.xaml index f780ac10..a43c45c3 100644 --- a/FModel/App.xaml +++ b/FModel/App.xaml @@ -1,17 +1,13 @@  - - - - + + diff --git a/FModel/App.xaml.cs b/FModel/App.xaml.cs index b13666a4..81295a88 100644 --- a/FModel/App.xaml.cs +++ b/FModel/App.xaml.cs @@ -1,20 +1,80 @@ -using FModel.Methods.MessageBox; -using FModel.Methods.Utilities; +using FModel.Discord; +using FModel.Logger; +using FModel.Utils; +using FModel.ViewModels.StatusBar; +using FModel.Windows.DarkMessageBox; +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; using System.Windows; +using System.Windows.Threading; namespace FModel { /// - /// Logique d'interaction pour App.xaml + /// Interaction logic for App.xaml /// public partial class App : Application { - void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) + internal static Stopwatch StartTimer { get; private set; } + static bool framerateSet = false; + + protected override void OnStartup(StartupEventArgs e) { - string errorMessage = string.Format("An unhandled exception occurred: {0}", e.Exception.Message); + StartTimer = Stopwatch.StartNew(); + + //Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US"); + + DebugHelper.Init(LogsFilePath); + DebugHelper.WriteLine("{0} {1}", "[FModel]", "––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––"); + DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Version]", Assembly.GetExecutingAssembly().GetName().Version.ToString()); + DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Build]", Globals.Build); + DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[OS]", Logger.Logger.GetOperatingSystemProductName(true)); + DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Runtime]", RuntimeInformation.FrameworkDescription); + DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Culture]", Thread.CurrentThread.CurrentUICulture); + + StatusBarVm.statusBarViewModel.Set(FModel.Properties.Resources.Initializing, FModel.Properties.Resources.Loading); + DiscordIntegration.StartClient(); + + base.OnStartup(e); + } + + public static string LogsFilePath + { + get + { + string filename = string.Format("FModel-Log-{0:yyyy-MM-dd}.txt", DateTime.Now); + + // Copy user settings from previous application version if necessary + if (FModel.Properties.Settings.Default.UpdateSettings) + FModel.Properties.Settings.Default.Upgrade(); + + Folders.LoadFolders(); + + return Path.Combine(FModel.Properties.Settings.Default.OutputPath + "\\Logs", filename); + } + } + + private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) + { + string errorMessage = string.Format(FModel.Properties.Resources.UnhandledExceptionOccured, e.Exception.Message); DebugHelper.WriteException(e.Exception, "thrown in App.xaml.cs by OnDispatcherUnhandledException"); - DarkMessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error); + DarkMessageBoxHelper.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error); e.Handled = true; } + + internal static void SetFramerate() + { + if (!framerateSet) + { + System.Windows.Media.Animation.Timeline.DesiredFrameRateProperty.OverrideMetadata( + typeof(System.Windows.Media.Animation.Timeline), + new FrameworkPropertyMetadata { DefaultValue = 10 }); + framerateSet = true; + } + } } } diff --git a/FModel/AssemblyInfo.cs b/FModel/AssemblyInfo.cs new file mode 100644 index 00000000..8b5504ec --- /dev/null +++ b/FModel/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/FModel/Commands/FModel_Commands.cs b/FModel/Commands/FModel_Commands.cs deleted file mode 100644 index 17503699..00000000 --- a/FModel/Commands/FModel_Commands.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Windows.Input; - -namespace FModel.Commands -{ - static class FModel_Commands - { - public static readonly RoutedUICommand OpenSettings = new RoutedUICommand("Open Settings Window", "OpenSettings", typeof(MainWindow)); - public static readonly RoutedUICommand OpenSearch = new RoutedUICommand("Open Search Window", "OpenSearch", typeof(MainWindow)); - public static readonly RoutedUICommand OpenOutput = new RoutedUICommand("Open Output Folder", "OpenOutput", typeof(MainWindow)); - public static readonly RoutedUICommand MergeImages = new RoutedUICommand("Merge Images", "MergeImages", typeof(MainWindow)); - } -} diff --git a/FModel/Creator/BaseBundle.cs b/FModel/Creator/BaseBundle.cs new file mode 100644 index 00000000..648f278e --- /dev/null +++ b/FModel/Creator/BaseBundle.cs @@ -0,0 +1,102 @@ +using FModel.Creator.Bundles; +using FModel.Creator.Texts; +using PakReader.Pak; +using PakReader.Parsers.Class; +using PakReader.Parsers.PropertyTagData; +using System.Collections.Generic; + +namespace FModel.Creator +{ + public class BaseBundle + { + public Header DisplayStyle; + public string DisplayName; + public string FolderName; + public string Watermark; + public int Width = 1024; + public int HeaderHeight = 261; // height is the header basically + public int AdditionalSize = 50; // must be increased depending on the number of quests to draw + public bool IsDisplayNameShifted; + public List Quests; + public List CompletionRewards; + + public BaseBundle() + { + DisplayStyle = new Header(); + DisplayName = ""; + FolderName = ""; + Watermark = Properties.Settings.Default.ChallengeBannerWatermark; + Quests = new List(); + CompletionRewards = new List(); + } + + /// + /// used for the settings + /// + public BaseBundle(string watermark) : this() + { + DisplayName = "{DisplayName}"; + FolderName = "{FolderName}"; + Watermark = watermark; + Quests.Add(new Quest { Description = "", Count = 999, Reward = null }); + AdditionalSize += 89; + } + + public BaseBundle(IUExport export, string assetFolder) : this() + { + if (export.GetExport("DisplayStyle") is StructProperty displayStyle) + DisplayStyle = new Header(displayStyle, assetFolder); + if (export.GetExport("DisplayName") is TextProperty displayName) + DisplayName = Text.GetTextPropertyBase(displayName); + + if (export.GetExport("CareerQuestBitShifts") is ArrayProperty careerQuestBitShifts) + { + foreach (SoftObjectProperty questPath in careerQuestBitShifts.Value) + { + PakPackage p = Utils.GetPropertyPakPackage(questPath.Value.AssetPathName.String); + if (p.HasExport() && !p.Equals(default)) + { + var obj = p.GetExport(); + if (obj != null) + Quests.Add(new Quest(obj)); + } + } + } + + if (export.GetExport("BundleCompletionRewards") is ArrayProperty bundleCompletionRewards) + { + foreach (StructProperty completionReward in bundleCompletionRewards.Value) + { + if (completionReward.Value is UObject reward && + reward.TryGetValue("CompletionCount", out var c) && c is IntProperty completionCount && + reward.TryGetValue("Rewards", out var r) && r is ArrayProperty rewards) + { + foreach (StructProperty rew in rewards.Value) + { + if (rew.Value is UObject re && + re.TryGetValue("Quantity", out var q) && q is IntProperty quantity && + re.TryGetValue("TemplateId", out var t) && t is StrProperty templateId && + re.TryGetValue("ItemDefinition", out var d) && d is SoftObjectProperty itemDefinition) + { + if (!itemDefinition.Value.AssetPathName.IsNone && + !itemDefinition.Value.AssetPathName.String.StartsWith("/Game/Items/Tokens/") && + !itemDefinition.Value.AssetPathName.String.StartsWith("/Game/Athena/Items/Quests")) + { + CompletionRewards.Add(new CompletionReward(completionCount, quantity, itemDefinition)); + } + else if (!string.IsNullOrEmpty(templateId.Value)) + { + CompletionRewards.Add(new CompletionReward(completionCount, quantity, templateId.Value)); + } + } + } + } + } + } + + FolderName = assetFolder; + AdditionalSize += 95 * Quests.Count; + if (CompletionRewards.Count > 0) AdditionalSize += 50 + (95 * CompletionRewards.Count); + } + } +} diff --git a/FModel/Creator/BaseIcon.cs b/FModel/Creator/BaseIcon.cs new file mode 100644 index 00000000..5c5a6bfb --- /dev/null +++ b/FModel/Creator/BaseIcon.cs @@ -0,0 +1,126 @@ +using FModel.Creator.Icons; +using FModel.Creator.Rarities; +using FModel.Creator.Stats; +using FModel.Creator.Texts; +using FModel.Utils; +using PakReader.Parsers.Class; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; +using System; +using System.Collections.Generic; +using System.Windows; + +namespace FModel.Creator +{ + public class BaseIcon + { + public SKBitmap FallbackImage; + public SKBitmap IconImage; + public SKBitmap RarityBackgroundImage; + public SKBitmap[] UserFacingFlags; + public SKColor[] RarityBackgroundColors; + public SKColor[] RarityBorderColor; + public string DisplayName; + public string Description; + public string ShortDescription; + public string CosmeticSource; + public int Size = 512; // keep it 512 (or a multiple of 512) if you don't want blurry icons + public int AdditionalSize = 0; // must be increased if there are weapon stats, hero abilities or more to draw/show + public int Margin = 2; + public List Stats; + + public BaseIcon() + { + FallbackImage = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T_Placeholder_Item_Image.png")).Stream); + IconImage = FallbackImage; + RarityBackgroundImage = null; + UserFacingFlags = null; + RarityBackgroundColors = new SKColor[2] { SKColor.Parse("5EBC36"), SKColor.Parse("305C15") }; + RarityBorderColor = new SKColor[2] { SKColor.Parse("74EF52"), SKColor.Parse("74EF52") }; + DisplayName = ""; + Description = ""; + ShortDescription = ""; + CosmeticSource = ""; + Stats = new List(); + } + + /// + /// used to get low res icons ONLY + /// + /// + /// + public BaseIcon(IUExport export, string assetName) : this() + { + if (export.GetExport("HeroDefinition", "WeaponDefinition") is ObjectProperty itemDef) + LargeSmallImage.GetPreviewImage(this, itemDef, assetName, false); + else if (export.GetExport("SmallPreviewImage", "SmallImage") is SoftObjectProperty previewImage) + LargeSmallImage.GetPreviewImage(this, previewImage); + } + + /// + /// Order: + /// 1. Rarity + /// 2. Image + /// 3. Text + /// 1. DisplayName + /// 2. Description + /// 3. Misc + /// 4. GameplayTags + /// 1. order doesn't matter + /// 2. the importance here is to get the description before gameplay tags + /// + public BaseIcon(IUExport export, string exportType, string assetName) : this() + { + // rarity + if (export.GetExport("Series") is ObjectProperty series) + Serie.GetRarity(this, series); + else if (Properties.Settings.Default.UseGameColors) // override default green + Rarity.GetInGameRarity(this, export.GetExport("Rarity")); // uncommon will be triggered by Rarity being null + else if (export.GetExport("Rarity") is EnumProperty rarity) + Rarity.GetHardCodedRarity(this, rarity); + + // image + if (Properties.Settings.Default.UseItemShopIcon && + DisplayAssetImage.GetDisplayAssetImage(this, export.GetExport("DisplayAssetPath"), assetName)) + { } // ^^^^ will return false if image not found, if so, we try to get the normal icon + else if (export.GetExport("HeroDefinition", "WeaponDefinition") is ObjectProperty itemDef) + LargeSmallImage.GetPreviewImage(this, itemDef, assetName); + else if (export.GetExport("LargePreviewImage", "SmallPreviewImage", "ItemDisplayAsset") is SoftObjectProperty previewImage) + LargeSmallImage.GetPreviewImage(this, previewImage); + else if (export.GetExport("IconBrush") is StructProperty iconBrush) // abilities + LargeSmallImage.GetPreviewImage(this, iconBrush); + + // text + if (export.GetExport("DisplayName", "DefaultHeaderText", "UIDisplayName") is TextProperty displayName) + DisplayName = Text.GetTextPropertyBase(displayName); + if (export.GetExport("Description", "DefaultBodyText") is TextProperty description) + Description = Text.GetTextPropertyBase(description); + else if (export.GetExport("Description") is ArrayProperty arrayDescription) // abilities + Description = Text.GetTextPropertyBase(arrayDescription); + if (export.GetExport("MaxStackSize") is StructProperty maxStackSize) + ShortDescription = Text.GetMaxStackSize(maxStackSize); + else if (export.GetExport("ShortDescription") is TextProperty shortDescription) + ShortDescription = Text.GetTextPropertyBase(shortDescription); + else if (exportType.Equals("AthenaItemWrapDefinition")) // if no ShortDescription it's most likely a wrap + ShortDescription = Localizations.GetLocalization("Fort.Cosmetics", "ItemWrapShortDescription", "Wrap"); + + // gameplaytags + if (export.GetExport("GameplayTags") is StructProperty gameplayTags) + GameplayTag.GetGameplayTags(this, gameplayTags, exportType); + else if (export.GetExport("cosmetic_item") is ObjectProperty cosmeticItem) // variants + CosmeticSource = cosmeticItem.Value.Resource.ObjectName.String; + + if (export.GetExport("AmmoData") is SoftObjectProperty ammoData) + Statistics.GetAmmoData(this, ammoData); + if (export.GetExport("WeaponStatHandle") is StructProperty weaponStatHandle) + Statistics.GetWeaponStats(this, weaponStatHandle); + if (export.GetExport("HeroGameplayDefinition") is ObjectProperty heroGameplayDefinition) + Statistics.GetHeroStats(this, heroGameplayDefinition); + + /* Please do not add Schematics support because it takes way too much memory */ + /* Thank the STW Dev Team for using a 5,69Mb file to get... Oh nvm, they all left */ + + AdditionalSize = 48 * Stats.Count; + } + } +} diff --git a/FModel/Creator/BaseUserOption.cs b/FModel/Creator/BaseUserOption.cs new file mode 100644 index 00000000..80eab7bc --- /dev/null +++ b/FModel/Creator/BaseUserOption.cs @@ -0,0 +1,166 @@ +using FModel.Creator.Texts; +using PakReader.Parsers.Class; +using PakReader.Parsers.Objects; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; +using System.Collections.Generic; + +namespace FModel.Creator +{ + public class Options + { + public string Option; + public SKColor Color = SKColor.Parse("55C5FC").WithAlpha(150); + } + + public class BaseUserOption + { + private readonly SKPaint descriptionPaint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Typeface = Text.TypeFaces.DisplayNameTypeface, + TextSize = 25, + Color = SKColor.Parse("88DBFF"), + }; + + public string OptionDisplayName; + public string OptionDescription; + public List OptionValues = new List(); + public int Width = 512; + public int Height = 128; + public int Margin = 32; + + public BaseUserOption(IUExport export) + { + if (export.GetExport("OptionDisplayName") is TextProperty optionDisplayName) + OptionDisplayName = Text.GetTextPropertyBase(optionDisplayName).ToUpperInvariant(); + if (export.GetExport("OptionDescription") is TextProperty optionDescription) + { + OptionDescription = Text.GetTextPropertyBase(optionDescription); + Height += (int)descriptionPaint.TextSize * Helper.SplitLines(OptionDescription, descriptionPaint, Width - Margin).Length; + Height += (int)descriptionPaint.TextSize; + } + + if (export.GetExport("OptionValues") is ArrayProperty optionValues) + { + OptionValues = new List(optionValues.Value.Length); + for (int i = 0; i < OptionValues.Capacity; i++) + { + if (optionValues.Value[i] is StructProperty s && s.Value is UObject option) + { + if (option.TryGetValue("DisplayName", out var v1) && v1 is TextProperty displayName) + { + var opt = new Options { Option = Text.GetTextPropertyBase(displayName).ToUpperInvariant() }; + if (option.TryGetValue("Value", out var v) && v is StructProperty value && value.Value is FLinearColor color) + opt.Color = SKColor.Parse(color.Hex).WithAlpha(150); + OptionValues.Add(opt); + } + else if (option.TryGetValue("PrimaryAssetName", out var v2) && v2 is NameProperty primaryAssetName) + OptionValues.Add(new Options { Option = primaryAssetName.Value.String }); + } + } + } + + if (export.GetExport("OptionOnText") is TextProperty optionOnText) + OptionValues.Add(new Options { Option = Text.GetTextPropertyBase(optionOnText).ToUpperInvariant() }); + if (export.GetExport("OptionOffText") is TextProperty optionOffText) + OptionValues.Add(new Options { Option = Text.GetTextPropertyBase(optionOffText).ToUpperInvariant() }); + + if (export.GetExport("Min", "DefaultValue") is IntProperty iMin && + export.GetExport("Max") is IntProperty iMax) + { + int increment = iMin.Value; + if (export.GetExport("IncrementValue") is IntProperty incrementValue) + increment = incrementValue.Value; + + for (int i = iMin.Value; i <= iMax.Value; i += increment) + { + OptionValues.Add(new Options { Option = i.ToString() }); + } + } + + if (export.GetExport("Min") is FloatProperty fMin && + export.GetExport("Max") is FloatProperty fMax) + { + float increment = fMin.Value; + if (export.GetExport("IncrementValue") is FloatProperty incrementValue) + increment = incrementValue.Value; + + for (float i = fMin.Value; i <= fMax.Value; i += increment) + { + OptionValues.Add(new Options { Option = i.ToString() }); + } + } + + Height += Margin; + Height += 35 * OptionValues.Count; + } + + public void Draw(SKCanvas c) + { + c.DrawRect(new SKRect(0, 0, Width, Height), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Shader = SKShader.CreateLinearGradient( + new SKPoint(Width / 2, Height), + new SKPoint(Width, Height / 4), + new SKColor[2] { SKColor.Parse("01369C"), SKColor.Parse("1273C8") }, + SKShaderTileMode.Clamp) + }); + + int textSize = 45; + SKPaint namePaint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Typeface = Text.TypeFaces.DisplayNameTypeface, + TextSize = textSize, + Color = SKColors.White, + TextAlign = SKTextAlign.Left + }; + + // resize if too long + while (namePaint.MeasureText(OptionDisplayName) > (Width - (Margin * 2))) + { + namePaint.TextSize = textSize -= 2; + } + int y = Margin + textSize; + c.DrawText(OptionDisplayName, Margin, y, namePaint); + y += (int)descriptionPaint.TextSize + (Margin / 2); + + // wrap if too long + Helper.DrawMultilineText(c, OptionDescription, Width, Margin, ETextSide.Left, + new SKRect(Margin, y, Width - Margin, 256), descriptionPaint, out int top); + + int height = 30; + int space = 5; + foreach (Options option in OptionValues) + { + c.DrawRect(new SKRect(Margin, top, Width - Margin, top + height), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = option.Color + }); + + int ts = 20; + c.DrawText(option.Option, Margin + (space * 2), top + (ts * 1.1f), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Typeface = Text.TypeFaces.DisplayNameTypeface, + TextSize = ts, + Color = SKColor.Parse("EEFFFF"), + TextAlign = SKTextAlign.Left + }); + + top += height + space; + } + } + } +} diff --git a/FModel/Creator/Bundles/CompletionReward.cs b/FModel/Creator/Bundles/CompletionReward.cs new file mode 100644 index 00000000..3f92b714 --- /dev/null +++ b/FModel/Creator/Bundles/CompletionReward.cs @@ -0,0 +1,60 @@ +using FModel.Utils; +using PakReader.Parsers.PropertyTagData; +using System; + +namespace FModel.Creator.Bundles +{ + public class CompletionReward + { + private const string _TRIGGER1 = ""; + private const string _TRIGGER2 = ""; + public string CompletionText; + public Reward Reward; + + public CompletionReward(IntProperty completionCount) + { + string all = Localizations.GetLocalization("AthenaChallengeDetailsEntry", "CompletionRewardFormat_All", "Complete all {0} challenges to earn the reward item"); + string allFormated = ReformatString(all, completionCount.Value.ToString(), true); + string any = Localizations.GetLocalization("AthenaChallengeDetailsEntry", "CompletionRewardFormat", "Complete any {0} challenges to earn the reward item"); + string anyFormated = ReformatString(any, completionCount.Value.ToString(), false); + CompletionText = completionCount.Value >= 0 ? anyFormated : allFormated; + + Reward = null; + } + + public CompletionReward(IntProperty completionCount, IntProperty quantity, SoftObjectProperty itemDefinition) : this(completionCount) + { + Reward = new Reward(quantity, itemDefinition); + } + + public CompletionReward(IntProperty completionCount, IntProperty quantity, string reward) : this(completionCount) + { + Reward = new Reward(quantity, reward); + } + + private string ReformatString(string s, string completionCount, bool isAll) + { + s = s.Replace("({0})", "{0}").Replace("{QuestNumber}", "{0}"); + + int index = s.IndexOf("|plural(", StringComparison.CurrentCultureIgnoreCase); + if (index > -1) + { + int i = s.Substring(index).IndexOf(')', StringComparison.CurrentCultureIgnoreCase); + s = s.Replace(s.Substring(index, i + 1), string.Empty).Replace("{0} {0}", "{0}"); + } + + int index1 = s.IndexOf(_TRIGGER1, StringComparison.CurrentCultureIgnoreCase); + if (index1 < 0) index1 = 0; + string partOne = s.Substring(0, index1); + + string partTemp = s.Substring(index1 + _TRIGGER1.Length); + int index2 = partTemp.IndexOf(_TRIGGER2, StringComparison.CurrentCultureIgnoreCase); + if (index2 < 0) index2 = 0; + string partUpper = partTemp.Substring(0, index2).ToUpper().Replace("{0}", isAll ? string.Empty : completionCount); + + string partTwo = partTemp.Substring(index2 + _TRIGGER2.Length); + + return string.Format("{0}{1}{2}", partOne, partUpper, partTwo).Replace(" ", " ").Replace(" ,", ","); + } + } +} diff --git a/FModel/Creator/Bundles/Header.cs b/FModel/Creator/Bundles/Header.cs new file mode 100644 index 00000000..66efc995 --- /dev/null +++ b/FModel/Creator/Bundles/Header.cs @@ -0,0 +1,106 @@ +using PakReader.Parsers.Class; +using PakReader.Parsers.Objects; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; +using System; +using System.IO; + +namespace FModel.Creator.Bundles +{ + public class Header + { + public SKColor PrimaryColor; + public SKColor SecondaryColor; + public SKColor AccentColor; + public SKBitmap DisplayImage; // 256x256 + public SKBitmap CustomBackground; // 1024x256 + + private readonly Random _random = new Random(Environment.TickCount); + private readonly string[] _randomColors = new string[255] + { + "F44336", "FFEBEE", "FFCDD2", "EF9A9A", "E57373", "EF5350", "E53935", "D32F2F", "C62828", "B71C1C", + "FF8A80", "FF5252", "FF1744", "D50000", "FCE4EC", "F8BBD0", "F48FB1", "F06292", "EC407A", "E91E63", + "D81B60", "C2185B", "AD1457", "880E4F", "FF80AB", "FF4081", "F50057", "C51162", "F3E5F5", "E1BEE7", + "CE93D8", "BA68C8", "AB47BC", "9C27B0", "8E24AA", "7B1FA2", "6A1B9A", "4A148C", "EA80FC", "E040FB", + "D500F9", "AA00FF", "EDE7F6", "D1C4E9", "B39DDB", "9575CD", "7E57C2", "673AB7", "5E35B1", "512DA8", + "4527A0", "311B92", "B388FF", "7C4DFF", "651FFF", "6200EA", "E8EAF6", "C5CAE9", "9FA8DA", "7986CB", + "5C6BC0", "3F51B5", "3949AB", "303F9F", "283593", "1A237E", "8C9EFF", "536DFE", "3D5AFE", "304FFE", + "E3F2FD", "BBDEFB", "90CAF9", "64B5F6", "42A5F5", "2196F3", "1E88E5", "1976D2", "1565C0", "0D47A1", + "82B1FF", "448AFF", "2979FF", "2962FF", "E1F5FE", "B3E5FC", "81D4FA", "4FC3F7", "29B6F6", "03A9F4", + "039BE5", "0288D1", "0277BD", "01579B", "80D8FF", "40C4FF", "00B0FF", "0091EA", "E0F7FA", "B2EBF2", + "80DEEA", "4DD0E1", "26C6DA", "00BCD4", "00ACC1", "0097A7", "00838F", "006064", "84FFFF", "18FFFF", + "00E5FF", "00B8D4", "E0F2F1", "B2DFDB", "80CBC4", "4DB6AC", "26A69A", "009688", "00897B", "00796B", + "00695C", "004D40", "A7FFEB", "64FFDA", "1DE9B6", "00BFA5", "E8F5E9", "C8E6C9", "A5D6A7", "81C784", + "66BB6A", "4CAF50", "43A047", "388E3C", "2E7D32", "1B5E20", "B9F6CA", "69F0AE", "00E676", "00C853", + "F1F8E9", "DCEDC8", "C5E1A5", "AED581", "9CCC65", "8BC34A", "7CB342", "689F38", "558B2F", "33691E", + "CCFF90", "B2FF59", "76FF03", "64DD17", "F9FBE7", "F0F4C3", "E6EE9C", "DCE775", "D4E157", "CDDC39", + "C0CA33", "AFB42B", "9E9D24", "827717", "F4FF81", "EEFF41", "C6FF00", "AEEA00", "FFFDE7", "FFF9C4", + "FFF59D", "FFF176", "FFEE58", "FFEB3B", "FDD835", "FBC02D", "F9A825", "F57F17", "FFFF8D", "FFFF00", + "FFEA00", "FFD600", "FFF8E1", "FFECB3", "FFE082", "FFD54F", "FFCA28", "FFC107", "FFB300", "FFA000", + "FF8F00", "FF6F00", "FFE57F", "FFD740", "FFC400", "FFAB00", "FFF3E0", "FFE0B2", "FFCC80", "FFB74D", + "FFA726", "FF9800", "FB8C00", "F57C00", "EF6C00", "E65100", "FFD180", "FFAB40", "FF9100", "FF6D00", + "FBE9E7", "FFCCBC", "FFAB91", "FF8A65", "FF7043", "FF5722", "F4511E", "E64A19", "D84315", "BF360C", + "FF9E80", "FF6E40", "FF3D00", "DD2C00", "EFEBE9", "D7CCC8", "BCAAA4", "A1887F", "8D6E63", "795548", + "6D4C41", "5D4037", "4E342E", "3E2723", "FAFAFA", "F5F5F5", "EEEEEE", "E0E0E0", "BDBDBD", "9E9E9E", + "757575", "616161", "424242", "212121", "ECEFF1", "CFD8DC", "B0BEC5", "90A4AE", "78909C", "607D8B", + "546E7A", "455A64", "37474F", "263238", "000000", + }; + + public Header() + { + if (Properties.Settings.Default.UseChallengeBanner) + { + SKColor mainColor = SKColor.Parse(Properties.Settings.Default.ChallengeBannerPrimaryColor); + mainColor.ToHsl(out float h, out float s, out float l); + float i = l + 20.0F > 100.0F ? 100.0F - l : 20.0F; + + PrimaryColor = mainColor; + SecondaryColor = SKColor.Parse(Properties.Settings.Default.ChallengeBannerSecondaryColor); + AccentColor = SKColor.FromHsl(h += i, s, l); + DisplayImage = null; + if (!string.IsNullOrEmpty(Properties.Settings.Default.ChallengeBannerPath)) + CustomBackground = SKBitmap.Decode(new FileInfo(Properties.Settings.Default.ChallengeBannerPath).Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); + else CustomBackground = null; + } + else + { + SKColor mainColor = SKColor.Parse(_randomColors[_random.Next(0, 255)]); + mainColor.ToHsl(out float h, out float s, out float l); + while (l > 75 || l < 10) + { + mainColor = SKColor.Parse(_randomColors[_random.Next(0, 255)]); + mainColor.ToHsl(out float _, out float _, out l); + } + float i = l + 20.0F > 100.0F ? 100.0F - l : 20.0F; + + PrimaryColor = mainColor; + SecondaryColor = SKColor.FromHsl(h, s, l += i); + AccentColor = SKColor.FromHsl(h += i, s, l); + DisplayImage = null; + CustomBackground = null; + } + } + + public Header(StructProperty displayStyle, string assetFolder) : this() + { + if (displayStyle.Value is UObject o) + { + if (!Properties.Settings.Default.UseChallengeBanner && o.TryGetValue(out var c1, "PrimaryColor", "Context_LimitedTimeColor") && c1 is StructProperty s1 && s1.Value is FLinearColor primaryColor) + PrimaryColor = SKColor.Parse(primaryColor.Hex); + if (!Properties.Settings.Default.UseChallengeBanner && o.TryGetValue(out var c2, "SecondaryColor", "Context_BaseColor") && c2 is StructProperty s2 && s2.Value is FLinearColor secondaryColor) + SecondaryColor = SKColor.Parse(secondaryColor.Hex); + if (!Properties.Settings.Default.UseChallengeBanner && o.TryGetValue("AccentColor", out var c3) && c3 is StructProperty s3 && s3.Value is FLinearColor accentColor) + { + AccentColor = SKColor.Parse(accentColor.Hex); + if (SecondaryColor.Red + SecondaryColor.Green + SecondaryColor.Blue <= 75 || assetFolder.Equals("LTM", StringComparison.CurrentCultureIgnoreCase)) // if secondary is too dark + SecondaryColor = AccentColor; // use accent and pray for accent to be ligher + } + + if (o.TryGetValue("DisplayImage", out var i) && i is SoftObjectProperty displayImage) + DisplayImage = Utils.GetSoftObjectTexture(displayImage); + if (CustomBackground == null && o.TryGetValue("CustomBackground", out var b) && b is SoftObjectProperty customBackground) + CustomBackground = Utils.GetSoftObjectTexture(customBackground); + } + } + } +} diff --git a/FModel/Creator/Bundles/HeaderStyle.cs b/FModel/Creator/Bundles/HeaderStyle.cs new file mode 100644 index 00000000..bd0534b3 --- /dev/null +++ b/FModel/Creator/Bundles/HeaderStyle.cs @@ -0,0 +1,98 @@ +using FModel.Creator.Texts; +using SkiaSharp; +using System; + +namespace FModel.Creator.Bundles +{ + static class HeaderStyle + { + public static void DrawHeaderPaint(SKCanvas c, BaseBundle icon) + { + c.DrawRect(new SKRect(0, 0, icon.Width, icon.HeaderHeight), new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = icon.DisplayStyle.PrimaryColor + }); + + if (icon.DisplayStyle.CustomBackground != null && icon.DisplayStyle.CustomBackground.Height != icon.DisplayStyle.CustomBackground.Width) + { + icon.IsDisplayNameShifted = false; + var bgPaint = new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.High, BlendMode = SKBlendMode.Screen }; + if (Properties.Settings.Default.UseChallengeBanner) bgPaint.Color = SKColors.Transparent.WithAlpha((byte)Properties.Settings.Default.ChallengeBannerOpacity); + c.DrawBitmap(icon.DisplayStyle.CustomBackground, new SKRect(0, 0, 1024, 256), bgPaint); + } + else if (icon.DisplayStyle.DisplayImage != null) + { + icon.IsDisplayNameShifted = true; + if (icon.DisplayStyle.CustomBackground != null && icon.DisplayStyle.CustomBackground.Height == icon.DisplayStyle.CustomBackground.Width) + c.DrawBitmap(icon.DisplayStyle.CustomBackground, new SKRect(0, 0, icon.HeaderHeight, icon.HeaderHeight), + new SKPaint { + IsAntialias = true, FilterQuality = SKFilterQuality.High, BlendMode = SKBlendMode.Screen, + ImageFilter = SKImageFilter.CreateDropShadow(2.5F, 0, 20, 0, icon.DisplayStyle.SecondaryColor.WithAlpha(25), SKDropShadowImageFilterShadowMode.DrawShadowAndForeground) + }); + + c.DrawBitmap(icon.DisplayStyle.DisplayImage, new SKRect(0, 0, icon.HeaderHeight, icon.HeaderHeight), + new SKPaint { + IsAntialias = true, FilterQuality = SKFilterQuality.High, + ImageFilter = SKImageFilter.CreateDropShadow(-2.5F, 0, 20, 0, icon.DisplayStyle.SecondaryColor.WithAlpha(50), SKDropShadowImageFilterShadowMode.DrawShadowAndForeground) + }); + } + + SKPath pathTop = new SKPath { FillType = SKPathFillType.EvenOdd }; + pathTop.MoveTo(0, icon.HeaderHeight); + pathTop.LineTo(icon.Width, icon.HeaderHeight); + pathTop.LineTo(icon.Width, icon.HeaderHeight - 19); + pathTop.LineTo(icon.Width / 2 + 7, icon.HeaderHeight - 23); + pathTop.LineTo(icon.Width / 2 + 13, icon.HeaderHeight - 7); + pathTop.LineTo(0, icon.HeaderHeight - 19); + pathTop.Close(); + c.DrawPath(pathTop, new SKPaint { + IsAntialias = true, FilterQuality = SKFilterQuality.High, Color = icon.DisplayStyle.SecondaryColor, + ImageFilter = SKImageFilter.CreateDropShadow(-5, -5, 0, 0, icon.DisplayStyle.AccentColor.WithAlpha(75), SKDropShadowImageFilterShadowMode.DrawShadowAndForeground) + }); + + c.DrawRect(new SKRect(0, icon.HeaderHeight, icon.Width, icon.HeaderHeight + icon.AdditionalSize), new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = icon.DisplayStyle.PrimaryColor.WithAlpha(200) // default background is black, so i'm kinda lowering the brightness here and that's what i want + }); + } + + public static void DrawHeaderText(SKCanvas c, BaseBundle icon) + { + using SKPaint paint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Typeface = Text.TypeFaces.BundleDisplayNameTypeface, + TextSize = 50, + Color = SKColors.White, + TextAlign = SKTextAlign.Left, + }; + + string text = icon.DisplayName.ToUpper(); + int x = icon.IsDisplayNameShifted ? 300 : 50; + while (paint.MeasureText(text) > (icon.Width - x)) + { + paint.TextSize -= 2; + } + c.DrawText(text, x, 155, paint); + + paint.Color = SKColors.White.WithAlpha(150); + paint.TextAlign = SKTextAlign.Right; + paint.TextSize = 23; + c.DrawText(icon.Watermark + .Replace("{BundleName}", text) + .Replace("{Date}", DateTime.Now.ToString("dd/MM/yyyy")), + icon.Width - 25, icon.HeaderHeight - 40, paint); + + paint.Typeface = Text.TypeFaces.BundleDefaultTypeface; + paint.Color = icon.DisplayStyle.SecondaryColor; + paint.TextAlign = SKTextAlign.Left; + paint.TextSize = 30; + c.DrawText(icon.FolderName.ToUpper(), x, 95, paint); + } + } +} diff --git a/FModel/Creator/Bundles/Quest.cs b/FModel/Creator/Bundles/Quest.cs new file mode 100644 index 00000000..ee0847b0 --- /dev/null +++ b/FModel/Creator/Bundles/Quest.cs @@ -0,0 +1,94 @@ +using FModel.Creator.Texts; +using PakReader.Pak; +using PakReader.Parsers.Class; +using PakReader.Parsers.PropertyTagData; + +namespace FModel.Creator.Bundles +{ + public class Quest + { + public string Description; + public int Count; + public Reward Reward; + + public Quest() + { + Description = ""; + Count = 0; + Reward = null; + } + + public Quest(UObject obj) : this() + { + if (obj.TryGetValue("Description", out var d) && d is TextProperty description) + Description = Text.GetTextPropertyBase(description); + if (obj.TryGetValue("ObjectiveCompletionCount", out var o) && o is IntProperty objectiveCompletionCount) + Count = objectiveCompletionCount.Value; + + if (obj.TryGetValue("Objectives", out var v1) && v1 is ArrayProperty a1 && + a1.Value.Length > 0 && a1.Value[0] is StructProperty s && s.Value is UObject objectives) + { + if (string.IsNullOrEmpty(Description) && objectives.TryGetValue("Description", out var od) && od is TextProperty objectivesDescription) + Description = Text.GetTextPropertyBase(objectivesDescription); + + if (Count == 0 && objectives.TryGetValue("Count", out var c) && c is IntProperty count) + Count = count.Value; + } + + if (obj.TryGetValue("RewardsTable", out var v4) && v4 is ObjectProperty rewardsTable) + { + PakPackage p = Utils.GetPropertyPakPackage(rewardsTable.Value.Resource.OuterIndex.Resource.ObjectName.String); + if (p.HasExport() && !p.Equals(default)) + { + var u = p.GetExport(); + if (u != null && u.TryGetValue("Default", out var i) && i is UObject r && + r.TryGetValue("TemplateId", out var i1) && i1 is NameProperty templateId && + r.TryGetValue("Quantity", out var i2) && i2 is IntProperty quantity) + { + Reward = new Reward(quantity, templateId); + } + } + } + + if (Reward == null && obj.TryGetValue("Rewards", out var v2) && v2 is ArrayProperty rewards) + { + foreach (StructProperty reward in rewards.Value) + { + if (reward.Value is UObject r1 && + r1.TryGetValue("ItemPrimaryAssetId", out var i1) && i1 is StructProperty itemPrimaryAssetId && + r1.TryGetValue("Quantity", out var i2) && i2 is IntProperty quantity) + { + if (itemPrimaryAssetId.Value is UObject r2 && + r2.TryGetValue("PrimaryAssetType", out var t1) && t1 is StructProperty primaryAssetType && + r2.TryGetValue("PrimaryAssetName", out var t2) && t2 is NameProperty primaryAssetName) + { + if (primaryAssetType.Value is UObject r3 && r3.TryGetValue("Name", out var k) && k is NameProperty name) + { + if (!name.Value.String.Equals("Quest") && !name.Value.String.Equals("Token") && + !name.Value.String.Equals("ChallengeBundle") && !name.Value.String.Equals("GiftBox")) + { + Reward = new Reward(quantity, primaryAssetName); + break; + } + } + } + } + } + } + + if (Reward == null && obj.TryGetValue("HiddenRewards", out var v3) && v3 is ArrayProperty hiddenRewards) + { + foreach (StructProperty reward in hiddenRewards.Value) + { + if (reward.Value is UObject r1 && + r1.TryGetValue("TemplateId", out var i1) && i1 is NameProperty templateId && + r1.TryGetValue("Quantity", out var i2) && i2 is IntProperty quantity) + { + Reward = new Reward(quantity, templateId); + break; + } + } + } + } + } +} diff --git a/FModel/Creator/Bundles/QuestStyle.cs b/FModel/Creator/Bundles/QuestStyle.cs new file mode 100644 index 00000000..70d3af47 --- /dev/null +++ b/FModel/Creator/Bundles/QuestStyle.cs @@ -0,0 +1,174 @@ +using FModel.Creator.Texts; +using SkiaSharp; + +namespace FModel.Creator.Bundles +{ + static class QuestStyle + { + public static void DrawQuests(SKCanvas c, BaseBundle icon) + { + using SKPaint paint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + TextSize = 27, + Color = SKColors.White, + TextAlign = SKTextAlign.Left, + Typeface = Text.TypeFaces.BundleDisplayNameTypeface + }; + + int y = icon.HeaderHeight + 50; + foreach (Quest q in icon.Quests) + { + DrawQuestBackground(c, icon, y, true); + + paint.TextSize = 27; + paint.ImageFilter = null; + paint.Color = SKColors.White; + paint.TextAlign = SKTextAlign.Left; + paint.Typeface = Text.TypeFaces.BundleDisplayNameTypeface; + while (paint.MeasureText(q.Description) > icon.Width - 65 - 165) + { + paint.TextSize -= 1; + } + c.DrawText(q.Description, new SKPoint(65, y + paint.TextSize + 11), paint); + + paint.TextSize = 16; + paint.Color = SKColors.White.WithAlpha(200); + paint.Typeface = Text.TypeFaces.BundleDefaultTypeface; + c.DrawText(q.Count.ToString(), new SKPoint(93 + icon.Width - (175 * 3), y + 60), paint); + + if (q.Reward?.RewardIcon != null) + { + if (q.Reward.IsCountShifted) + { + int l = q.Reward.RewardQuantity.ToString().Length; + paint.TextSize = l >= 5 ? 30 : 35; + paint.TextAlign = SKTextAlign.Right; + paint.Color = SKColor.Parse(q.Reward.RewardFillColor); + paint.ImageFilter = SKImageFilter.CreateDropShadow(0, 0, 5, 5, SKColor.Parse(q.Reward.RewardBorderColor).WithAlpha(200), SKDropShadowImageFilterShadowMode.DrawShadowAndForeground); + c.DrawText(q.Reward.RewardQuantity.ToString(), new SKPoint(icon.Width - 85, y + 47.5F), paint); + c.DrawBitmap(q.Reward.RewardIcon, new SKPoint(icon.Width - 30 - q.Reward.RewardIcon.Width, y + 12.5F), + new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.High }); + } + else + c.DrawBitmap(q.Reward.RewardIcon, new SKPoint(icon.Width - 125, y + 5), + new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.High }); + } + + y += 95; + } + } + + public static void DrawCompletionRewards(SKCanvas c, BaseBundle icon) + { + using SKPaint paint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + TextSize = 35, + Color = SKColors.White, + TextAlign = SKTextAlign.Left, + Typeface = Text.TypeFaces.BundleDisplayNameTypeface + }; + + int y = icon.HeaderHeight + (50 * 2) + (95 * icon.Quests.Count); + foreach (CompletionReward r in icon.CompletionRewards) + { + DrawQuestBackground(c, icon, y, false); + + paint.TextSize = 35; + paint.ImageFilter = null; + paint.Color = SKColors.White; + paint.TextAlign = SKTextAlign.Left; + paint.Typeface = Text.TypeFaces.BundleDisplayNameTypeface; + while (paint.MeasureText(r.CompletionText) > icon.Width - 65 - 165) + { + paint.TextSize -= 1; + } + c.DrawText(r.CompletionText, new SKPoint(65, y + paint.TextSize + 15), paint); + + if (r.Reward?.RewardIcon != null) + { + if (r.Reward.IsCountShifted) + { + int l = r.Reward.RewardQuantity.ToString().Length; + paint.TextSize = l >= 5 ? 30 : 35; + paint.TextAlign = SKTextAlign.Right; + paint.Color = SKColor.Parse(r.Reward.RewardFillColor); + paint.Typeface = Text.TypeFaces.BundleDefaultTypeface; + paint.ImageFilter = SKImageFilter.CreateDropShadow(0, 0, 5, 5, SKColor.Parse(r.Reward.RewardBorderColor).WithAlpha(200), SKDropShadowImageFilterShadowMode.DrawShadowAndForeground); + c.DrawText(r.Reward.RewardQuantity.ToString(), new SKPoint(icon.Width - 85, y + 47.5F), paint); + c.DrawBitmap(r.Reward.RewardIcon, new SKPoint(icon.Width - 30 - r.Reward.RewardIcon.Width, y + 12.5F), + new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.High }); + } + else + c.DrawBitmap(r.Reward.RewardIcon, new SKPoint(icon.Width - 125, y + 5), + new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.High }); + } + + y += 95; + } + } + + private static void DrawQuestBackground(SKCanvas c, BaseBundle icon, int y, bool hasSlider) + { + SKColor baseColor = icon.DisplayStyle.PrimaryColor; + using SKPaint paint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = baseColor + }; + using SKPath secondaryRect = new SKPath + { + FillType = SKPathFillType.EvenOdd + }; + using SKPath selector = new SKPath + { + FillType = SKPathFillType.EvenOdd + }; + using SKPath slider = new SKPath + { + FillType = SKPathFillType.EvenOdd + }; + + c.DrawRect(new SKRect(25, y, icon.Width - 25, y + 75), paint); + + baseColor.ToHsl(out float h, out float s, out float l); + baseColor = SKColor.FromHsl(h, s, l + 5); + paint.Color = baseColor; + + secondaryRect.MoveTo(32, y + 5); + secondaryRect.LineTo(icon.Width - 155, y + 4); + secondaryRect.LineTo(icon.Width - 175, y + 68); + secondaryRect.LineTo(29, y + 71); + secondaryRect.Close(); + c.DrawPath(secondaryRect, paint); + + paint.Color = icon.DisplayStyle.SecondaryColor; + selector.MoveTo(41, y + 38); + selector.LineTo(48, y + 34); + selector.LineTo(52, y + 39); + selector.LineTo(46, y + 44); + selector.Close(); + c.DrawPath(selector, paint); + + if (hasSlider) + { + slider.MoveTo(65, y + 53); + slider.LineTo(65 + icon.Width - (175 * 3), y + 53); + slider.LineTo(65 + icon.Width - (175 * 3), y + 58); + slider.LineTo(65, y + 58); + slider.Close(); + c.DrawPath(slider, paint); + + paint.TextSize = 14; + paint.Color = SKColors.White; + paint.TextAlign = SKTextAlign.Left; + paint.Typeface = Text.TypeFaces.BundleDefaultTypeface; + c.DrawText("0 / ", new SKPoint(75 + icon.Width - (175 * 3), y + 59), paint); + } + } + } +} diff --git a/FModel/Creator/Bundles/Reward.cs b/FModel/Creator/Bundles/Reward.cs new file mode 100644 index 00000000..fd38be35 --- /dev/null +++ b/FModel/Creator/Bundles/Reward.cs @@ -0,0 +1,134 @@ +using PakReader.Pak; +using PakReader.Parsers.Class; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; +using System; + +namespace FModel.Creator.Bundles +{ + public class Reward + { + public int RewardQuantity; + public SKBitmap RewardIcon; + public string RewardFillColor; + public string RewardBorderColor; + public bool IsCountShifted; + + public Reward() + { + RewardQuantity = 0; + RewardIcon = null; + RewardFillColor = ""; + RewardBorderColor = ""; + IsCountShifted = false; + } + + public Reward(IntProperty quantity, NameProperty primaryAssetName) : this(quantity, primaryAssetName.Value.String) { } + public Reward(IntProperty quantity, string assetName) : this() + { + RewardQuantity = quantity.Value; + + if (assetName.Contains(':')) + { + string[] parts = assetName.Split(':'); + if (parts[0].Equals("HomebaseBannerIcon", StringComparison.CurrentCultureIgnoreCase)) + { + PakPackage p = Utils.GetPropertyPakPackage("/Game/Banners/BannerIcons"); + if (p.HasExport() && !p.Equals(default)) + { + var c = p.GetExport(); + if (c != null && c.TryGetCaseInsensitiveValue(parts[1], out var s) && s is UObject banner) + { + RewardIcon = new BaseIcon(banner, "BannerIcons.uasset").IconImage.Resize(64, 64); + } + } + } + else GetReward(parts[1]); + } + else GetReward(assetName); + } + + public Reward(IntProperty quantity, SoftObjectProperty itemDefinition) : this() + { + RewardQuantity = quantity.Value; + + PakPackage p = Utils.GetPropertyPakPackage(itemDefinition.Value.AssetPathName.String); + if (p.HasExport() && !p.Equals(default)) + { + var d = p.GetExport(); + if (d != null) + { + int s1 = itemDefinition.Value.AssetPathName.String.LastIndexOf('/'); + if (s1 < 0) s1 = 0; + int s2 = itemDefinition.Value.AssetPathName.String.LastIndexOf('.') - s1; + switch (itemDefinition.Value.AssetPathName.String) + { + case "/Game/Items/PersistentResources/AthenaBattleStar.AthenaBattleStar": + IsCountShifted = true; + RewardFillColor = "FFDB67"; + RewardBorderColor = "8F4A20"; + RewardIcon = Utils.GetTexture("/Game/UI/Foundation/Textures/Icons/Items/T-FNBR-BattlePoints").Resize(48, 48); + break; + case "/Game/Items/PersistentResources/AthenaSeasonalXP.AthenaSeasonalXP": + IsCountShifted = true; + RewardFillColor = "E6FDB1"; + RewardBorderColor = "51830F"; + RewardIcon = Utils.GetTexture("/Game/UI/Foundation/Textures/Icons/Items/T-FNBR-XPMedium").Resize(48, 48); + break; + case "/Game/Items/Currency/MtxGiveaway.MtxGiveaway": + IsCountShifted = true; + RewardFillColor = "DCE6FF"; + RewardBorderColor = "64A0AF"; + RewardIcon = Utils.GetTexture("/Game/UI/Foundation/Textures/Icons/Items/T-Items-MTX").Resize(48, 48); + break; + default: + IsCountShifted = false; + RewardIcon = new BaseIcon(d, itemDefinition.Value.AssetPathName.String.Substring(s1, s2) + ".uasset").IconImage.Resize(64, 64); + break; + } + } + } + } + + private void GetReward(string trigger) + { + switch (trigger.ToLower()) + { + case "athenabattlestar": + IsCountShifted = true; + RewardFillColor = "FFDB67"; + RewardBorderColor = "8F4A20"; + RewardIcon = Utils.GetTexture("/Game/UI/Foundation/Textures/Icons/Items/T-FNBR-BattlePoints").Resize(48, 48); + break; + case "athenaseasonalxp": + IsCountShifted = true; + RewardFillColor = "E6FDB1"; + RewardBorderColor = "51830F"; + RewardIcon = Utils.GetTexture("/Game/UI/Foundation/Textures/Icons/Items/T-FNBR-XPMedium").Resize(48, 48); + break; + case "mtxgiveaway": + IsCountShifted = true; + RewardFillColor = "DCE6FF"; + RewardBorderColor = "64A0AF"; + RewardIcon = Utils.GetTexture("/Game/UI/Foundation/Textures/Icons/Items/T-Items-MTX").Resize(48, 48); + break; + default: + { + string path = Utils.GetFullPath($"/FortniteGame/Content/Athena/.*?/{trigger}.*").Replace("FortniteGame/Content", "Game"); + PakPackage p = Utils.GetPropertyPakPackage(path); + if (p.HasExport() && !p.Equals(default)) + { + var d = p.GetExport(); + if (d != null) + { + int i = path.LastIndexOf('/'); + IsCountShifted = false; + RewardIcon = new BaseIcon(d, path.Substring(i > 0 ? i : 0) + ".uasset").IconImage.Resize(64, 64); + } + } + break; + } + } + } + } +} diff --git a/FModel/Creator/Creator.cs b/FModel/Creator/Creator.cs new file mode 100644 index 00000000..adf3f13a --- /dev/null +++ b/FModel/Creator/Creator.cs @@ -0,0 +1,180 @@ +using FModel.Creator.Bundles; +using FModel.Creator.Icons; +using FModel.Creator.Rarities; +using FModel.Creator.Stats; +using FModel.Creator.Texts; +using FModel.ViewModels.ImageBox; +using PakReader.Parsers.Class; +using SkiaSharp; +using System.IO; + +namespace FModel.Creator +{ + static class Creator + { + /// + /// we draw based on the fist export type of the asset, no need to check others it's a waste of time + /// i don't cache images because i don't wanna store a lot of SKCanvas in the memory + /// + /// true if an icon has been drawn + public static bool TryDrawIcon(string assetPath, string exportType, IUExport export) + { + var d = new DirectoryInfo(assetPath); + string assetName = d.Name; + string assetFolder = d.Parent.Name; + if (Text.TypeFaces.NeedReload(false)) + Text.TypeFaces = new Typefaces(); // when opening bundle creator settings without loading paks first + + // please respect my wave if you wanna add a new exportType + // Athena first, then Fort, thank you + switch (exportType) + { + case "AthenaConsumableEmoteItemDefinition": + case "AthenaSkyDiveContrailItemDefinition": + case "AthenaLoadingScreenItemDefinition": + case "AthenaVictoryPoseItemDefinition": + case "AthenaPetCarrierItemDefinition": + case "AthenaMusicPackItemDefinition": + case "AthenaBattleBusItemDefinition": + case "AthenaCharacterItemDefinition": + case "AthenaBackpackItemDefinition": + case "AthenaPickaxeItemDefinition": + case "AthenaGadgetItemDefinition": + case "AthenaGliderItemDefinition": + case "AthenaDailyQuestDefinition": + case "AthenaSprayItemDefinition": + case "AthenaDanceItemDefinition": + case "AthenaEmojiItemDefinition": + case "AthenaItemWrapDefinition": + case "AthenaToyItemDefinition": + case "FortHeroType": + case "FortTokenType": + case "FortAbilityKit": + case "FortWorkerType": + case "FortBannerTokenType": + case "FortVariantTokenType": + case "FortFeatItemDefinition": + case "FortStatItemDefinition": + case "FortTrapItemDefinition": + case "FortAmmoItemDefinition": + case "FortQuestItemDefinition": + case "FortBadgeItemDefinition": + case "FortAwardItemDefinition": + case "FortGadgetItemDefinition": + case "FortPlaysetItemDefinition": + case "FortGiftBoxItemDefinition": + case "FortSpyTechItemDefinition": + case "FortAccoladeItemDefinition": + case "FortCardPackItemDefinition": + case "FortDefenderItemDefinition": + case "FortCurrencyItemDefinition": + case "FortResourceItemDefinition": + case "FortSchematicItemDefinition": + case "FortIngredientItemDefinition": + case "FortWeaponMeleeItemDefinition": + case "FortContextTrapItemDefinition": + case "FortPlayerPerksItemDefinition": + case "FortPlaysetPropItemDefinition": + case "FortHomebaseNodeItemDefinition": + case "FortWeaponRangedItemDefinition": + case "FortNeverPersistItemDefinition": + case "FortPlaysetGrenadeItemDefinition": + case "FortPersonalVehicleItemDefinition": + case "FortHardcoreModifierItemDefinition": + case "FortConsumableAccountItemDefinition": + case "FortConversionControlItemDefinition": + case "FortPersistentResourceItemDefinition": + case "FortCampaignHeroLoadoutItemDefinition": + case "FortConditionalResourceItemDefinition": + case "FortChallengeBundleScheduleDefinition": + case "FortWeaponMeleeDualWieldItemDefinition": + case "FortDailyRewardScheduleTokenDefinition": + { + BaseIcon icon = new BaseIcon(export, exportType, assetName); + int height = icon.Size + icon.AdditionalSize; + using (var ret = new SKBitmap(icon.Size, height, SKColorType.Rgba8888, SKAlphaType.Opaque)) + using (var c = new SKCanvas(ret)) + { + Rarity.DrawRarity(c, icon); + LargeSmallImage.DrawPreviewImage(c, icon); + if ((EIconDesign)Properties.Settings.Default.AssetsIconDesign != EIconDesign.NoText) + { + Text.DrawBackground(c, icon); + Text.DrawDisplayName(c, icon); + Text.DrawDescription(c, icon); + if ((EIconDesign)Properties.Settings.Default.AssetsIconDesign != EIconDesign.Mini) + { + if (!icon.ShortDescription.Equals(icon.DisplayName) && !icon.ShortDescription.Equals(icon.Description)) + Text.DrawToBottom(c, icon, ETextSide.Left, icon.ShortDescription); + Text.DrawToBottom(c, icon, ETextSide.Right, icon.CosmeticSource); + } + } + UserFacingFlag.DrawUserFacingFlags(c, icon); + + // has more things to show + if (height > icon.Size) + { + Statistics.DrawStats(c, icon); + } + + Watermark.DrawWatermark(c); // watermark should only be applied on icons with width = 512 + ImageBoxVm.imageBoxViewModel.Set(ret, assetName); + } + return true; + } + case "FortItemSeriesDefinition": + { + BaseIcon icon = new BaseIcon(); + using (var ret = new SKBitmap(icon.Size, icon.Size, SKColorType.Rgba8888, SKAlphaType.Opaque)) + using (var c = new SKCanvas(ret)) + { + Serie.GetRarity(icon, export); + Rarity.DrawRarity(c, icon); + + Watermark.DrawWatermark(c); // watermark should only be applied on icons with width = 512 + ImageBoxVm.imageBoxViewModel.Set(ret, assetName); + } + return true; + } + case "PlaylistUserOptionEnum": + case "PlaylistUserOptionBool": + case "PlaylistUserOptionString": + case "PlaylistUserOptionIntEnum": + case "PlaylistUserOptionIntRange": + case "PlaylistUserOptionColorEnum": + case "PlaylistUserOptionFloatEnum": + case "PlaylistUserOptionFloatRange": + case "PlaylistUserOptionPrimaryAsset": + case "PlaylistUserOptionCollisionProfileEnum": + { + BaseUserOption icon = new BaseUserOption(export); + using (var ret = new SKBitmap(icon.Width, icon.Height, SKColorType.Rgba8888, SKAlphaType.Opaque)) + using (var c = new SKCanvas(ret)) + { + icon.Draw(c); + + Watermark.DrawWatermark(c); // watermark should only be applied on icons with width = 512 + ImageBoxVm.imageBoxViewModel.Set(ret, assetName); + } + return true; + } + case "FortChallengeBundleItemDefinition": + { + BaseBundle icon = new BaseBundle(export, assetFolder); + using (var ret = new SKBitmap(icon.Width, icon.HeaderHeight + icon.AdditionalSize, SKColorType.Rgba8888, SKAlphaType.Opaque)) + using (var c = new SKCanvas(ret)) + { + HeaderStyle.DrawHeaderPaint(c, icon); + HeaderStyle.DrawHeaderText(c, icon); + QuestStyle.DrawQuests(c, icon); + QuestStyle.DrawCompletionRewards(c, icon); + + ImageBoxVm.imageBoxViewModel.Set(ret, assetName); + } + return true; + } + } + return false; + } + } +} diff --git a/FModel/Creator/Icons/DisplayAssetImage.cs b/FModel/Creator/Icons/DisplayAssetImage.cs new file mode 100644 index 00000000..df232b55 --- /dev/null +++ b/FModel/Creator/Icons/DisplayAssetImage.cs @@ -0,0 +1,55 @@ +using PakReader.Pak; +using PakReader.Parsers.Class; +using PakReader.Parsers.PropertyTagData; + +namespace FModel.Creator.Icons +{ + static class DisplayAssetImage + { + public static bool GetDisplayAssetImage(BaseIcon icon, SoftObjectProperty o, string assetName) + { + string imageType = "DetailsImage"; + switch ("DA_Featured_" + assetName) + { + case "DA_Featured_Glider_ID_141_AshtonBoardwalk.uasset": + case "DA_Featured_Glider_ID_150_TechOpsBlue.uasset": + case "DA_Featured_Glider_ID_131_SpeedyMidnight.uasset": + case "DA_Featured_Pickaxe_ID_178_SpeedyMidnight.uasset": + case "DA_Featured_Glider_ID_015_Brite.uasset": + case "DA_Featured_Glider_ID_016_Tactical.uasset": + case "DA_Featured_Glider_ID_017_Assassin.uasset": + case "DA_Featured_Pickaxe_ID_027_Scavenger.uasset": + case "DA_Featured_Pickaxe_ID_028_Space.uasset": + case "DA_Featured_Pickaxe_ID_029_Assassin.uasset": + return false; + case "DA_Featured_Glider_ID_070_DarkViking.uasset": + case "DA_Featured_CID_319_Athena_Commando_F_Nautilus.uasset": + imageType = "TileImage"; + break; + } + + string path = o?.Value.AssetPathName.String; + 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)) + { + var obj = p.GetExport(); + if (obj != null) + { + if (obj.TryGetValue(imageType, out var v1) && v1 is StructProperty s && s.Value is UObject type && + type.TryGetValue("ResourceObject", out var v2) && v2 is ObjectProperty resourceObject) + { + if (!resourceObject.Value.Resource.OuterIndex.Resource.ObjectName.String.Contains("/Game/Athena/Prototype/Textures/")) + { + icon.IconImage = Utils.GetObjectTexture(resourceObject); + return true; + } + } + } + } + return false; + } + } +} diff --git a/FModel/Creator/Icons/LargeSmallImage.cs b/FModel/Creator/Icons/LargeSmallImage.cs new file mode 100644 index 00000000..3bd18e77 --- /dev/null +++ b/FModel/Creator/Icons/LargeSmallImage.cs @@ -0,0 +1,41 @@ +using PakReader.Pak; +using PakReader.Parsers.Class; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; + +namespace FModel.Creator.Icons +{ + static class LargeSmallImage + { + public static void GetPreviewImage(BaseIcon icon, StructProperty u) + { + if (u.Value is UObject o && o.TryGetValue("ResourceObject", out var v) && v is ObjectProperty resourceObject) + icon.IconImage = Utils.GetObjectTexture(resourceObject); + } + 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")) + path += "_" + assetName.Substring(assetName.LastIndexOf(".") - 1, 1); + + PakPackage p = Utils.GetPropertyPakPackage(path); + if (p.HasExport() && !p.Equals(default)) + { + var obj = p.GetExport(); + if (obj != null) + { + if (hightRes && obj.TryGetValue("LargePreviewImage", out var sLarge) && sLarge is SoftObjectProperty largePreviewImage) + GetPreviewImage(icon, largePreviewImage); + else if (obj.TryGetValue("SmallPreviewImage", out var sSmall) && sSmall is SoftObjectProperty smallPreviewImage) + GetPreviewImage(icon, smallPreviewImage); + } + } + } + public static void GetPreviewImage(BaseIcon icon, SoftObjectProperty s) => icon.IconImage = Utils.GetSoftObjectTexture(s); + + public static void DrawPreviewImage(SKCanvas c, BaseIcon icon) => + c.DrawBitmap(icon.IconImage ?? icon.FallbackImage, new SKRect(icon.Margin, icon.Margin, icon.Size - icon.Margin, icon.Size - icon.Margin), + new SKPaint { FilterQuality = SKFilterQuality.High, IsAntialias = true }); + } +} diff --git a/FModel/Creator/Icons/UserFacingFlag.cs b/FModel/Creator/Icons/UserFacingFlag.cs new file mode 100644 index 00000000..a8ac086c --- /dev/null +++ b/FModel/Creator/Icons/UserFacingFlag.cs @@ -0,0 +1,72 @@ +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; + +namespace FModel.Creator.Icons +{ + static class UserFacingFlag + { + public static void GetUserFacingFlags(List uffs, BaseIcon icon, string exportType) + { + if (uffs.Count > 0) + { + PakPackage p = Utils.GetPropertyPakPackage("/Game/Items/ItemCategories"); //PrimaryCategories - SecondaryCategories - TertiaryCategories + if (p.HasExport() && !p.Equals(default)) + { + var o = p.GetExport(); + if (o != null && o.TryGetValue("TertiaryCategories", out var tertiaryCategories) && tertiaryCategories is ArrayProperty tertiaryArray) + { + icon.UserFacingFlags = new SKBitmap[uffs.Count]; + for (int i = 0; i < uffs.Count; i++) + { + if (uffs[i].Equals("Cosmetics.UserFacingFlags.HasUpgradeQuests")) + { + if (exportType.Equals("AthenaPetCarrierItemDefinition")) + icon.UserFacingFlags[i] = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T-Icon-Pets-64.png")).Stream); + else + icon.UserFacingFlags[i] = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T-Icon-Quests-64.png")).Stream); + } + else + { + foreach (StructProperty structProp in tertiaryArray.Value) + { + if (structProp.Value is UObject mainUObject && + mainUObject.TryGetValue("TagContainer", out var struc1) && struc1 is StructProperty tagContainer && tagContainer.Value is FGameplayTagContainer f && f.GameplayTags.TryGetGameplayTag(uffs[i], out var _) && + mainUObject.TryGetValue("CategoryBrush", out var struc2) && struc2 is StructProperty categoryBrush && categoryBrush.Value is UObject categoryUObject && + categoryUObject.TryGetValue("Brush_XXS", out var struc3) && struc3 is StructProperty brushXXS && brushXXS.Value is UObject brushUObject && + brushUObject.TryGetValue("ResourceObject", out var object1) && object1 is ObjectProperty resourceObject) + { + icon.UserFacingFlags[i] = Utils.GetObjectTexture(resourceObject); + break; + } + } + } + } + } + } + } + } + + public static void DrawUserFacingFlags(SKCanvas c, BaseIcon icon) + { + if (icon.UserFacingFlags != null) + { + int size = 25; + int x = icon.Margin * (int)2.5; + foreach (SKBitmap b in icon.UserFacingFlags) + { + if (b == null) + continue; + + c.DrawBitmap(b.Resize(size, size), new SKPoint(x, icon.Margin * (int)2.5), new SKPaint { FilterQuality = SKFilterQuality.High, IsAntialias = true }); + x += size; + } + } + } + } +} diff --git a/FModel/Creator/Icons/Watermark.cs b/FModel/Creator/Icons/Watermark.cs new file mode 100644 index 00000000..c6b952c3 --- /dev/null +++ b/FModel/Creator/Icons/Watermark.cs @@ -0,0 +1,31 @@ +using SkiaSharp; +using System.IO; + +namespace FModel.Creator.Icons +{ + static class Watermark + { + public static void DrawWatermark(SKCanvas c) + { + if (Properties.Settings.Default.UseIconWatermark && !string.IsNullOrWhiteSpace(Properties.Settings.Default.IconWatermarkPath)) + { + using SKBitmap watermarkBase = SKBitmap.Decode(new FileInfo(Properties.Settings.Default.IconWatermarkPath).Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); + int sizeX = watermarkBase.Width * (int)Properties.Settings.Default.IconWatermarkScale / 512; + int sizeY = watermarkBase.Height * (int)Properties.Settings.Default.IconWatermarkScale / 512; + SKBitmap watermark = watermarkBase.Resize(sizeX, sizeY); + + float left = Properties.Settings.Default.IconWatermarkX; + float top = Properties.Settings.Default.IconWatermarkY; + float right = left + watermark.Width; + float bottom = top + watermark.Height; + c.DrawBitmap(watermark, new SKRect(left, top, right, bottom), + new SKPaint + { + FilterQuality = SKFilterQuality.High, + IsAntialias = true, + Color = SKColors.Transparent.WithAlpha((byte)Properties.Settings.Default.IconWatermarkOpacity) + }); + } + } + } +} diff --git a/FModel/Creator/Rarities/EFortRarity.cs b/FModel/Creator/Rarities/EFortRarity.cs new file mode 100644 index 00000000..412e7988 --- /dev/null +++ b/FModel/Creator/Rarities/EFortRarity.cs @@ -0,0 +1,15 @@ +namespace FModel.Creator.Rarities +{ + public enum EFortRarity : int + { + Common, + Uncommon, + Rare, + Epic, + Legendary, + Mythic, + Transcendent, + Unattainable, + //Impossible + } +} diff --git a/FModel/Creator/Rarities/Rarity.cs b/FModel/Creator/Rarities/Rarity.cs new file mode 100644 index 00000000..069a9897 --- /dev/null +++ b/FModel/Creator/Rarities/Rarity.cs @@ -0,0 +1,171 @@ +using PakReader.Pak; +using PakReader.Parsers.Class; +using PakReader.Parsers.Objects; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; +using System.Linq; + +namespace FModel.Creator.Rarities +{ + static class Rarity + { + public static void GetInGameRarity(BaseIcon icon, EnumProperty e) + { + PakPackage p = Utils.GetPropertyPakPackage("/Game/Balance/RarityData"); + if (p.HasExport() && !p.Equals(default)) + { + var d = p.GetExport(); + if (d != null) + { + EFortRarity rarity = EFortRarity.Uncommon; + switch (e?.Value.String) + { + case "EFortRarity::Common": + rarity = EFortRarity.Common; + break; + case "EFortRarity::Rare": + rarity = EFortRarity.Rare; + break; + case "EFortRarity::Epic": + case "EFortRarity::Quality": + rarity = EFortRarity.Epic; + break; + case "EFortRarity::Legendary": + rarity = EFortRarity.Legendary; + break; + case "EFortRarity::Mythic": + rarity = EFortRarity.Mythic; + break; + case "EFortRarity::Transcendent": + rarity = EFortRarity.Transcendent; + break; + case "EFortRarity::Unattainable": + rarity = EFortRarity.Unattainable; + break; + } + + if (d.Values.ElementAt((int)rarity) is StructProperty s && s.Value is UObject colors) + { + if (colors.TryGetValue("Color1", out var c1) && c1 is StructProperty s1 && s1.Value is FLinearColor color1 && + colors.TryGetValue("Color2", out var c2) && c2 is StructProperty s2 && s2.Value is FLinearColor color2 && + colors.TryGetValue("Color3", out var c3) && c3 is StructProperty s3 && s3.Value is FLinearColor color3) + { + icon.RarityBackgroundColors = new SKColor[2] { SKColor.Parse(color1.Hex), SKColor.Parse(color3.Hex) }; + icon.RarityBorderColor = new SKColor[2] { SKColor.Parse(color2.Hex), SKColor.Parse(color1.Hex) }; + } + } + } + } + else GetHardCodedRarity(icon, e); + } + + public static void GetHardCodedRarity(BaseIcon icon, EnumProperty e) + { + switch (e?.Value.String) + { + case "EFortRarity::Common": + icon.RarityBackgroundColors = new SKColor[2] { SKColor.Parse("6D6D6D"), SKColor.Parse("333333") }; + icon.RarityBorderColor = new SKColor[2] { SKColor.Parse("9E9E9E"), SKColor.Parse("9E9E9E") }; + break; + case "EFortRarity::Rare": + icon.RarityBackgroundColors = new SKColor[2] { SKColor.Parse("3669BB"), SKColor.Parse("133254") }; + icon.RarityBorderColor = new SKColor[2] { SKColor.Parse("5180EE"), SKColor.Parse("5180EE") }; + break; + case "EFortRarity::Epic": + case "EFortRarity::Quality": + icon.RarityBackgroundColors = new SKColor[2] { SKColor.Parse("8138C2"), SKColor.Parse("35155C") }; + icon.RarityBorderColor = new SKColor[2] { SKColor.Parse("B251ED"), SKColor.Parse("B251ED") }; + break; + case "EFortRarity::Legendary": + icon.RarityBackgroundColors = new SKColor[2] { SKColor.Parse("C06A38"), SKColor.Parse("5C2814") }; + icon.RarityBorderColor = new SKColor[2] { SKColor.Parse("EC9650"), SKColor.Parse("EC9650") }; + break; + case "EFortRarity::Mythic": + icon.RarityBackgroundColors = new SKColor[2] { SKColor.Parse("BA9C36"), SKColor.Parse("594415") }; + icon.RarityBorderColor = new SKColor[2] { SKColor.Parse("EED951"), SKColor.Parse("EED951") }; + break; + case "EFortRarity::Transcendent": + icon.RarityBackgroundColors = new SKColor[2] { SKColor.Parse("D51944"), SKColor.Parse("660522") }; + icon.RarityBorderColor = new SKColor[2] { SKColor.Parse("FF3F58"), SKColor.Parse("FF3F58") }; + break; + } + } + + public static void DrawRarity(SKCanvas c, BaseIcon icon) + { + // border + c.DrawRect(new SKRect(0, 0, icon.Size, icon.Size), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Shader = SKShader.CreateLinearGradient( + new SKPoint(icon.Size / 2, icon.Size), + new SKPoint(icon.Size, icon.Size / 4), + icon.RarityBorderColor, + SKShaderTileMode.Clamp) + }); + + switch ((EIconDesign)Properties.Settings.Default.AssetsIconDesign) + { + case EIconDesign.Flat: + { + if (icon.RarityBackgroundImage != null) + c.DrawBitmap(icon.RarityBackgroundImage, new SKRect(icon.Margin, icon.Margin, icon.Size - icon.Margin, icon.Size - icon.Margin), + new SKPaint { FilterQuality = SKFilterQuality.High, IsAntialias = true }); + else + { + c.DrawRect(new SKRect(icon.Margin, icon.Margin, icon.Size - icon.Margin, icon.Size - icon.Margin), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = icon.RarityBackgroundColors[0] + }); + + var paint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = icon.RarityBackgroundColors[1].WithAlpha(75) + }; + var pathTop = new SKPath { FillType = SKPathFillType.EvenOdd }; + pathTop.MoveTo(icon.Margin, icon.Margin); + pathTop.LineTo(icon.Margin + (icon.Size / 17 * 10), icon.Margin); + pathTop.LineTo(icon.Margin, icon.Margin + (icon.Size / 17)); + pathTop.Close(); + c.DrawPath(pathTop, paint); + + var pathBottom = new SKPath { FillType = SKPathFillType.EvenOdd }; + pathBottom.MoveTo(icon.Margin, icon.Size - icon.Margin); + pathBottom.LineTo(icon.Margin, icon.Size - icon.Margin - (icon.Size / 17 * 2.5f)); + pathBottom.LineTo(icon.Size - icon.Margin, icon.Size - icon.Margin - (icon.Size / 17 * 4.5f)); + pathBottom.LineTo(icon.Size - icon.Margin, icon.Size - icon.Margin); + pathBottom.Close(); + c.DrawPath(pathBottom, paint); + } + break; + } + default: + { + if (icon.RarityBackgroundImage != null) + c.DrawBitmap(icon.RarityBackgroundImage, new SKRect(icon.Margin, icon.Margin, icon.Size - icon.Margin, icon.Size - icon.Margin), + new SKPaint { FilterQuality = SKFilterQuality.High, IsAntialias = true }); + else + c.DrawRect(new SKRect(icon.Margin, icon.Margin, icon.Size - icon.Margin, icon.Size - icon.Margin), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Shader = SKShader.CreateRadialGradient( + new SKPoint(icon.Size / 2, icon.Size / 2), + icon.Size / 5 * 4, + icon.RarityBackgroundColors, + SKShaderTileMode.Clamp) + }); + break; + } + } + } + } +} diff --git a/FModel/Creator/Rarities/Serie.cs b/FModel/Creator/Rarities/Serie.cs new file mode 100644 index 00000000..fd037e89 --- /dev/null +++ b/FModel/Creator/Rarities/Serie.cs @@ -0,0 +1,40 @@ +using FModel.Creator.Texts; +using PakReader.Pak; +using PakReader.Parsers.Class; +using PakReader.Parsers.Objects; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; + +namespace FModel.Creator.Rarities +{ + static class Serie + { + public static void GetRarity(BaseIcon icon, ObjectProperty o) + { + PakPackage p = Utils.GetPropertyPakPackage(o.Value.Resource.OuterIndex.Resource.ObjectName.String); + if (p.HasExport() && !p.Equals(default)) + { + var obj = p.GetExport(); + if (obj != null) + GetRarity(icon, obj); + } + } + + public static void GetRarity(BaseIcon icon, IUExport export) + { + if (export.TryGetValue("BackgroundTexture", out var t) && t is SoftObjectProperty sop) + icon.RarityBackgroundImage = Utils.GetSoftObjectTexture(sop); + + if (export.TryGetValue("Colors", out var v) && v is StructProperty s && s.Value is UObject colors) + { + if (colors.TryGetValue("Color1", out var c1) && c1 is StructProperty s1 && s1.Value is FLinearColor color1 && + colors.TryGetValue("Color2", out var c2) && c2 is StructProperty s2 && s2.Value is FLinearColor color2 && + colors.TryGetValue("Color4", out var c4) && c4 is StructProperty s4 && s4.Value is FLinearColor color4) + { + icon.RarityBackgroundColors = new SKColor[2] { SKColor.Parse(color1.Hex), SKColor.Parse(color4.Hex) }; + icon.RarityBorderColor = new SKColor[2] { SKColor.Parse(color2.Hex), SKColor.Parse(color1.Hex) }; + } + } + } + } +} diff --git a/FModel/Creator/Stats/Statistic.cs b/FModel/Creator/Stats/Statistic.cs new file mode 100644 index 00000000..0730064e --- /dev/null +++ b/FModel/Creator/Stats/Statistic.cs @@ -0,0 +1,10 @@ +using SkiaSharp; + +namespace FModel.Creator.Stats +{ + public class Statistic + { + public SKBitmap Icon; + public string Description; + } +} diff --git a/FModel/Creator/Stats/Statistics.cs b/FModel/Creator/Stats/Statistics.cs new file mode 100644 index 00000000..3b687c35 --- /dev/null +++ b/FModel/Creator/Stats/Statistics.cs @@ -0,0 +1,203 @@ +using FModel.Creator.Texts; +using FModel.Utils; +using PakReader.Pak; +using PakReader.Parsers.Class; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; +using System; +using System.Windows; + +namespace FModel.Creator.Stats +{ + static class Statistics + { + public static void GetAmmoData(BaseIcon icon, SoftObjectProperty ammoData) + { + PakPackage p = Utils.GetPropertyPakPackage(ammoData.Value.AssetPathName.String); + if (p.HasExport() && !p.Equals(default)) + { + var obj = p.GetExport(); + if (obj != null) + { + if (obj.TryGetValue("DisplayName", out var v1) && v1 is TextProperty displayName && + obj.TryGetValue("SmallPreviewImage", out var v2) && v2 is SoftObjectProperty smallPreviewImage) + { + icon.Stats.Add(new Statistic + { + Icon = Utils.GetSoftObjectTexture(smallPreviewImage), + Description = Text.GetTextPropertyBase(displayName).ToUpper() + }); + } + } + } + } + + public static void GetWeaponStats(BaseIcon icon, StructProperty weaponStatHandle) + { + if (weaponStatHandle.Value is UObject o1 && + 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); + if (p.HasExport() && !p.Equals(default)) + { + var table = p.GetExport(); + if (table != null) + { + if (table.TryGetValue(rowName.Value.String, out var v1) && v1 is UObject stats) + { + if (stats.TryGetValue("ReloadTime", out var s1) && s1 is FloatProperty reloadTime && reloadTime.Value != 0) + icon.Stats.Add(new Statistic + { + Icon = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T_ReloadTime_Weapon_Stats.png")).Stream), + Description = $"{Localizations.GetLocalization(string.Empty, "6EA26D1A4252034FBD869A90F9A6E49A", "Reload Time")} ({Localizations.GetLocalization(string.Empty, "6BA53D764BA5CC13E821D2A807A72365", "seconds")}) : {reloadTime.Value:0.0}".ToUpper() + }); + + if (stats.TryGetValue("ClipSize", out var s2) && s2 is IntProperty clipSize && clipSize.Value != 0) + icon.Stats.Add(new Statistic + { + Icon = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T_ClipSize_Weapon_Stats.png")).Stream), + Description = $"{Localizations.GetLocalization(string.Empty, "068239DD4327B36124498C9C5F61C038", "Magazine Size")} : {clipSize.Value}".ToUpper() + }); + + if (stats.TryGetValue("DmgPB", out var s3) && s3 is FloatProperty dmgPB && dmgPB.Value != 0) + icon.Stats.Add(new Statistic + { + Icon = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T_DamagePerBullet_Weapon_Stats.png")).Stream), + Description = $"{Localizations.GetLocalization(string.Empty, "BF7E3CF34A9ACFF52E95EAAD4F09F133", "Damage to Player")} : {dmgPB.Value}".ToUpper() + }); + } + } + } + } + } + + public static void GetHeroStats(BaseIcon icon, ObjectProperty heroGameplayDefinition) + { + PakPackage p = Utils.GetPropertyPakPackage(heroGameplayDefinition.Value.Resource.OuterIndex.Resource.ObjectName.String); + if (p.HasExport() && !p.Equals(default)) + { + var obj = p.GetExport(); + if (obj != null) + { + if (obj.TryGetValue("HeroPerk", out var v1) && v1 is StructProperty s1 && s1.Value is UObject heroPerk) + { + GetAbilityKit(icon, heroPerk); + } + + if (obj.TryGetValue("TierAbilityKits", out var v2) && v2 is ArrayProperty tierAbilityKits) + { + foreach (StructProperty abilityKit in tierAbilityKits.Value) + { + if (abilityKit.Value is UObject kit) + { + GetAbilityKit(icon, kit); + } + } + } + } + } + } + + private static void GetAbilityKit(BaseIcon icon, UObject parent) + { + if (parent.TryGetValue("GrantedAbilityKit", out var v) && v is SoftObjectProperty grantedAbilityKit) + { + PakPackage k = Utils.GetPropertyPakPackage(grantedAbilityKit.Value.AssetPathName.String); + if (k.HasExport() && !k.Equals(default)) + { + var kit = k.GetExport(); + if (kit != null && + kit.GetExport("DisplayName") is TextProperty displayName && + kit.GetExport("IconBrush") is StructProperty brush && brush.Value is UObject iconBrush && + iconBrush.TryGetValue("ResourceObject", out var s) && s is ObjectProperty resourceObject) + { + icon.Stats.Add(new Statistic + { + Icon = Utils.GetObjectTexture(resourceObject), + Description = Text.GetTextPropertyBase(displayName).ToUpper() + }); + } + } + } + } + + public static void DrawStats(SKCanvas c, BaseIcon icon) + { + int size = 48; + int iconSize = 40; + int textSize = 25; + int y = icon.Size; + foreach (Statistic stat in icon.Stats) + { + c.DrawRect(new SKRect(0, y, icon.Size, y + size), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Shader = SKShader.CreateLinearGradient( + new SKPoint(icon.Size / 2, icon.Size), + new SKPoint(icon.Size, icon.Size / 4), + icon.RarityBorderColor, + SKShaderTileMode.Clamp) + }); + + + if ((EIconDesign)Properties.Settings.Default.AssetsIconDesign == EIconDesign.Flat) + { + c.DrawRect(new SKRect(icon.Margin, y, icon.Size - icon.Margin, y + size - icon.Margin), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = icon.RarityBackgroundColors[0] + }); + } + else + { + c.DrawRect(new SKRect(icon.Margin, y, icon.Size - icon.Margin, y + size - icon.Margin), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Shader = SKShader.CreateRadialGradient( + new SKPoint(icon.Size / 2, icon.Size / 2), + icon.Size / 5 * 4, + icon.RarityBackgroundColors, + SKShaderTileMode.Clamp) + }); + } + + c.DrawRect(new SKRect(icon.Margin, y, icon.Size - icon.Margin, y + size - icon.Margin), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = new SKColor(0, 0, 50, 75) + }); + + c.DrawBitmap(stat.Icon.Resize(iconSize, iconSize), new SKPoint(icon.Margin * (int)2.5, y + 4), new SKPaint { FilterQuality = SKFilterQuality.High, IsAntialias = true }); + + var statPaint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Typeface = Text.TypeFaces.DisplayNameTypeface, + TextSize = textSize, + Color = SKColors.White, + TextAlign = SKTextAlign.Center, + }; + + // resize if too long + while (statPaint.MeasureText(stat.Description) > (icon.Size - (icon.Margin * 2) - iconSize)) + { + statPaint.TextSize = textSize -= 2; + } + + c.DrawText(stat.Description, icon.Size / 2, y + 32, statPaint); + + y += size; + } + } + } +} diff --git a/FModel/Creator/Texts/ETextSide.cs b/FModel/Creator/Texts/ETextSide.cs new file mode 100644 index 00000000..2d4d9aba --- /dev/null +++ b/FModel/Creator/Texts/ETextSide.cs @@ -0,0 +1,9 @@ +namespace FModel.Creator.Texts +{ + public enum ETextSide + { + Center, + Right, + Left + } +} diff --git a/FModel/Creator/Texts/GameplayTag.cs b/FModel/Creator/Texts/GameplayTag.cs new file mode 100644 index 00000000..24dbd4ed --- /dev/null +++ b/FModel/Creator/Texts/GameplayTag.cs @@ -0,0 +1,72 @@ +using FModel.Creator.Icons; +using FModel.Utils; +using PakReader.Pak; +using PakReader.Parsers.Class; +using PakReader.Parsers.Objects; +using PakReader.Parsers.PropertyTagData; + +namespace FModel.Creator.Texts +{ + static class GameplayTag + { + public static void GetGameplayTags(BaseIcon icon, StructProperty s, string exportType) + { + if (s.Value is FGameplayTagContainer g) + { + if (g.GameplayTags.TryGetGameplayTag("Cosmetics.Source.", out var source)) + icon.CosmeticSource = source.String.Substring("Cosmetics.Source.".Length); + else if(g.GameplayTags.TryGetGameplayTag("Athena.ItemAction.", out var action)) + icon.CosmeticSource = action.String.Substring("Athena.ItemAction.".Length); + + if (g.GameplayTags.TryGetGameplayTag("Cosmetics.Set.", out var set)) + icon.Description += GetCosmeticSet(set.String); + if (g.GameplayTags.TryGetGameplayTag("Cosmetics.Filter.Season.", out var season)) + icon.Description += GetCosmeticSeason(season.String); + + UserFacingFlag.GetUserFacingFlags( + g.GameplayTags.GetAllGameplayTag("Cosmetics.UserFacingFlags.", "Homebase.Class.", "NPC.CharacterType.Survivor.Defender."), + icon, exportType); + } + } + + private static string GetCosmeticSet(string setName) + { + PakPackage p = Utils.GetPropertyPakPackage("/Game/Athena/Items/Cosmetics/Metadata/CosmeticSets"); + if (p.HasExport() && !p.Equals(default)) + { + var d = p.GetExport(); + if (d != null && d.TryGetValue(setName, out var obj) && obj is UObject o) + { + if (o.TryGetValue("DisplayName", out var displayName) && displayName is TextProperty t) + { + (string n, string k, string s) = Text.GetTextPropertyBases(t); + string set = Localizations.GetLocalization(n, k, s); + string format = Localizations.GetLocalization("Fort.Cosmetics", "CosmeticItemDescription_SetMembership_NotRich", "\nPart of the {0} set."); + return string.Format(format, set); + } + } + } + return string.Empty; + } + + private static string GetCosmeticSeason(string seasonNumber) + { + string s = seasonNumber.Substring("Cosmetics.Filter.Season.".Length); + int number = int.Parse(s); + if (number == 10) + s = "X"; + + string season = Localizations.GetLocalization("AthenaSeasonItemDefinitionInternal", "SeasonTextFormat", "Season {0}"); + string introduced = Localizations.GetLocalization("Fort.Cosmetics", "CosmeticItemDescription_Season", "\nIntroduced in {0}.") + .Replace("", string.Empty).Replace("", string.Empty); + if (number > 10) + { + string chapter = Localizations.GetLocalization("AthenaSeasonItemDefinitionInternal", "ChapterTextFormat", "Chapter {0}"); + string chapterFormat = Localizations.GetLocalization("AthenaSeasonItemDefinitionInternal", "ChapterSeasonTextFormat", "{0}, {1}"); + string d = string.Format(chapterFormat, string.Format(chapter, number / 10 + 1), string.Format(season, s[^1..])); + return string.Format(introduced, d); + } + else return string.Format(introduced, string.Format(season, s)); + } + } +} diff --git a/FModel/Creator/Texts/Helper.cs b/FModel/Creator/Texts/Helper.cs new file mode 100644 index 00000000..933dc50a --- /dev/null +++ b/FModel/Creator/Texts/Helper.cs @@ -0,0 +1,110 @@ +using SkiaSharp; +using System; +using System.Collections.Generic; +using System.Text; + +namespace FModel.Creator.Texts +{ + static class Helper + { + public class Line + { + public string Value { get; set; } + public float Width { get; set; } + } + + public static void DrawCenteredMultilineText(SKCanvas canvas, string text, int maxLineCount, BaseIcon icon, ETextSide side, SKRect area, SKPaint paint) + => DrawCenteredMultilineText(canvas, text, maxLineCount, icon.Size, icon.Margin, side, area, paint); + public static void DrawCenteredMultilineText(SKCanvas canvas, string text, int maxLineCount, int size, int margin, ETextSide side, SKRect area, SKPaint paint) + { + float lineHeight = paint.TextSize * 1.2f; + Line[] lines = SplitLines(text, paint, area.Width - margin); + + if (lines == null) + return; + if (lines.Length <= maxLineCount) + maxLineCount = lines.Length; + + float height = maxLineCount * lineHeight; + float y = area.MidY - height / 2; + for (int i = 0; i < maxLineCount; i++) + { + y += lineHeight; + float x = side switch + { + ETextSide.Center => area.MidX - lines[i].Width / 2, + ETextSide.Right => size - margin - lines[i].Width, + ETextSide.Left => margin, + _ => area.MidX - lines[i].Width / 2 + }; + canvas.DrawText(lines[i].Value.TrimEnd(), x, y, paint); + } + } + + public static void DrawMultilineText(SKCanvas canvas, string text, int size, int margin, ETextSide side, SKRect area, SKPaint paint, out int yPos) + { + float lineHeight = paint.TextSize * 1.2f; + Line[] lines = SplitLines(text, paint, area.Width - margin); + if (lines == null) + { + yPos = (int)area.Top; + return; + } + + float y = area.Top; + for (int i = 0; i < lines.Length; i++) + { + float x = side switch + { + ETextSide.Center => area.MidX - lines[i].Width / 2, + ETextSide.Right => size - margin - lines[i].Width, + ETextSide.Left => margin, + _ => area.MidX - lines[i].Width / 2 + }; + canvas.DrawText(lines[i].Value.TrimEnd(), x, y, paint); + y += lineHeight; + } + yPos = (int)area.Top + ((int)lineHeight * lines.Length); + } + + public static Line[] SplitLines(string text, SKPaint paint, float maxWidth) + { + if (string.IsNullOrEmpty(text)) + return null; + + float spaceWidth = paint.MeasureText(" "); + string[] lines = text.Split('\n', StringSplitOptions.RemoveEmptyEntries); + + List ret = new List(lines.Length); + for (int i = 0; i < lines.Length; i++) + { + if (string.IsNullOrWhiteSpace(lines[i])) + continue; + + float width = 0; + var lineResult = new StringBuilder(); + string[] words = lines[i].Split(' ', StringSplitOptions.None); + foreach (var word in words) + { + float wordWidth = paint.MeasureText(word); + float wordWithSpaceWidth = wordWidth + spaceWidth; + string wordWithSpace = word + " "; + + if (width + wordWidth > maxWidth) + { + ret.Add(new Line { Value = lineResult.ToString(), Width = width }); + lineResult = new StringBuilder(wordWithSpace); + width = wordWithSpaceWidth; + } + else + { + lineResult.Append(wordWithSpace); + width += wordWithSpaceWidth; + } + } + ret.Add(new Line { Value = lineResult.ToString(), Width = width }); + } + return ret.ToArray(); + } + } +} diff --git a/FModel/Creator/Texts/Text.cs b/FModel/Creator/Texts/Text.cs new file mode 100644 index 00000000..b2cb71b4 --- /dev/null +++ b/FModel/Creator/Texts/Text.cs @@ -0,0 +1,217 @@ +using PakReader.Pak; +using PakReader.Parsers.Class; +using PakReader.Parsers.Objects; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; +using System.Collections.Generic; + +namespace FModel.Creator.Texts +{ + static class Text + { + public static Typefaces TypeFaces = new Typefaces(); + private const int _STARTER_TEXT_POSITION = 380; + private static int _BOTTOM_TEXT_SIZE = 15; + private static int _NAME_TEXT_SIZE = 45; + + public static string GetTextPropertyBase(TextProperty t) + { + if (t.Value is FText text) + if (text.Text is FTextHistory.Base b) + return b.SourceString.Replace("", string.Empty).Replace("", string.Empty); + else if (text.Text is FTextHistory.StringTableEntry s) + { + PakPackage p = Utils.GetPropertyPakPackage(s.TableId.String); + if (p.HasExport() && !p.Equals(default)) + { + var table = p.GetExport(); + if (table != null) + { + if (table.TryGetValue("StringTable", out var v1) && v1 is FStringTable stringTable && + stringTable.KeysToMetadata.TryGetValue(stringTable.TableNamespace, out var v2) && v2 is Dictionary dico && + dico.TryGetValue(s.Key, out var ret)) + { + return ret; + } + } + } + } + + return string.Empty; + } + public static string GetTextPropertyBase(ArrayProperty a) + { + if (a.Value.Length > 0 && a.Value[0] is TextProperty t) + return GetTextPropertyBase(t); + return string.Empty; + } + + public static (string, string, string) GetTextPropertyBases(TextProperty t) + { + if (t.Value is FText text && text.Text is FTextHistory.Base b) + return (b.Namespace, b.Key, b.SourceString); + return (string.Empty, string.Empty, string.Empty); + } + + public static string GetMaxStackSize(StructProperty maxStackSize) + { + if (maxStackSize.Value is UObject o1) + { + if (o1.TryGetValue("Value", out var c) && c is FloatProperty value && value.Value != -1) // old way + return $"MaxStackSize : {value.Value}"; + else if ( + o1.TryGetValue("Curve", out var c1) && c1 is StructProperty curve && curve.Value is UObject o2 && + 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); + if (p.HasExport() && !p.Equals(default)) + { + var table = p.GetExport(); + if (table != null) + { + if (table.TryGetValue(rowName.Value.String, out var v1) && v1 is UObject maxStackAmount && + maxStackAmount.TryGetValue("Keys", out var v2) && v2 is ArrayProperty keys && + keys.Value.Length > 0 && (keys.Value[0] as StructProperty).Value is FSimpleCurveKey amount && + amount.KeyValue != -1) + { + return $"MaxStackSize : {amount.KeyValue}"; + } + } + } + } + } + return string.Empty; + } + + public static void DrawBackground(SKCanvas c, BaseIcon icon) + { + switch ((EIconDesign)Properties.Settings.Default.AssetsIconDesign) + { + case EIconDesign.Flat: + { + var pathBottom = new SKPath { FillType = SKPathFillType.EvenOdd }; + pathBottom.MoveTo(icon.Margin, icon.Size - icon.Margin); + pathBottom.LineTo(icon.Margin, icon.Size - icon.Margin - (icon.Size / 17 * 2.5f)); + pathBottom.LineTo(icon.Size - icon.Margin, icon.Size - icon.Margin - (icon.Size / 17 * 4.5f)); + pathBottom.LineTo(icon.Size - icon.Margin, icon.Size - icon.Margin); + pathBottom.Close(); + c.DrawPath(pathBottom, new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = new SKColor(0, 0, 50, 75), + }); + break; + } + default: + { + c.DrawRect( + new SKRect(icon.Margin, _STARTER_TEXT_POSITION, icon.Size - icon.Margin, icon.Size - icon.Margin), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = new SKColor(0, 0, 50, 75), + }); + break; + } + } + } + + public static void DrawDisplayName(SKCanvas c, BaseIcon icon) + { + _NAME_TEXT_SIZE = 45; + string text = icon.DisplayName; + SKTextAlign side = SKTextAlign.Center; + int x = icon.Size / 2; + int y = _STARTER_TEXT_POSITION + _NAME_TEXT_SIZE; + switch ((EIconDesign)Properties.Settings.Default.AssetsIconDesign) + { + case EIconDesign.Mini: + { + _NAME_TEXT_SIZE = 47; + text = text.ToUpper(); + break; + } + case EIconDesign.Flat: + { + _NAME_TEXT_SIZE = 47; + side = SKTextAlign.Right; + x = icon.Size - icon.Margin * 2; + break; + } + } + + SKPaint namePaint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Typeface = TypeFaces.DisplayNameTypeface, + TextSize = _NAME_TEXT_SIZE, + Color = SKColors.White, + TextAlign = side, + }; + + // resize if too long + while (namePaint.MeasureText(text) > (icon.Size - (icon.Margin * 2))) + { + namePaint.TextSize = _NAME_TEXT_SIZE -= 2; + } + + c.DrawText(text, x, y, namePaint); + } + + public static void DrawDescription(SKCanvas c, BaseIcon icon) + { + int maxLine = 4; + _BOTTOM_TEXT_SIZE = 15; + string text = icon.Description; + ETextSide side = ETextSide.Center; + switch ((EIconDesign)Properties.Settings.Default.AssetsIconDesign) + { + case EIconDesign.Mini: + { + maxLine = 5; + _BOTTOM_TEXT_SIZE = icon.Margin; + text = text.ToUpper(); + break; + } + case EIconDesign.Flat: + { + side = ETextSide.Right; + break; + } + } + + SKPaint descriptionPaint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Typeface = TypeFaces.DescriptionTypeface, + TextSize = 13, + Color = SKColors.White, + }; + + // wrap if too long + Helper.DrawCenteredMultilineText(c, text, maxLine, icon, side, + new SKRect(icon.Margin, _STARTER_TEXT_POSITION + _NAME_TEXT_SIZE, icon.Size - icon.Margin, icon.Size - _BOTTOM_TEXT_SIZE), + descriptionPaint); + } + + public static void DrawToBottom(SKCanvas c, BaseIcon icon, ETextSide side, string text) + { + SKPaint shortDescriptionPaint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Typeface = side == ETextSide.Left ? TypeFaces.DisplayNameTypeface : TypeFaces.DefaultTypeface, + TextSize = 15, + Color = SKColors.White, + TextAlign = side == ETextSide.Left ? SKTextAlign.Left : SKTextAlign.Right, + }; + + c.DrawText(text, side == ETextSide.Left ? icon.Margin * 2.5f : icon.Size - (icon.Margin * 2.5f), icon.Size - (icon.Margin * 2.5f), shortDescriptionPaint); + } + } +} diff --git a/FModel/Creator/Texts/Typefaces.cs b/FModel/Creator/Texts/Typefaces.cs new file mode 100644 index 00000000..05d7444f --- /dev/null +++ b/FModel/Creator/Texts/Typefaces.cs @@ -0,0 +1,105 @@ +using FModel.Utils; +using FModel.ViewModels.DataGrid; +using SkiaSharp; +using System; +using System.Windows; + +namespace FModel.Creator.Texts +{ + public class Typefaces + { +#pragma warning disable IDE0051 + private const string _BASE_PATH = "/Game/UI/Foundation/Fonts/"; + private const string _ASIA_ERINM = "AsiaERINM"; // korean fortnite + private const string _BURBANK_BIG_CONDENSED_BLACK = "BurbankBigCondensed-Black"; + private readonly Uri _BURBANK_BIG_CONDENSED_BOLD = new Uri("pack://application:,,,/Resources/BurbankBigCondensed-Bold.ttf"); // other languages fortnite unofficial + private const string _BURBANK_BIG_REGULAR_BLACK = "BurbankBigRegular-Black"; + private const string _BURBANK_BIG_REGULAR_BOLD = "BurbankBigRegular-Bold"; // official fortnite but it's too big so i use it for russian only + private const string _BURBANK_SMALL_MEDIUM = "BurbankSmall-Medium"; + private const string _DROID_SANS_FORTNITE_SUBSET = "DroidSans-Fortnite-Subset"; + private const string _NIS_JYAU = "NIS_JYAU"; // japanese fortnite + private const string _NOTO_COLOR_EMOJI = "NotoColorEmoji"; + private const string _NOTO_SANS_BOLD = "NotoSans-Bold"; + private const string _NOTO_SANS_FORTNITE_BOLD = "NotoSans-Fortnite-Bold"; + private const string _NOTO_SANS_FORTNITE_ITALIC = "NotoSans-Fortnite-Italic"; + private const string _NOTO_SANS_FORTNITE_REGULAR = "NotoSans-Fortnite-Regular"; + private const string _NOTO_SANS_ITALIC = "NotoSans-Italic"; + private const string _NOTO_SANS_REGULAR = "NotoSans-Regular"; + private const string _NOTO_SANS_ARABIC_BLACK = "NotoSansArabic-Black"; // arabic fortnite + private const string _NOTO_SANS_ARABIC_BOLD = "NotoSansArabic-Bold"; + private const string _NOTO_SANS_ARABIC_REGULAR = "NotoSansArabic-Regular"; + private const string _NOTO_SANS_JP_BOLD = "NotoSansJP-Bold"; + private const string _NOTO_SANS_KR_REGULAR = "NotoSansKR-Regular"; + private const string _NOTO_SANS_SC_BLACK = "NotoSansSC-Black"; // traditional chinese fortnite + private const string _NOTO_SANS_SC_REGULAR = "NotoSansSC-Regular"; + private const string _NOTO_SANS_TC_BLACK = "NotoSansTC-Black"; // simplified chinese fortnite + private const string _NOTO_SANS_TC_REGULAR = "NotoSansTC-Regular"; + private const string _BURBANK_SMALL_BLACK = "burbanksmall-black"; + private const string _BURBANK_SMALL_BOLD = "burbanksmall-bold"; +#pragma warning restore IDE0051 + + public SKTypeface DefaultTypeface; // used as default font for all untranslated strings (item source, ...) + public SKTypeface BundleDefaultTypeface; // used for the last folder string + public SKTypeface DisplayNameTypeface; + public SKTypeface DescriptionTypeface; + public SKTypeface BundleDisplayNameTypeface; + + public Typefaces() + { + DefaultTypeface = SKTypeface.FromStream(Application.GetResourceStream(_BURBANK_BIG_CONDENSED_BOLD).Stream); + + ArraySegment[] t = Utils.GetPropertyArraySegmentByte(_BASE_PATH + _BURBANK_BIG_CONDENSED_BLACK); + if (t != null && t.Length == 3) + BundleDefaultTypeface = SKTypeface.FromStream(t[2].AsStream()); + else BundleDefaultTypeface = DefaultTypeface; + + string namePath = _BASE_PATH + ( + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Korean ? _ASIA_ERINM : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Russian ? _BURBANK_BIG_REGULAR_BOLD : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Japanese ? _NIS_JYAU : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Arabic ? _NOTO_SANS_ARABIC_BLACK : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.TraditionalChinese ? _NOTO_SANS_SC_BLACK : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Chinese ? _NOTO_SANS_TC_BLACK : + string.Empty); + if (!namePath.Equals(_BASE_PATH)) + { + t = Utils.GetPropertyArraySegmentByte(namePath); + if (t != null && t.Length == 3) + DisplayNameTypeface = SKTypeface.FromStream(t[2].AsStream()); + } + else DisplayNameTypeface = DefaultTypeface; + + string descriptionPath = _BASE_PATH + ( + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Korean ? _NOTO_SANS_KR_REGULAR : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Japanese ? _NOTO_SANS_JP_BOLD : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Arabic ? _NOTO_SANS_ARABIC_REGULAR : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.TraditionalChinese ? _NOTO_SANS_SC_REGULAR : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Chinese ? _NOTO_SANS_TC_REGULAR : + _NOTO_SANS_REGULAR); + t = Utils.GetPropertyArraySegmentByte(descriptionPath); + if (t != null && t.Length == 3) + DescriptionTypeface = SKTypeface.FromStream(t[2].AsStream()); + else DescriptionTypeface = DefaultTypeface; + + string bundleNamePath = _BASE_PATH + ( + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Korean ? _ASIA_ERINM : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Russian ? _BURBANK_BIG_REGULAR_BOLD : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Japanese ? _NIS_JYAU : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Arabic ? _NOTO_SANS_ARABIC_BLACK : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.TraditionalChinese ? _NOTO_SANS_SC_BLACK : + Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Chinese ? _NOTO_SANS_TC_BLACK : + string.Empty); + if (!bundleNamePath.Equals(_BASE_PATH)) + { + t = Utils.GetPropertyArraySegmentByte(bundleNamePath); + if (t != null && t.Length == 3) + BundleDisplayNameTypeface = SKTypeface.FromStream(t[2].AsStream()); + } + else BundleDisplayNameTypeface = BundleDefaultTypeface; + } + + public bool NeedReload(bool forceReload) => forceReload ? + DataGridVm.dataGridViewModel.Count > 0 : //reload only if at least one pak is loaded + DataGridVm.dataGridViewModel.Count > 0 && (BundleDefaultTypeface == DefaultTypeface && DisplayNameTypeface == DefaultTypeface && DescriptionTypeface == DefaultTypeface && BundleDisplayNameTypeface == BundleDefaultTypeface); + } +} diff --git a/FModel/Creator/Utils.cs b/FModel/Creator/Utils.cs new file mode 100644 index 00000000..5b18e873 --- /dev/null +++ b/FModel/Creator/Utils.cs @@ -0,0 +1,78 @@ +using FModel.Utils; +using PakReader.Pak; +using PakReader.Parsers.Class; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; +using System; + +namespace FModel.Creator +{ + static class Utils + { + public static string GetFullPath(string partialPath) + { + foreach (var fileReader in Globals.CachedPakFiles.Values) + if (fileReader.TryGetPartialKey(partialPath, out var fullPath)) + { + return fullPath; + } + return string.Empty; + } + + public static PakPackage GetPropertyPakPackage(string value) + { + string path = Strings.FixPath(value); + foreach (var fileReader in Globals.CachedPakFiles.Values) + if (fileReader.TryGetValue(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); + } + return default; + } + + public static ArraySegment[] GetPropertyArraySegmentByte(string value) + { + string path = Strings.FixPath(value); + foreach (var fileReader in Globals.CachedPakFiles.Values) + if (fileReader.TryGetValue(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; + } + + public static SKBitmap NewZeroedBitmap(int width, int height) => new SKBitmap(new SKImageInfo(width, height), SKBitmapAllocFlags.ZeroPixels); + public static SKBitmap Resize(this SKBitmap me, int width, int height) + { + var bmp = NewZeroedBitmap(width, height); + using var pixmap = bmp.PeekPixels(); + me.ScalePixels(pixmap, SKFilterQuality.Medium); + return bmp; + } + + public static SKBitmap GetObjectTexture(ObjectProperty o) => GetTexture(o.Value.Resource.OuterIndex.Resource.ObjectName.String); + public static SKBitmap GetSoftObjectTexture(SoftObjectProperty s) => GetTexture(s.Value.AssetPathName.String); + public static SKBitmap GetTexture(string s) + { + PakPackage p = GetPropertyPakPackage(s); + if (p.HasExport() && !p.Equals(default)) + { + var i = p.GetExport(); + if (i != null) + return SKBitmap.Decode(i.Image.Encode()); + + var u = p.GetExport(); + if (u != null) + if (u.TryGetValue("TextureParameterValues", out var v) && v is ArrayProperty a) + if (a.Value.Length > 0 && a.Value[0] is StructProperty str && str.Value is UObject o) + if (o.TryGetValue("ParameterValue", out var obj) && obj is ObjectProperty parameterValue) + return GetObjectTexture(parameterValue); + } + return null; + } + } +} diff --git a/FModel/Discord/DiscordIntegration.cs b/FModel/Discord/DiscordIntegration.cs new file mode 100644 index 00000000..3e8ed8ab --- /dev/null +++ b/FModel/Discord/DiscordIntegration.cs @@ -0,0 +1,66 @@ +using DiscordRPC; +using DiscordRPC.Logging; +using FModel.Logger; +using System; +using System.Reflection; + +namespace FModel.Discord +{ + static class DiscordIntegration + { + private const string _DISCORD_APP_ID = "684489366189768767"; + + private static readonly Timestamps _baseTimestamp = new Timestamps { Start = DateTime.UtcNow }; + private static readonly Assets _assets = new Assets + { + LargeImageKey = "official_logo", + SmallImageKey = "verified", + SmallImageText = $"v{Assembly.GetExecutingAssembly().GetName().Version.ToString().Substring(0, 5)}" + }; + private static readonly DiscordRpcClient _client = new DiscordRpcClient(_DISCORD_APP_ID); + private static RichPresence _presence; + + public static void Dispose() => _client.Dispose(); + private static void Initialize() + { + _client.Logger = new ConsoleLogger() { Level = LogLevel.Warning }; + _client.OnReady += (sender, e) => + { + DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Discord RPC]", $"Ready for {e.User.Username}#{e.User.Discriminator} ({e.User.ID})"); + }; + _client.Initialize(); + } + + public static void StartClient() + { + _client.SetPresence(new RichPresence + { + Assets = _assets, + Timestamps = _baseTimestamp, + State = Properties.Resources.Idling + }); + Initialize(); + SaveCurrentPresence(); + } + + public static void Update(string detail = null, string state = null) + { + _client.SetPresence(new RichPresence + { + Assets = _assets, + Timestamps = _baseTimestamp, + Details = string.IsNullOrEmpty(detail) ? _presence.Details : detail, + State = string.IsNullOrEmpty(state) ? _presence.State : state + }); + _client.Invoke(); + } + + public static void Restore() + { + _client.SetPresence(_presence); + _client.Invoke(); + } + + public static void SaveCurrentPresence() => _presence = _client.CurrentPresence; + } +} diff --git a/FModel/Enums.cs b/FModel/Enums.cs new file mode 100644 index 00000000..2e924931 --- /dev/null +++ b/FModel/Enums.cs @@ -0,0 +1,60 @@ +namespace FModel +{ + public enum EGame + { + Unknown, + Fortnite, + Valorant + } + + public enum EFModel + { + Debug, + Release, + Unknown + } + + public enum EPakLoader + { + Single, + All, + New, + Modified, + NewModified + } + + public enum ECopy + { + Path, + PathNoExt, + File, + FileNoExt + } + + public enum ELanguage : long + { + English, + French, + German, + Italian, + Spanish, + SpanishLatin, + Arabic, + Japanese, + Korean, + Polish, + PortugueseBrazil, + Russian, + Turkish, + Chinese, + TraditionalChinese + } + + public enum EIconDesign : long + { + Default, + NoText, + Mini, + Flat + } +} diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index 00de34d5..90127e46 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -1,634 +1,236 @@ - - - + + - Debug - AnyCPU - {8AAB27BD-18D7-4164-8BBC-AB534D55D30F} WinExe - FModel - FModel - v4.7.2 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - true - true - - - - false - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true + netcoreapp3.1 + true + FModel.ico + FModel.App + Asval + + 3.1.0.0 + 3.1.0.0 + FModel.ico + + https://github.com/iAmAsval/FModel + + 3.1.0 + x64 - + + x64 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 true - 7.1 + 1701;1702;NU1701 - + + x64 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 true - false - 7.1 - - - Logo.ico - - - FModel.Program + 1701;1702;NU1701 + - - ..\packages\Autoupdater.NET.Official.1.5.8\lib\net40\AutoUpdater.NET.dll - - - ..\packages\HtmlAgilityPack.1.11.17\lib\Net45\HtmlAgilityPack.dll - - - ..\packages\AvalonEdit.6.0.0\lib\net45\ICSharpCode.AvalonEdit.dll - - - ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll - - - ..\packages\Ookii.Dialogs.Wpf.1.1.0\lib\net45\Ookii.Dialogs.Wpf.dll - - - ..\packages\RestSharp.106.6.10\lib\net452\RestSharp.dll - - - ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll - - - - ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll - - - - - - ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll - - - - ..\packages\System.Numerics.Vectors.4.6.0-preview5.19224.8\lib\net46\System.Numerics.Vectors.dll - - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll - - - - - - - - - - - - 4.0 - - - - - - ..\packages\WriteableBitmapEx.1.6.3\lib\net40\WriteableBitmapEx.Wpf.dll - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + - - MSBuild:Compile - Designer - - - - AESManager.xaml - - - - - - - ColorPickerControl.xaml - - - - ColorPickerSwatch.xaml - - - ColorPickerWindow.xaml - - - ColorPickRow.xaml - - - SliderRow.xaml - - - FModel_About.xaml - - - FModel_CustomMB.xaml - - - FModel_ImagesMerger.xaml - - - FModel_SearchFiles.xaml - - - FModel_Settings.xaml - - - FModel_UpdateMode.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FindReplaceWindow.xaml - - - FindWindow.xaml - - - GiveByteWindow.xaml - - - HexBox.xaml - - - - HexEditor.xaml - - - HexViewer.xaml - - - ReplaceByteWindow.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - FindReplaceDialog.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True Resources.resx - - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - FModel_Main.xaml - Code - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - - - Code - - + + True True Settings.settings - True - + + + + PublicResXFileCodeGenerator Resources.Designer.cs - - - - - - - SettingsSingleFileGenerator + + + + + PublicSettingsSingleFileGenerator Settings.Designer.cs - - - - - - - - - - - - - - - - - False - Microsoft .NET Framework 4.7.2 %28x86 et x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - %(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension) - - - - - - - Ce projet fait référence à des packages NuGet qui sont manquants sur cet ordinateur. Utilisez l'option de restauration des packages NuGet pour les télécharger. Pour plus d'informations, consultez http://go.microsoft.com/fwlink/?LinkID=322105. Le fichier manquant est : {0}. - - - \ No newline at end of file diff --git a/FModel/FModel.ico b/FModel/FModel.ico new file mode 100644 index 0000000000000000000000000000000000000000..20fb9834f34e69221c918b6dc8e925ac3289f7e6 GIT binary patch literal 48051 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 z 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 i6Gxh~I@AFG@c#p%AQkkgiF_0Q0000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -