[UE4]UObject Notes
Keywords: UE4, UObject, Construct, Construction, Instantiating, UObject-derived, Config, DefaultGame.ini
NewObject using a Blueprint class
1st way:
header:
UPROPERTY(EditAnywhere, Category = "Player")
TSubclassOf<AMyActor> AMyActorClass;
cpp:
MyActor = NewObject<AMyActor>(this, TEXT("MyActor"), RF_NoFlags, AMyActorClass->GetDefaultObject(), true);
2nd way:
header:
UPROPERTY(EditAnywhere, Category = "Player")
TSubclassOf<AMyActor> AMyActorClass;
cpp:
MyActor = NewObject<AMyActor>(this, AMyActorClass);
Different ways to instantiate the object
-
UObject::CreateDefaultSubobject
is only callable in a class constructor, and takes care of creating an instance of the CDO of the subobject’s class, setting its outer class as the caller object, among other things. The created object then becomes the default object for the property when its object class is instantiated. -
NewObject<T>
is the function normally used to instantiate objects after engine initialisation, during normal gameplay. It provides several convenience overloads to handle most scenarios. -
UWorld::SpawnActor<T>
is a convenience method to spawn actors in a level with the specified location and rotation, spawn collision settings, and checks to ensure it’s a spawnable actor class, and is nothing more than a wrapper of NewObject. -
ConstructObject
has been removed in favour of NewObject.
Orign:
Unreal Engine 4. Different ways to instantiate the object
https://stackoverflow.com/a/60030248/1645289
Check Types
Class:
UClass::IsChildOf();
Actor:
AActor::IsA();
Initialize members of UObject from ini configuration file
Engine\Source\Runtime\CoreUObject\Public\UObject\Object.h
/**
* Imports property values from an .ini file.
*
* @param Class the class to use for determining which section of the ini to retrieve text values from
* @param Filename indicates the filename to load values from; if not specified, uses ConfigClass's ClassConfigName
* @param PropagationFlags indicates how this call to LoadConfig should be propagated; expects a bitmask of UE4::ELoadConfigPropagationFlags values.
* @param PropertyToLoad if specified, only the ini value for the specified property will be imported.
*/
void LoadConfig( UClass* ConfigClass=NULL, const TCHAR* Filename=NULL, uint32 PropagationFlags=UE4::LCPF_None, class UProperty* PropertyToLoad=NULL );
/**
* Wrapper method for LoadConfig that is used when reloading the config data for objects at runtime which have already loaded their config data at least once.
* Allows the objects the receive a callback that it's configuration data has been reloaded.
*
* @param Class the class to use for determining which section of the ini to retrieve text values from
* @param Filename indicates the filename to load values from; if not specified, uses ConfigClass's ClassConfigName
* @param PropagationFlags indicates how this call to LoadConfig should be propagated; expects a bitmask of UE4::ELoadConfigPropagationFlags values.
* @param PropertyToLoad if specified, only the ini value for the specified property will be imported
*/
void ReloadConfig( UClass* ConfigClass=NULL, const TCHAR* Filename=NULL, uint32 PropagationFlags=UE4::LCPF_None, class UProperty* PropertyToLoad=NULL );
/** Import an object from a file. */
void ParseParms( const TCHAR* Parms );
How do I create a blueprint that can inherit from a UObject
Examples:
UCLASS(Blueprintable, BlueprintType)
class ENGINE_API UMyObject : public UObject
{
Reference:
https://answers.unrealengine.com/questions/35953/view.html
LoadClass
Example
UClass* TestClass = LoadClass<AActor>(nullptr, TEXT("Blueprint'/Game/Blueprints/MapPathBrush_BP.MapPathBrush_BP_C'"));
UClass* AnimClass = LoadClass<UAnimInstance>(nullptr, TEXT("AnimBlueprint'/Game/ABP_Test.ABP_Test_C'"));
UClass* WidgetClass = LoadClass<UUserWidget>(nullptr, TEXT("WidgetBlueprint'/Game/NewWidgetBlueprint.NewWidgetBlueprint_C'"))
LoadClass触发构造函数的问题
如果项目中使用了LoadClass,那么蓝图相关的class构造函数中不要执行和实例化对象相关的操作,因为当执行LoadClass时也会把对应class的构造函数执行一遍(即使我们没有手动执行spawn或者create等函数,原因是LoadClass执行了LoadObject,而LoadObject内部又会执行ConstructorHelpers::FObjectFinder(),所以会触发class的构造函数,比如自己新建了一个UserWidget class,这个class的默认构造函数会在LoadClass时被执行一次),建议将初始化操作放在Initialize、BeginPlay等函数中。
Config (ini file)
How to add GUI for custom ini file in Project Settings
It’s much easier to create custom project settings using DeveloperSettings (Custom ‘Project Settings’), example:
UCLASS(Config = Game, DefaultConfig, meta = (DisplayName = "My Custom Settings"))
class MYGAME_API UMySettings : public UDeveloperSettings
{
GENERATED_BODY()
public:
UPROPERTY(Config, EditAnywhere, Category = "Info")
FString Foo = TEXT("test");
UPROPERTY(Config, EditAnywhere, Category = "Info")
int32 Bar = 222;
};
Then you can modify values in GUI panel (Project Settings -> Game -> My Settings), and values will be saved to [Project]/Config/DefaultGame.ini
(in section [/Script/MyGame.MySettings]
) automatically when modify them in project settings panel.
If want to save values in custom ini file, not Game.ini, you should change
UCLASS(Config = Game, DefaultConfig, meta = (DisplayName = "My Custom Settings"))
to
UCLASS(Config = MySetting, DefaultConfig, meta = (DisplayName = "My Custom Settings"))
but then the GUI panel moved into Project Settings -> Engine -> My Custom Settings
.
ini file was saved in [Project]/Config/DefaultMySetting.ini
automatically when values was modified in GUI (if the default value wasn’t changed),
but if change value and save it using C++ code: LoadConfig()
then SaveConfig()
, then ini file will be saved in FPaths::GeneratedConfigDir()
(e.g. [Project]/Saved/Config/WindowsNoEditor/MySetting.ini)
Change values and save them using C++ at run-time (LoadConfig()
, SaveConfig()
):
static const FString ConfigFileName = TEXT("MySettings.ini");
FString Path = FPaths::GeneratedConfigDir() + ConfigFileName;
UMySettings* Settings = GetMutableDefault<UMySettings>();
//load values from [Project]/Saved/Config/WindowsNoEditor/MySettings.ini
Settings->LoadConfig(nullptr, *Path);
Settings->Foo = TEXT("jjjj");
Settings->Bar = 6666;
//save values into [Project]/Saved/Config/WindowsNoEditor/MySettings.ini
Settings->SaveConfig(CPF_Config, *Path);
DefaultConfig vs ConfigDoNotCheckDefaults
一般一个ini对应的config class长这样:
UCLASS(Config = Game, DefaultConfig, meta = (DisplayName = "My Custom Settings"))
class MYGAME_API UMySettings : public UDeveloperSettings
{
其中DefaultConfig
表示ini文件的读取和存储方式,另外一种方式是ConfigDoNotCheckDefaults
。
读取方式区别:
DefaultConfig
: 使用LoadConfig()
接口获取的配置,或者编辑器首次启动时,都是从FPaths::SourceConfigDir()
目录下的ini读取,比如:[Project]/Saved/Config/WindowsNoEditor/MySettings.ini
,而不是DefaultMySettings.ini(即使其内部有修改过的值)。但通过编辑器(Project Settings面板)修改后,会清掉[Project]/Saved/Config/WindowsNoEditor/MySettings.ini
中所有内容,即使只修改了一项。同时,将修改过的值保存在[Project]/Config/MySettings.ini
ConfigDoNotCheckDefaults
: 都是从[Project]/Saved/Config/WindowsNoEditor/MySettings.ini
读取。
存储方式区别(两种情况):
- 使用C++接口
SaveConfig()
触发的存储都存在FPaths::SourceConfigDir()
目录下,比如:[Project]/Saved/Config/WindowsNoEditor/MySettings.ini
。 - 通过编辑器(Project Settings面板)修改触发的存储:
DefaultConfig
: ini文件存放在[Project]/Config/DefaultMySettings.ini
中。[Project]/Saved/Config/WindowsNoEditor/MySettings.ini
文件仍然存在,但是内容为空。ConfigDoNotCheckDefaults
:[Project]/Config/DefaultMySettings.ini
文件不存在,且内容保存在[Project]/Saved/Config/WindowsNoEditor/MySettings.ini
参考:UE4中Config的使用
https://blog.ch-wind.com/ue4-config-usage/
How to add custom config in specified section in project settings
Credits to: UnLuaModule.cpp
1, Add C++ class for ini config:
UCLASS(Config = UnLua, DefaultConfig, Meta = (DisplayName = "UnLua"))
class UNLUA_API UUnLuaSettings : public UObject
{
GENERATED_BODY()
public:
UUnLuaSettings(const FObjectInitializer& ObjectInitializer);
/** Entry module name of lua env. Leave it empty to skip execution on startup. */
UPROPERTY(Config, EditAnywhere, Category="Runtime")
FString StartupModuleName = TEXT("");
}
2, Use FModuleManager::RegisterSettings()
to register custom ini settings in Project Settings on startup module:
void FMyPluginModule::StartupModule()
{
RegisterSettings();
}
void FMyPluginModule::ShutdownModule()
{
UnregisterSettings();
}
void FMyPluginModule::RegisterSettings()
{
#if WITH_EDITOR
ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
if (!SettingsModule)
return;
const auto Section = SettingsModule->RegisterSettings("Project", "Plugins", "UnLua",
LOCTEXT("UnLuaEditorSettingsName", "UnLua"), LOCTEXT("UnLuaEditorSettingsDescription", "UnLua Runtime Settings"),
GetMutableDefault<UUnLuaSettings>());
//bind callback for value changed
Section->OnModified().BindRaw(this, &FMyPluginModule::OnSettingsModified);
#endif
}
void FMyPluginModule::UnregisterSettings()
{
#if WITH_EDITOR
ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
if (SettingsModule)
SettingsModule->UnregisterSettings("Project", "Plugins", "UnLua");
#endif
}
Plugins Config file(ini)
You can put config files into plugin’s Config directory. e.g.:
[Porject]\Plugins\[Plugin]\Config\CustomSettings.ini
If there’s a config with same file name in the directory [Porject]\Config\
, then the content of [Porject]\Plugins\[Plugin]\Config\
will be merged into [Porject]\Config\
automatically when packaging.
生如夏花之绚烂,死如秋叶之静美。----泰戈尔《生如夏花》