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
}
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);
	}
}
Example #3
0
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
}