蓝图里获取配置信息

// DeveloperSettings.Build.cs
#include "Kismet/BlueprintFunctionLibrary.h"
#include "xxx.generated.h"

UCLASS(Config=Game, defaultconfig)
class UMySettings : public UDeveloperSettings
{
	GENERATED_BODY()

public:
	UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category = "General")
	bool DisableScreenMessages = false; // 在蓝图里可以直接访问该变量(GetClassDefaults)

	/** Gets the settings container name for the settings, either Project or Editor */
	virtual FName GetContainerName() const override { return TEXT("Project"); }
	/** Gets the category for the settings, some high level grouping like, Editor, Engine, Game...etc. */
	virtual FName GetCategoryName() const override { return TEXT("Game"); }
	/** The unique name for your section of settings, uses the class's FName. */
	virtual FName GetSectionName() const override { return TEXT("General"); }
};


UCLASS()
class UMyBPLibrary : public UBlueprintFunctionLibrary
{
        GENERATED_BODY()
public:
	UFUNCTION(BlueprintCallable, Category = "MyBP")
	static bool GetGameConfig(const FString& Section, const FString& Key, FString& Val);

	UFUNCTION(BlueprintCallable, Category = "MyBP")
	static bool DumpGameConfig();
};


bool UMyBPLibrary::GetGameConfig(const FString& Section, const FString& Key, FString& Val)
{
	if (GConfig == nullptr)
	{
		return false;
	}

	FString ConfigFilePath = FPaths::ProjectDir() + TEXT("GameConfig/GameConfig.ini");
	ConfigFilePath = FPaths::ConvertRelativePathToFull(ConfigFilePath);
	return GConfig->GetString(*Section, *Key, Val, ConfigFilePath);
}

bool UMyBPLibrary::DumpGameConfig()
{
	if (GConfig == nullptr)
	{
		return false;
	}

	FString ConfigFilePath = FPaths::ProjectDir() + TEXT("GameConfig/GameConfig.ini");
	ConfigFilePath = FPaths::ConvertRelativePathToFull(ConfigFilePath);
	UE_LOG(LogTemp, Log, TEXT("Dumping GameConfig file: [%s] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"), *ConfigFilePath);

	TArray<FString> OutSectionNames;
	bool bOk = GConfig->GetSectionNames(ConfigFilePath, OutSectionNames);

	for(auto s: OutSectionNames)
	{
		TArray<FString> OutResult;
		GConfig->GetSection(*s, OutResult, ConfigFilePath);
		UE_LOG(LogTemp, Log, TEXT("Section: [%s]"), *s);
		for(auto line: OutResult)
		{
			UE_LOG(LogTemp, Log, TEXT("key-value: %s"), *line);
		}
		UE_LOG(LogTemp, Log, TEXT("End Section <<<<<<<<<<<<<<<<<"));
	}
	UE_LOG(LogTemp, Log, TEXT("End Dumping <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"));

	return bOk;
}

config/配置存取

 UCLASS(Config=AnjGameSettings, ConfigDoNotCheckDefaults/DefaultConfig)
 class UAnjGameSettings : UDevelopSettings // [OR] UEditorSettings [OR]
 class AAnjGameSettings : Axxx
 {
     UPROPERTY(Config)
     int BroadcastPort = 8888;
     AAnjGameSettings();
     /** Gets the settings container name for the settings, either Project or Editor */
     virtual FName GetContainerName() const override { return TEXT("Project"); }
     /** Gets the category for the settings, some high level grouping like, Editor, Engine, Game...etc. */
     virtual FName GetCategoryName() const override { return TEXT("DataDrivenSettings"); }
     /** The unique name for your section of settings, uses the class's FName. */
     virtual FName GetSectionName() const override { return TEXT("DataDrivenSettings"); }
 }
代码中Config=AnjGameSettings用来设定class中带有Config meta信息的Property要写入AnjGameSettings.ini文件。参考官网文档,这个Config叫做Specifier,指定Configuration Categories,Categories列表在官网能看到。
AAnjGameSettings()构造函数可以用来设定Property的默认值:
 UAnjGameSettings::UAnjGameSettings( )
 {
 	if (GConfig)
 	{
 		FString IPStr;
 		if (!GConfig->GetString(TEXT("/Script/SuraForAnj.AnjGameSettings"), TEXT("LocalIP"), IPStr, GetClass()->GetConfigName()))
 		{
 			bool canBind = false;
 			TSharedRef<FInternetAddr> localIp = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->GetLocalHostAddr(*GLog, canBind);
 			FIPv4Endpoint LocalEndpoint = FIPv4Endpoint(localIp);
 			LocalIP = LocalEndpoint.Address.ToString();
 			SaveConfig();
 		}
 	}
 }
注意上面代码中的GetClass()->GetConfigName(),它返回Config指定的AnjGameSettings.ini文件的存储路径(也可以直接写GGameIni、GEngineIni等值)。SaveConfig()是UObject的函数,注意其Filename参数未指定时,内部实现是设定为GetClass()->GetConfigName()。
ConfigDoNotCheckDefaults与DefaultConfig的区别:
UpdateDefaultConfigFile()函数类似上面的SaveConfig(),但会把值写入AnjGameSettingsDefault.ini文件。而在调用SaveConfig()时,如为DefaultConfig,则当Property的值与xxxDefault.ini文件里的值一致时,xxx.ini文件里Property属性行会被删除,这是因为xxxDefault.ini文件先被读取,然后是xxx.ini,所以与xxxDefault.ini里一致的属性,没必要再往xxx.ini写一条记录。而指定了ConfigDoNotCheckDefaults时,SaveConfig()不检查有无Default.ini文件及里面的属性值,直接更新xxx.ini文件。

从UDeveloperSettings派生的UObject,可以继承其能够在UE编辑器的ProjectSettings/EditorPreferences->Category->Section->(UPROPERTY.Category)里直接编辑属性的能力。

关于config信息的读取,参考
To access the developer settings in C++ we use the CDO (Class Default Object) as that is already automatically instanced for us and accessed using GetDefault<T>();
 void USSaveGameSubsystem::Initialize(FSubsystemCollectionBase& Collection)
 {
 	Super::Initialize(Collection);
 	const USSaveGameSettings* SGSettings = GetDefault<USSaveGameSettings>(); // Access via CDO
 	// Access defaults from DefaultGame.ini
 	SlotName = SGSettings->SaveSlotName;
 	// Make sure it's loaded into memory .Get() only resolves if already loaded previously elsewhere in code
 	UDataTable* DummyTable = SGSettings->DummyTablePath.LoadSynchronous();
 }

有一个全部自定义处理config的参考

获取本地IP地址

// Module: Sockets.build.cs

#include "SocketSubsystem.h"
#include "IPAddress.h"
#include "Interfaces/IPv4/IPv4Endpoint.h"

bool canBind = false;
TSharedRef<FInternetAddr> localIp = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->GetLocalHostAddr(*GLog, canBind);
FIPv4Endpoint LocalEndpoint = FIPv4Endpoint(localIp);
LocalIP = LocalEndpoint.Address.ToString();

ini文件读写 → ...

https://blog.51cto.com/hanzhichao/3201113

from configparser import ConfigParser
conf = ConfigParser()
conf.read(configFilePath, encoding=cur_encoding)
print(conf['section']['key'])


''' LutConfig.py '''
from pathlib import Path
from typing import *
import chardet
from configparser import ConfigParser

def GetDefaultConfigFilePath() -> Path:
    return Path(__file__).parent.absolute() / 'Windows/TestLutPro/Config/DefaultGame.ini'

def GetConfig(configFilePath: str) -> dict:
    # 首先二进制方式打开文件
    with open(configFilePath, 'rb') as frb:
        # 检测编码方式
        cur_encoding = chardet.detect(frb.read())['encoding']

    # 指定文件编码方式
    conf = ConfigParser()
    conf.read(configFilePath, encoding=cur_encoding)

    configResult = {}
    section = '/Script/ApplyLutTools.ApplyLutSettings'
    if conf.has_option(section, 'ServerIP'):
        configResult['ServerIP'] = conf[section]['ServerIP']
    if conf.has_option(section, 'ServerPort'):
        configResult['ServerPort'] = conf[section].getint('ServerPort')
    if conf.has_option(section, 'LocalListeningIP'):
        configResult['LocalListeningIP'] = conf[section]['LocalListeningIP']
    return configResult

def GetDefaultConfig() -> dict:
    return GetConfig(GetDefaultConfigFilePath())