Finished naming script first implementation

This commit is contained in:
Roel Algaba Brizuela 2021-02-25 12:51:54 +01:00 committed by bernat
parent bf82f09a31
commit 69a0da33a4
2 changed files with 416 additions and 0 deletions

View File

@ -0,0 +1,325 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "NamingScript.h"
#include "Animation/AnimBlueprint.h"
#include "Animation/AnimSequence.h"
#include "Engine/SkeletalMesh.h"
#include "Engine/Texture.h"
#include "Engine/TextureCube.h"
#include "HAL/FileManager.h"
#include "Materials/MaterialParameterCollection.h"
#include "Particles/ParticleSystem.h"
UNamingScript::UNamingScript(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer) {
InitializeContainers();
TexSuffMsg = "----------------------------------\n"
"Texture suffixes you should use\n"
"----------------------------------\n"
"Diffuse / Albedo / Base Color = _D\n"
"Normal = _N\n"
"Roughness = _R\n"
"Alpha / Opacity = _A\n"
"Ambient Occlusion = _O\n"
"Bump = _B\n"
"Emissive = _E\n"
"Mask = _M\n"
"Specular = _S\n"
"Metallic = _M\n"
"Occlusion, roughness, metallic = _ORM\n"
"SubSurface Scattering = _SSS\n";
}
void UNamingScript::InitializeContainers() {
TextureSuffixes.Add("_D");
TextureSuffixes.Add("_N");
TextureSuffixes.Add("_R");
TextureSuffixes.Add("_A");
TextureSuffixes.Add("_O");
TextureSuffixes.Add("_B");
TextureSuffixes.Add("_E");
TextureSuffixes.Add("_M");
TextureSuffixes.Add("_S");
TextureSuffixes.Add("_M");
TextureSuffixes.Add("_ORM");
TextureSuffixes.Add("_SSS");
}
void UNamingScript::FlushData() {
AssetFilenames.Empty();
AssetData.Empty();
MessageLog.Empty();
}
bool UNamingScript::LoadDataFromPath(const FString &Path) {
//Load the modules
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(FName("AssetRegistry"));
IFileManager &FileManager = IFileManager::Get();
//Scan directories recursively from disk in order to access assets
FString FullPath = FileManager.ConvertToAbsolutePathForExternalAppForRead(*FPaths::ProjectContentDir());
FullPath /= Path;
//If directory exists, then convert the absolute path
//to in-game path (this is used later for the asset registry module in order to read the assets)
if (FPaths::DirectoryExists(FullPath)) {
FileManager.FindFilesRecursive(AssetFilenames, *FullPath, TEXT("*"), false, true);
if (AssetFilenames.Num() != 0) {
for (int i = 0; i < AssetFilenames.Num(); ++i) {
//Convert from "Content/Carla..." to "Game/Carla..." directory.
//This is needed for the asset registry module
AssetFilenames[i] = AssetFilenames[i].RightChop(AssetFilenames[i].Find("Content", ESearchCase::Type::CaseSensitive, ESearchDir::Type::FromStart) + 7);
FString FinalString = "/Game";
FinalString += AssetFilenames[i];
AssetFilenames[i] = FinalString;
}
}
}
else {
FlushData();
return false;
}
AssetFilenames.Add("/Game/" + Path);
//Scan the obtained filenames for assets
AssetRegistryModule.Get().ScanPathsSynchronous(AssetFilenames);
//Array that will hold all assets found
for (int i = 0; i < AssetFilenames.Num(); ++i) {
AssetRegistryModule.Get().GetAssetsByPath(*AssetFilenames[i], AssetData);
}
return true;
}
void UNamingScript::ValidateAssetName(const FString &AssetPath, const FString &AssetName, const AssetTypes &AssetType, const FString &ValidAssetName, const FString &ValidPrefix, bool bUsesSuffix) {
if (AssetName.IsEmpty() == true) {
//Do something else?
return;
}
MessageLog.Add(TPair<FText, EMessageSeverity::Type>(FText::FromString("Validating name : " + AssetName), EMessageSeverity::Type::Info));
MessageLog.Add(TPair<FText, EMessageSeverity::Type>(FText::FromString(AssetPath), EMessageSeverity::Type::CriticalError));
bool IsValid = true;
int CharOcurrences = 0;
for (int i = 0; i < AssetName.GetCharArray().Num(); ++i) {
if (AssetName.GetCharArray()[i] == '_') {
++CharOcurrences;
}
}
if (CharOcurrences < 1 || CharOcurrences > 3) {
MessageLog.Add(TPair<FText, EMessageSeverity::Type>(FText::FromString("The name of the asset should only have between 1 or 3 '_' characters"), EMessageSeverity::Type::Error));
MessageLog.Add(TPair<FText, EMessageSeverity::Type>(FText::FromString("The name of the asset is invalid. You should use : " + ValidAssetName), EMessageSeverity::Type::Error));
return;
}
bool FoundCharacter = false;
FString CurrentAssetPrefix;
for (int i = 0; i < AssetName.Len() && FoundCharacter == false; ++i) {
if (AssetName[i] != '_') {
CurrentAssetPrefix += AssetName[i];
}
else {
CurrentAssetPrefix += AssetName[i];
FoundCharacter = true;
}
}
//Validate the prefix of the asset
if (ValidPrefix.Equals(CurrentAssetPrefix, ESearchCase::CaseSensitive) == false) {
if (ValidPrefix.Equals(CurrentAssetPrefix.ToUpper(), ESearchCase::CaseSensitive) == true) {
MessageLog.Add(TPair<FText, EMessageSeverity::Type>(FText::FromString("The prefix of the asset is correct but must in uppercase " + ValidPrefix.ToUpper()), EMessageSeverity::Type::Error));
}
else {
MessageLog.Add(TPair<FText, EMessageSeverity::Type>(FText::FromString("The name of the asset must have prefix " + ValidPrefix), EMessageSeverity::Type::Error));
}
IsValid = false;
}
//Validate the suffix of the asset if it uses any
if (bUsesSuffix == true) {
FString CurrentAssetSuffix = AssetName.RightChop(AssetName.Find("_", ESearchCase::CaseSensitive, ESearchDir::FromEnd));
FString *SearchResult = NULL;
if (AssetType == AssetTypes::Texture) {
SearchResult = TextureSuffixes.Find(CurrentAssetSuffix);
}
else {
UE_LOG(LogTemp, Error, TEXT("Asset uses suffix but it's not recognized"));
return;
}
//Keys in a set are NOT case sensitive. That's why "_n" might be found in the set, which in reality is "_N"
if (SearchResult != NULL && SearchResult->Equals(CurrentAssetSuffix, ESearchCase::CaseSensitive) == false) {
if (SearchResult->Equals(CurrentAssetSuffix.ToUpper()) == true) {
MessageLog.Add(TPair<FText, EMessageSeverity::Type>(FText::FromString("The suffix of the asset is correct but must be in uppercase " + CurrentAssetSuffix.ToUpper()), EMessageSeverity::Type::Error));
}
else {
MessageLog.Add(TPair<FText, EMessageSeverity::Type>(FText::FromString("The name of the asset has invalid suffix " + CurrentAssetSuffix), EMessageSeverity::Type::Error));
}
IsValid = false;
}
else if (SearchResult == NULL) {
MessageLog.Add(TPair<FText, EMessageSeverity::Type>(FText::FromString("The name of the asset has invalid suffix " + CurrentAssetSuffix), EMessageSeverity::Type::Error));
IsValid = false;
}
}
if (IsValid == false) {
MessageLog.Add(TPair<FText, EMessageSeverity::Type>(FText::FromString("The name of the asset is invalid. You should use : " + ValidAssetName), EMessageSeverity::Type::Error));
}
else {
MessageLog.Add(TPair<FText, EMessageSeverity::Type>(FText::FromString("The name of the asset seems to be valid but you should check that base name of the asset and the variant use capital letters : " + ValidAssetName), EMessageSeverity::Type::Warning));
}
}
void UNamingScript::IdentifyAndCheckAssets() {
for (int i = 0; i < AssetData.Num(); ++i) {
if (AssetFilters.bScanForTextures == true) {
if (Cast<UTexture>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::Texture, "T_BaseAssetName_VariantOrVersionIfAny_TextureSuffix", "T_", true);
}
else if (Cast<UTexture2D>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::Texture, "T_BaseAssetName_VariantOrVersionIfAny_TextureSuffix", "T_", true);
}
else if (Cast<UTextureCube>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::TextureCube, "TC_BaseAssetName_VariantOrVersionIfAny_TextureSuffix", "TC_", false);
}
}
if (AssetFilters.bScanForMaterials == true) {
if (Cast<UMaterial>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::Material, "M_BaseAssetName_VariantOrVersionIfAny", "M_", false);
}
else if (Cast<UMaterialInstance>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::MaterialInstance, "MI_BaseAssetName_VariantOrVersionIfAny", "MI_", false);
}
else if (Cast<UMaterialParameterCollection>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::MaterialParameterCollection, "MPC_BaseAssetName_VariantOrVersionIfAny", "MPC_", false);
}
else if (Cast<UMaterialFunctionInterface>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::MaterialFunction, "MF_BaseAssetName_VariantOrVersionIfAny", "MF_", false);
}
}
if (AssetFilters.bScanForParticles == true) {
if (Cast<UParticleSystem>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::ParticleSystem, "PS_BaseAssetName_VariantOrVersionIfAny", "PS_", false);
}
}
if (AssetFilters.bScanForAnimations == true) {
if (Cast<UAnimBlueprint>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::AnimationBlueprint, "ABP_BaseAssetName_VariantOrVersionIfAny", "ABP_", false);
}
else if (Cast<UAnimSequence>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::AnimationSequence, "A_BaseAssetName_VariantOrVersionIfAny", "A_", false);
}
}
if (AssetFilters.bScanForMeshes == true) {
if (Cast<UStaticMesh>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::StaticMesh, "S_BaseAssetName_VariantOrVersionIfAny", "S_", false);
}
else if (Cast<USkeletalMesh>(AssetData[i].GetAsset())) {
ValidateAssetName(AssetData[i].PackageName.ToString(), AssetData[i].AssetName.ToString(), AssetTypes::SkeletalMesh, "SK_BaseAssetName_VariantOrVersionIfAny", "SK_", false);
}
}
}
}
void UNamingScript::CheckAssetsNaming(FString DirectoryToScan, FFilterAssetsScan AssetsToScan) {
if (LoadDataFromPath(DirectoryToScan) == false) {
return;
}
FMessageLog MessageLogWindow("Naming script");
MessageLogWindow.Open(EMessageSeverity::Info, true);
AssetFilters = AssetsToScan;
if (AssetsToScan.bScanForTextures == true) MessageLogWindow.Message(EMessageSeverity::Info, FText::FromString(TexSuffMsg));
//Function will check the name of the loaded assets from the given path
IdentifyAndCheckAssets();
//Display log errors ocurred during the validation process
MessageLogWindow.Message(EMessageSeverity::Info, FText::FromString("-----------------------------------------"));
MessageLogWindow.Message(EMessageSeverity::Info, FText::FromString("Displaying 'Naming Script' Logging errors"));
MessageLogWindow.Message(EMessageSeverity::Info, FText::FromString("------------------------------------------"));
for (int i = 0; i < MessageLog.Num(); ++i) {
if (MessageLog[i].Value == EMessageSeverity::Type::CriticalError) {
MessageLogWindow.Info()->AddToken(FAssetNameToken::Create(MessageLog[i].Key.ToString()));
}
else {
MessageLogWindow.Message(MessageLog[i].Value, MessageLog[i].Key);
}
}
FlushData();
}

View File

@ -0,0 +1,91 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "UObject/Object.h"
#include "UObject/ScriptMacros.h"
#include "Modules/ModuleManager.h"
#include "AssetRegistryModule.h"
#include "Logging/MessageLog.h"
#include "NamingScript.generated.h"
UENUM()
enum class AssetTypes : uint8{
//Textures
Texture UMETA(DisplayName = "Texture"),
TextureCube UMETA(DisplayName = "TextureCube"),
//Materials
Material UMETA(DisplayName = "Material"),
MaterialFunction UMETA(DisplayName = "Material Function"),
MaterialInstance UMETA(DisplayName = "Material Instance"),
MaterialParameterCollection UMETA(DisplayName = "Material Parameter Collection"),
//Meshes
SkeletalMesh UMETA(DisplayName = "Skeletal Mesh"),
StaticMesh UMETA(DisplayName = "Static Mesh"),
//Animations
AnimationBlueprint UMETA(DisplayName = "Animation Blueprint"),
AnimationSequence UMETA(DisplayName = "Animation Montage"),
//Particles
ParticleSystem UMETA(DisplayName = "Particles System")
};
USTRUCT(BlueprintType)
struct FFilterAssetsScan {
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FFilterAssetsScan")
bool bScanForMaterials = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FFilterAssetsScan")
bool bScanForTextures = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FFilterAssetsScan")
bool bScanForMeshes = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FFilterAssetsScan")
bool bScanForAnimations = false;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "FFilterAssetsScan")
bool bScanForParticles = false;
};
UCLASS(Blueprintable, meta = (ShowWorldContextPin))
class CARLA_API UNamingScript : public UObject
{
GENERATED_BODY()
public:
UNamingScript(const FObjectInitializer& ObjectInitializer);
//*Function used to check the names of the assets at a given directory, filtered by FFilterAssetsScan. This process will take longer as more filters are included.
//*IMPORTANT : The path to the directory should be written as, for example "Game/Carla/Static/TrafficLights"
//@param DirectoryToScan The string path where to scan the assets directory.
//@param AssetsToScan Filter used to indicate which types of assets should be checked. Less filters will make the process faster.
UFUNCTION(BlueprintCallable, Category = "Naming Script")
void CheckAssetsNaming(FString DirectoryToScan, FFilterAssetsScan AssetsToScan);
private:
bool LoadDataFromPath(const FString &Path);
void InitializeContainers();
void FlushData();
void IdentifyAndCheckAssets();
void ValidateAssetName(const FString &AssetPath, const FString &AssetName, const AssetTypes &AssetType, const FString &ValidAssetName, const FString &ValidPrefix, bool bUsesSuffix = false);
TArray<FString> AssetFilenames;
TArray<FAssetData> AssetData;
TArray<TPair<FText, EMessageSeverity::Type>> MessageLog;
TSet<FString> TextureSuffixes;
FString TexSuffMsg;
FFilterAssetsScan AssetFilters;
};