DefaultChannelResponses

DefaultChannelResponses

#Overview

name: DefaultChannelResponses

The value of this variable can be defined or overridden in .ini config files. 5 .ini config files referencing this setting variable.

It is referenced in 14 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of DefaultChannelResponses is to define game-specific overrides to default responses for collision channels in Unreal Engine 5. This variable is primarily used for customizing collision behavior in the game’s physics system.

DefaultChannelResponses is mainly utilized by the Collision Profile system, which is part of Unreal Engine’s physics module. It is heavily referenced in the CollisionProfileDetails class, which is responsible for managing and customizing collision profiles in the editor.

The value of this variable is typically set in the project’s configuration files and loaded during engine initialization. It can also be modified through the Collision editor in Unreal Engine’s project settings.

DefaultChannelResponses interacts with other collision-related variables and structures, such as FCollisionResponseContainer and FCustomProfile. It is used to populate TraceTypeMapping and ObjectTypeMapping, which are crucial for the engine’s collision system.

Developers must be aware that:

  1. The order of entries in DefaultChannelResponses is important, as it’s sorted and used to populate other collision-related mappings.
  2. Duplicate channel names are not allowed and will be removed automatically.
  3. The number of custom channels is limited (MAX_CUSTOMCOLLISION_CHANNEL).

Best practices when using this variable include:

  1. Ensure unique names for each custom channel.
  2. Keep the number of custom channels within the allowed limit.
  3. Be cautious when modifying this variable, as it can significantly impact the game’s collision behavior.
  4. Use the Collision editor in the project settings for easier management of custom channels and responses.
  5. Consider the performance implications of adding too many custom collision channels.

#Setting Variables

#References In INI files

Location: <Workspace>/Projects/Lyra/Config/DefaultEngine.ini:205, section: [/Script/Engine.CollisionProfile]

Location: <Workspace>/Projects/Lyra/Config/DefaultEngine.ini:206, section: [/Script/Engine.CollisionProfile]

Location: <Workspace>/Projects/Lyra/Config/DefaultEngine.ini:207, section: [/Script/Engine.CollisionProfile]

Location: <Workspace>/Projects/Lyra/Config/DefaultEngine.ini:208, section: [/Script/Engine.CollisionProfile]

Location: <Workspace>/Projects/Lyra/Config/DefaultEngine.ini:209, section: [/Script/Engine.CollisionProfile]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp:1839

Scope (from outer to inner):

file
function     void FCollisionProfileDetails::RefreshChannelList

Source code excerpt:

		TraceChannelList.Empty();

		for(auto Iter = CollisionProfile->DefaultChannelResponses.CreateIterator(); Iter; ++Iter)
		{
			// only display game channels
			if(Iter->Channel >= ECC_GameTraceChannel1 && Iter->bTraceType)
			{
				TraceChannelList.Add(MakeShareable(new FChannelListItem(MakeShareable(new FCustomChannelSetup(*Iter)))));
			}

#Loc: <Workspace>/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp:1852

Scope (from outer to inner):

file
function     void FCollisionProfileDetails::RefreshChannelList

Source code excerpt:

		ObjectChannelList.Empty();

		for(auto Iter = CollisionProfile->DefaultChannelResponses.CreateIterator(); Iter; ++Iter)
		{
			// only display game channels
			if(Iter->Channel >= ECC_GameTraceChannel1 && !Iter->bTraceType)
			{
				ObjectChannelList.Add(MakeShareable(new FChannelListItem(MakeShareable(new FCustomChannelSetup(*Iter)))));
			}

#Loc: <Workspace>/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp:1887

Scope (from outer to inner):

file
function     void FCollisionProfileDetails::RemoveChannel

Source code excerpt:

void FCollisionProfileDetails::RemoveChannel(ECollisionChannel CollisionChannel) const
{
	for(auto Iter = CollisionProfile->DefaultChannelResponses.CreateIterator(); Iter; ++Iter)
	{
		if(Iter->Channel == CollisionChannel)
		{
			CollisionProfile->DefaultChannelResponses.RemoveAt(Iter.GetIndex());
			break;
		}
	}
}

int32 FCollisionProfileDetails::FindProfileIndexFromName(FName Name) const

#Loc: <Workspace>/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp:1912

Scope (from outer to inner):

file
function     FCustomChannelSetup * FCollisionProfileDetails::FindFromChannel

Source code excerpt:

FCustomChannelSetup * FCollisionProfileDetails::FindFromChannel(ECollisionChannel CollisionChannel) const
{
	for(auto Iter = CollisionProfile->DefaultChannelResponses.CreateIterator(); Iter; ++Iter)
	{
		if(Iter->Channel == CollisionChannel)
		{
			return &(*Iter);
		}
	}

#Loc: <Workspace>/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp:1925

Scope (from outer to inner):

file
function     ECollisionChannel FCollisionProfileDetails::FindAvailableChannel

Source code excerpt:

ECollisionChannel	FCollisionProfileDetails::FindAvailableChannel() const
{
	if(CollisionProfile->DefaultChannelResponses.Num() < MAX_CUSTOMCOLLISION_CHANNEL)
	{
		// this is very inefficient
		for(int32 ChannelIndex = ECC_GameTraceChannel1; ChannelIndex < ECC_GameTraceChannel1 + MAX_CUSTOMCOLLISION_CHANNEL; ++ChannelIndex)
		{
			if( FindFromChannel((ECollisionChannel)ChannelIndex) == NULL)
			{

#Loc: <Workspace>/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp:1942

Scope (from outer to inner):

file
function     bool FCollisionProfileDetails::IsValidChannelSetup

Source code excerpt:

bool	FCollisionProfileDetails::IsValidChannelSetup(const FCustomChannelSetup* Channel) const
{
	for(auto Iter = CollisionProfile->DefaultChannelResponses.CreateConstIterator(); Iter; ++Iter)
	{
		if(Iter->Channel != Channel->Channel)
		{
			// make sure name isn't same
			if(Iter->Name == Channel->Name)
			{

#Loc: <Workspace>/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp:1975

Scope (from outer to inner):

file
function     bool FCollisionProfileDetails::IsNewChannelAvailable

Source code excerpt:

bool	FCollisionProfileDetails::IsNewChannelAvailable() const
{
	return (CollisionProfile && CollisionProfile->DefaultChannelResponses.Num() < MAX_CUSTOMCOLLISION_CHANNEL);
}

FReply FCollisionProfileDetails::OnNewChannel(bool bTraceType)
{
	// find empty channel and see if we can add it. 
	ECollisionChannel NewChannel = FindAvailableChannel();

#Loc: <Workspace>/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp:2014

Scope (from outer to inner):

file
function     FReply FCollisionProfileDetails::OnNewChannel

Source code excerpt:

			ensure(IsValidChannelSetup(&(ChannelEditor->ChannelSetup))))
		{
			CollisionProfile->DefaultChannelResponses.Add(ChannelEditor->ChannelSetup);
			UpdateChannel(bTraceType);
		}
	}

	return FReply::Handled();
}

#Loc: <Workspace>/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.cpp:2240

Scope (from outer to inner):

file
function     void FCollisionProfileDetails::FCollisionProfileData::Save

Source code excerpt:

{
	Profiles = Profile->Profiles;
	DefaultChannelResponses = Profile->DefaultChannelResponses;
	EditProfiles = Profile->EditProfiles;
}

//=====================================================================================

#undef LOCTEXT_NAMESPACE

#Loc: <Workspace>/Engine/Source/Editor/DetailCustomizations/Private/CollisionProfileDetails.h:192

Scope (from outer to inner):

file
class        class FCollisionProfileDetails : public IDetailCustomization

Source code excerpt:

	{
		TArray<FCollisionResponseTemplate>	Profiles;
		TArray<FCustomChannelSetup>			DefaultChannelResponses;
		TArray<FCustomProfile>				EditProfiles;

		void Save(UCollisionProfile * Profile);
	};

	FCollisionProfileData SavedData;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/Engine/CollisionProfile.h:169

Scope (from outer to inner):

file
class        class UCollisionProfile : public UDeveloperSettings

Source code excerpt:

	/** Game-specific overrides to default responses to collision channels */
	UPROPERTY(globalconfig)
	TArray<FCustomChannelSetup>			DefaultChannelResponses;

	/** Game-specific overrides to engine profiles */
	UPROPERTY(globalconfig)
	TArray<FCustomProfile>				EditProfiles;

	/** Used to handle renaming profiles */

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/CollisionProfile.cpp:373

Scope (from outer to inner):

file
function     void UCollisionProfile::LoadProfileConfig

Source code excerpt:

	FCollisionResponseContainer::DefaultResponseContainer.SetResponse( COLLISION_GIZMO, ECR_Ignore );

	// we can't guarantee that DefaultChannelResponses was loaded ordered (from
	// config) - in the following loop, we fill out TraceTypeMapping and 
	// ObjectTypeMapping from DefaultChannelResponses, and those mappings expect 
	// to be ordered (since we reinterpret the index to be an enum value itself 
	// in functions like ConvertToCollisionChannel(), etc.)
	DefaultChannelResponses.Sort([](const FCustomChannelSetup& Rhs, const FCustomChannelSetup& Lhs)->bool 
		{ 
			return (Rhs.Channel < Lhs.Channel);
		}
	);

	for (int32 ChannelResponseIndex = 0; ChannelResponseIndex < DefaultChannelResponses.Num(); ++ChannelResponseIndex)
	{
		const FCustomChannelSetup& CustomChannel = DefaultChannelResponses[ChannelResponseIndex];
		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 )
			{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/CollisionProfile.cpp:401

Scope (from outer to inner):

file
function     void UCollisionProfile::LoadProfileConfig

Source code excerpt:

				{
					UE_LOG(LogCollisionProfile, Warning, TEXT("Cannot map multiple responses to the same collision channel (%d); ignoring '%s' "), EnumIndex, *DisplayValue);
					DefaultChannelResponses.RemoveAt(ChannelResponseIndex);
					// decrement iterator so this index gets processed again (since we just removed an entry)
					--ChannelResponseIndex;
					continue;
				}

				// also has to set this for internal use

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Collision/CollisionProfile.cpp:721

Scope (from outer to inner):

file
function     void UCollisionProfile::SaveCustomResponses

Source code excerpt:

			//The channel should either be a public engine channel or an existing game channel
			if((Index < ECollisionChannel::ECC_EngineTraceChannel1)
				|| (DefaultChannelResponses.FindByPredicate([ChannelDisplayName](const FCustomChannelSetup& ChannelSetup) { return ChannelSetup.Name == ChannelDisplayName; }) != nullptr))
			{
				Template.CustomResponses.Add(FResponseChannel(ChannelDisplayName, (ECollisionResponse)(Template.ResponseToChannels.EnumArray[Index])));
			}
		}
	}
}