void UPhysicsSettings::LoadSurfaceType() { // read "SurfaceType" defines and set meta data for the enum // find the enum UEnum * Enum = FindObject<UEnum>(ANY_PACKAGE, TEXT("EPhysicalSurface"), true); // we need this Enum check(Enum); const FString KeyName = TEXT("DisplayName"); const FString HiddenMeta = TEXT("Hidden"); const FString UnusedDisplayName = TEXT("Unused"); // remainders, set to be unused for(int32 EnumIndex=1; EnumIndex<Enum->NumEnums(); ++EnumIndex) { // if meta data isn't set yet, set name to "Unused" until we fix property window to handle this // make sure all hide and set unused first // if not hidden yet if(!Enum->HasMetaData(*HiddenMeta, EnumIndex)) { Enum->SetMetaData(*HiddenMeta, TEXT(""), EnumIndex); Enum->SetMetaData(*KeyName, *UnusedDisplayName, EnumIndex); } } for(auto Iter=PhysicalSurfaces.CreateConstIterator(); Iter; ++Iter) { // @todo only for editor Enum->SetMetaData(*KeyName, *Iter->Name.ToString(), Iter->Type); // also need to remove "Hidden" Enum->RemoveMetaData(*HiddenMeta, Iter->Type); } }
void USoundGroups::Initialize() const { for (int32 ProfileIndex = 0; ProfileIndex < SoundGroupProfiles.Num(); ++ProfileIndex) { SoundGroupMap.Add(SoundGroupProfiles[ProfileIndex].SoundGroup, SoundGroupProfiles[ProfileIndex]); } if (!SoundGroupMap.Find(SOUNDGROUP_Default)) { UE_LOG(LogAudio, Warning, TEXT("Missing default SoundGroup profile. Creating default with no decompression.")); SoundGroupMap.Add(SOUNDGROUP_Default, FSoundGroup()); } #if WITH_EDITOR UEnum* SoundGroupEnum = FindObjectChecked<UEnum>(NULL, TEXT("/Script/Engine.ESoundGroup")); for (const auto& It : SoundGroupMap) { if (It.Value.DisplayName.Len() > 0) { SoundGroupEnum->SetMetaData(TEXT("DisplayName"), *It.Value.DisplayName, It.Key); SoundGroupEnum->RemoveMetaData(TEXT("Hidden"), It.Key); } else { if (SoundGroupEnum->HasMetaData(TEXT("Hidden"), It.Key)) { UE_LOG(LogAudio, Warning, TEXT("Custom Game SoundGroup profile for %s defined but no display name supplied."), *SoundGroupEnum->GetEnumText(It.Key).ToString()); } SoundGroupEnum->RemoveMetaData(TEXT("Hidden"), It.Key); } } #endif }
UEnum* FEnumEditorUtils::CreateUserDefinedEnum(UObject* InParent, FName EnumName, EObjectFlags Flags) { ensure(0 != (RF_Public & Flags)); UEnum* Enum = NewObject<UUserDefinedEnum>(InParent, EnumName, Flags); if (NULL != Enum) { TArray<TPair<FName, int8>> EmptyNames; Enum->SetEnums(EmptyNames, UEnum::ECppForm::Namespaced); Enum->SetMetaData(TEXT("BlueprintType"), TEXT("true")); } return Enum; }
void UCollisionProfile::LoadProfileConfig(bool bForceInit) { /** * This function loads all config data to memory * * 1. First it fixes the meta data for each custom channel name since those meta data is used for #2 * 2. Load Default Profile so that it can be used later * 3. Second it sets up Correct ResponseToChannel for all profiles * 4. It loads profile redirect data **/ // read "EngineTraceChanne" and "GameTraceChanne" and set meta data FConfigSection* Configs = GConfig->GetSectionPrivate( TEXT("/Script/Engine.CollisionProfile"), false, true, GEngineIni ); // before any op, verify if profiles contains invalid name - such as Custom profile name - remove all of them for (auto Iter=Profiles.CreateConstIterator(); Iter; ++Iter) { // make sure it doens't have any if (Iter->Name == CustomCollisionProfileName) { UE_LOG(LogCollisionProfile, Error, TEXT("Profiles contain invalid name : %s is reserved for internal use"), *CustomCollisionProfileName.ToString()); Profiles.RemoveAt(Iter.GetIndex()); } } // 1. First loads all meta data for custom channels // this can be used in #2, so had to fix up first // this is to replace ECollisionChannel's DisplayName to be defined by users FString EngineTraceChannel = TEXT("EngineTraceChannel"); FString GameTraceChannel = TEXT("GameTraceChannel"); // find the enum UEnum* Enum = FindObject<UEnum>(ANY_PACKAGE, TEXT("ECollisionChannel"), true); // we need this Enum check (Enum); UStruct* Struct = FCollisionResponseContainer::StaticStruct(); check (Struct); const FString KeyName = TEXT("DisplayName"); const FString TraceType = TEXT("TraceQuery"); const FString TraceValue = TEXT("1"); const FString HiddenMeta = TEXT("Hidden"); // need to initialize displaynames separate int32 NumEnum = Enum->NumEnums(); ChannelDisplayNames.Empty(NumEnum); ChannelDisplayNames.AddZeroed(NumEnum); TraceTypeMapping.Empty(); ObjectTypeMapping.Empty(); // first go through enum entry, and add suffix to displaynames int32 PrefixLen = FString(TEXT("ECC_")).Len(); // need to have mapping table between ECollisionChannel and EObjectTypeQuery/ETraceTypeQuery UEnum* ObjectTypeEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT("EObjectTypeQuery"), true); UEnum* TraceTypeEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT("ETraceTypeQuery"), true); check (ObjectTypeEnum && TraceTypeEnum); for ( int32 EnumIndex=0; EnumIndex<NumEnum; ++EnumIndex ) { FString EnumName = Enum->GetEnumName(EnumIndex); EnumName = EnumName.RightChop(PrefixLen); FName DisplayName = FName(*EnumName); if ( IS_VALID_COLLISIONCHANNEL(EnumIndex) ) { // verify if the Struct name matches // this is to avoid situations where they mismatch and causes random bugs UField* Field = FindField<UField>(Struct, DisplayName); if (!Field) { // error - this is bad. This means somebody changed variable name without changing channel enum UE_LOG(LogCollisionProfile, Error, TEXT("Variable (%s) isn't found for Channel (%s). \nPlease make sure you name matches between ECollisionChannel and FCollisionResponseContainer."), *DisplayName.ToString(), *EnumName); } #if WITH_EDITOR // clear displayname since we're setting it in below Enum->RemoveMetaData(*KeyName, EnumIndex); if (Enum->HasMetaData(*HiddenMeta, EnumIndex) == false) { Enum->SetMetaData(*HiddenMeta, NULL, EnumIndex); } #endif } else { // fix up FCollisionQueryFlag AllObjects flag, if trace type=1 ECollisionChannel CollisionChannel = (ECollisionChannel)EnumIndex; // for any engine level collision profile, we hard coded here // meta data doesn't work in cooked build, so we'll have to manually handle them if ((CollisionChannel == ECC_Visibility) || (CollisionChannel == ECC_Camera)) { // remove from object query flags FCollisionQueryFlag::Get().RemoveFromAllObjectsQueryFlag(CollisionChannel); TraceTypeMapping.Add(CollisionChannel); } else if ( CollisionChannel < ECC_OverlapAll_Deprecated ) { ObjectTypeMapping.Add(CollisionChannel); } } ChannelDisplayNames[EnumIndex] = DisplayName; } // Now Load Channel setups, and set display names if customized // also initialize DefaultResposneContainer with default response for each channel FCollisionResponseContainer::DefaultResponseContainer.SetAllChannels(ECR_Block); for (auto Iter=DefaultChannelResponses.CreateConstIterator(); Iter; ++Iter) { const FCustomChannelSetup& CustomChannel = *Iter; int32 EnumIndex = CustomChannel.Channel; // make sure it is the range of channels we allow to change if ( IS_VALID_COLLISIONCHANNEL(EnumIndex) ) { if ( CustomChannel.Name != NAME_None ) { // before you set meta data, you'll have to save this value to modify // ECollisionResponseContainer variables meta data FString VariableName = ChannelDisplayNames[EnumIndex].ToString(); FString DisplayValue = CustomChannel.Name.ToString(); // also has to set this for internal use ChannelDisplayNames[EnumIndex] = FName(*DisplayValue); #if WITH_EDITOR // set displayvalue for this enum entry Enum->SetMetaData(*KeyName, *DisplayValue, EnumIndex); // also need to remove "Hidden" Enum->RemoveMetaData(*HiddenMeta, EnumIndex); #endif // now add MetaData type for trace type if it does if (CustomChannel.bTraceType) { #if WITH_EDITOR // add to enum Enum->SetMetaData(*TraceType, *TraceValue, EnumIndex); #endif // remove from all object queries FCollisionQueryFlag::Get().RemoveFromAllObjectsQueryFlag(CustomChannel.Channel); TraceTypeMapping.Add(CustomChannel.Channel); } // if it has display value else { #if WITH_EDITOR // add to enum Enum->RemoveMetaData(*TraceType, EnumIndex); #endif ObjectTypeMapping.Add(CustomChannel.Channel); if (CustomChannel.bStaticObject) { // add to static object FCollisionQueryFlag::Get().AddToAllStaticObjectsQueryFlag(CustomChannel.Channel); } } #if WITH_EDITOR // now enum is fixed, so find member variable for the field UField* Field = FindField<UField>(Struct, FName(*VariableName)); // I verified up in the class, this can't happen check (Field); Field->SetMetaData(*KeyName, *DisplayValue); #endif } else { // missing name UE_LOG(LogCollisionProfile, Warning, TEXT("Name can't be empty for Channel (%d) "), EnumIndex ); } // allow it to set default response FCollisionResponseContainer::DefaultResponseContainer.SetResponse((ECollisionChannel) EnumIndex, CustomChannel.DefaultResponse); } else { // you can't customize those channels UE_LOG(LogCollisionProfile, Warning, TEXT("Default Setup doesn't allow for predefined engine channels (%d) "), EnumIndex); } } #if WITH_EDITOR // now propagate all changes to the channels to EObjectTypeQuery and ETraceTypeQuery for blueprint accessibility // this code is to show in editor more friendly, so it doesn't have to be set if it's not for editor int32 ObjectTypeEnumIndex = 0; int32 TraceTypeEnumIndex = 0; // first go through fill up ObjectType Enum for ( int32 EnumIndex=0; EnumIndex<NumEnum; ++EnumIndex ) { // if not hidden const FString& Hidden = Enum->GetMetaData(*HiddenMeta, EnumIndex); if ( Hidden.IsEmpty() ) { const FString& DisplayName = Enum->GetMetaData(*KeyName, EnumIndex); if ( !DisplayName.IsEmpty() ) { // find out trace type or object type if (Enum->GetMetaData(*TraceType, EnumIndex) == TraceValue) { TraceTypeEnum->RemoveMetaData(*HiddenMeta, TraceTypeEnumIndex); TraceTypeEnum->SetMetaData(*KeyName, *DisplayName, TraceTypeEnumIndex); ++TraceTypeEnumIndex; } else { ObjectTypeEnum->RemoveMetaData(*HiddenMeta, ObjectTypeEnumIndex); ObjectTypeEnum->SetMetaData(*KeyName, *DisplayName, ObjectTypeEnumIndex); ++ObjectTypeEnumIndex; } } } } // make sure TraceTypeEnumIndex matches TraceTypeMapping check (TraceTypeMapping.Num() == TraceTypeEnumIndex); check (ObjectTypeMapping.Num() == ObjectTypeEnumIndex); #endif // collision redirector has to be loaded before profile CollisionChannelRedirectsMap.Empty(); for(auto Iter = CollisionChannelRedirects.CreateConstIterator(); Iter; ++Iter) { FName OldName = Iter->OldName; FName NewName = Iter->NewName; // at least we need to have OldName if(OldName!= NAME_None && NewName != NAME_None) { // add to pair CollisionChannelRedirectsMap.Add(OldName, NewName); } else { // print error UE_LOG(LogCollisionProfile, Warning, TEXT("CollisionChannel Redirects : Name Can't be none (%s: %s)"), *OldName.ToString(), *NewName.ToString()); } } // 2. Second loads all set up back to ResponseToChannels // this does a lot of iteration, but this only happens once loaded, so it's better to be convenient than efficient // fill up Profiles data FillProfileData(Profiles, Enum, KeyName, EditProfiles); // 3. It loads redirect data - now time to load profile redirect ProfileRedirectsMap.Empty(); // handle profile redirect here for(auto Iter = ProfileRedirects.CreateConstIterator(); Iter; ++Iter) { FName OldName = Iter->OldName; FName NewName = Iter->NewName; // at least we need to have OldName if(OldName!= NAME_None && NewName != NAME_None) { FCollisionResponseTemplate Template; // make sure the template exists if(FindProfileData(Profiles, NewName, Template)) { // add to pair ProfileRedirectsMap.Add(OldName, NewName); } else { // print error UE_LOG(LogCollisionProfile, Warning, TEXT("ProfileRedirect (%s : %s) - New Name (\'%s\') isn't found "), *OldName.ToString(), *NewName.ToString(), *NewName.ToString()); } } } #if WITH_EDITOR if (bForceInit) { // go through objects, and see if we can reinitialize profile for(TObjectIterator<UPrimitiveComponent> PrimIt; PrimIt; ++PrimIt) { PrimIt->UpdateCollisionProfile(); } } #endif }
void UGatherTextFromMetaDataCommandlet::GatherTextFromUObject(UField* const Field, const FGatherParameters& Arguments) { // Gather for object. { if( !Field->HasMetaData( TEXT("DisplayName") ) ) { Field->SetMetaData( TEXT("DisplayName"), *FName::NameToDisplayString( Field->GetName(), Field->IsA( UBoolProperty::StaticClass() ) ) ); } for(int32 i = 0; i < Arguments.InputKeys.Num(); ++i) { FFormatNamedArguments PatternArguments; PatternArguments.Add( TEXT("FieldPath"), FText::FromString( Field->GetFullGroupName(false) ) ); if( Field->HasMetaData( *Arguments.InputKeys[i] ) ) { const FString& MetaDataValue = Field->GetMetaData(*Arguments.InputKeys[i]); if( !MetaDataValue.IsEmpty() ) { PatternArguments.Add( TEXT("MetaDataValue"), FText::FromString(MetaDataValue) ); const FString Namespace = Arguments.OutputNamespaces[i]; FLocItem LocItem(MetaDataValue); FManifestContext Context; Context.Key = FText::Format(Arguments.OutputKeys[i], PatternArguments).ToString(); Context.SourceLocation = FString::Printf(TEXT("From metadata for key %s of member %s in %s"), *Arguments.InputKeys[i], *Field->GetName(), *Field->GetFullGroupName(true)); GatherManifestHelper->AddSourceText(Namespace, LocItem, Context); } } } } // For enums, also gather for enum values. { UEnum* Enum = Cast<UEnum>(Field); if(Enum) { const int32 ValueCount = Enum->NumEnums(); for(int32 i = 0; i < ValueCount; ++i) { if( !Enum->HasMetaData(TEXT("DisplayName"), i) ) { Enum->SetMetaData(TEXT("DisplayName"), *FName::NameToDisplayString(Enum->GetEnumName(i), false), i); } for(int32 j = 0; j < Arguments.InputKeys.Num(); ++j) { FFormatNamedArguments PatternArguments; PatternArguments.Add( TEXT("FieldPath"), FText::FromString( Enum->GetFullGroupName(false) + TEXT(".") + Enum->GetEnumName(i) ) ); if( Enum->HasMetaData(*Arguments.InputKeys[j], i) ) { const FString& MetaDataValue = Enum->GetMetaData(*Arguments.InputKeys[j], i); if( !MetaDataValue.IsEmpty() ) { PatternArguments.Add( TEXT("MetaDataValue"), FText::FromString(MetaDataValue) ); const FString Namespace = Arguments.OutputNamespaces[j]; FLocItem LocItem(MetaDataValue); FManifestContext Context; Context.Key = FText::Format(Arguments.OutputKeys[j], PatternArguments).ToString(); Context.SourceLocation = FString::Printf(TEXT("From metadata for key %s of enum value %s of enum %s in %s"), *Arguments.InputKeys[j], *Enum->GetEnumName(i), *Enum->GetName(), *Enum->GetFullGroupName(true)); GatherManifestHelper->AddSourceText(Namespace, LocItem, Context); } } } } } } }