UE基础篇三:数据驱动

25 篇文章 5 订阅 ¥39.90 ¥99.00

初级:

Gameplay数据

  • C++ 类:原生类构造函数设置默认值并支持数据继承。数据也可以硬编码到函数局部变量中,但很难跟踪。
  • 配置文件:Ini文件和控制台变量支持覆盖在C++构造函数中声明的数据,也可以直接查询。
  • 蓝图类:蓝图类默认值与C++类构造函数的作用相同,支持数据继承。数据也可以在函数局部变量或引脚文字值中安全地设置。
  • 数据资源:对于无法实例化且不需要数据继承的对象,独立数据资源比蓝图默认值更易于使用。
  • 表:数据可以作为数据表、曲线表导入,也可以在运行时读取。
  • 放置实例:数据可以存储在关卡或其他资源内设置的蓝图或C++类实例中,并会覆盖类默认值。
  • 自定义系统:与逻辑一样,可以使用多种自定义方法来存储数据。
    保存游戏:运行时保存游戏文件可用于覆盖或修改上述数据类型。

1、结构体

USTRUCT(BlueprintType)
struct DATADRIVEN_API FShopItem
{
	GENERATED_BODY();
public:
	UPROPERTY(BlueprintReadWrite,EditAnywhere)
		FText Name;
	UPROPERTY(BlueprintReadWrite, EditAnywhere)
		UTexture2D* Icon;
	UPROPERTY(BlueprintReadWrite, EditAnywhere)
		float Price;
};

2、ConstructorHelpers

ConstructorHelpers只能在构造函数中使用。如果在非构造函数中使用的话,则会引起Crash(原因不明),在其代码内部检查了是否在构造函数中调用:CheckIfIsInConstructor(ObjectToFind);

如下 在构造函数中查找UMG 并且设置WidgetClass

ConstructorHelpers::FClassFinder<UUserWidget> classFinder(TEXT("/Game/Blueprint/CPP/UMG_Shop_CPP"));
	Widget= CreateDefaultSubobject<UWidgetComponent>("Widget");
	Widget->SetupAttachment(RootComponent);
	Widget->SetRelativeLocation(FVector(0.f, 0.f, 110.f));
	Widget->SetRelativeScale3D(FVector(0.3f, 0.3f, 0.3f));
	Widget->SetDrawAtDesiredSize(true);
	Widget->SetManuallyRedraw(true);

	if (classFinder.Succeeded())
	{
		Widget->SetWidgetClass(classFinder.Class);
	}

3、Class Reference

中级:

4、Datatable

4.1 蓝图创建如下UMG,每个Item显示图片,名字,价格

数据结构设计:

USTRUCT(BlueprintType)
struct FShopItem : public FTableRowBase
{
	GENERATED_BODY()
	
	UPROPERTY(BlueprintReadWrite,EditAnywhere)
	FText Name;
	UPROPERTY(BlueprintReadWrite, EditAnywhere)
	UTexture2D* Icon;
	UPROPERTY(BlueprintReadWrite, EditAnywhere)
	float Price;
};

基于ShopItem创建DataTable, 可以在UE引擎里 点击添加进行操作,也可以导出成Json文件或CSV文件 进行修改,再点重新导入

创建单个UMG_Item

在图表里,添加ShopItem变量,并且公开,去更新图片,价格,名字

创建一个UMG_Shop,用来显示数据表里的Item

蓝图里获取DataTable的值

添加UMG_Item

4.2 C++中调用Datatable,LoadObject

// ShopConfig.h
struct FShopItem;

UCLASS(Blueprintable, Category = "DataDriven")
class UShopConfig : public UObject
{
	GENERATED_BODY()
public:
	virtual bool Initialize();
public:
	UFUNCTION(BlueprintPure, DisplayName = "ShopConfig")
		static UShopConfig* Get();

public:
	void GetAllItems(TArray<FShopItem*>& outItems);
protected:
	UPROPERTY()
		UDataTable* mItemsDataTable;
};

//ShopConfig.cpp

bool UShopConfig::Initialize()
{

	mItemsDataTable = LoadObject<UDataTable>(nullptr, TEXT("/Game/Blueprint/DataTable/DT_ShopItems.DT_ShopItems"));

	return mItemsDataTable!=nullptr;
}

UShopConfig* UShopConfig::Get()
{
//获取类的可变默认对象,GetDefault不可变
	return GetMutableDefault<UShopConfig>();
}

void UShopConfig::GetAllItems(TArray<FShopItem*>& outItems)
{
	static const FString ContextString(TEXT("GENERAL"));
	mItemsDataTable->GetAllRows(ContextString,outItems);
}

使用方法:

void UBaseShopWdget::NativePreConstruct()
{
	Super::NativePreConstruct();

	if (ItemWidgetClass == nullptr)
	{
		return;
	}

	ItemsUniformGridPanel->ClearChildren();
	TArray<FShopItem*> outItems;
	UShopConfig::Get()->GetAllItems(outItems);

	for (int32 i = 0; i < outItems.Num(); ++i)
	{
		UBaseItemWdget* itemWidget = CreateWidget<UBaseItemWdget>(ItemsUniformGridPanel, ItemWidgetClass);
		itemWidget->Item = *outItems[i];

		ItemsUniformGridPanel->AddChildToUniformGrid(itemWidget, i / 5, i % 5);
	}
}

4.3 Composite Datatable : 复合数据表,可以堆叠多个DataTable,

当出现相同的数据索引时,以最后面的表为第一优先级

5、CurveTable: 用于一些比较轻量的数值

外部CSV 编辑好表后,直接拖入场景,选择CurveTable

6、DataAsset

继承自UPrimaryDataAsset(方便管理数据对象的加载释放) ,也可以继承UDataAsset

UCLASS(BlueprintType)
class UShopItemAsset :public UPrimaryDataAsset
{
	GENERATED_BODY()
public:
	UPROPERTY(BlueprintReadWrite,EditAnywhere)
		FText Name;
	UPROPERTY(BlueprintReadWrite, EditAnywhere)
		UTexture2D* Icon;
	UPROPERTY(BlueprintReadWrite, EditAnywhere)
		float Price;
};

资产管理器中添加路径,可以动态加载

加载方式:

1.

2.通过Key动态加载

张乂卓:UE4动作游戏实例RPG Action解析五:GameInstance加载UPrimaryDataAsset(武器资源)并加载默认武器资源

多个DataAsset 可以批量编辑

6.2 全局数据

UCLASS(BlueprintType)
class UShopGlobalSettings : public UDataAsset
{
	GENERATED_BODY()
public:
	UShopGlobalSettings();
public:
	UFUNCTION(BlueprintPure, DisplayName = "ShopGlobalSettings")
		static UShopGlobalSettings* Get();

	UPROPERTY(BlueprintReadWrite, EditAnywhere)
		float PlayerStartMoney = 100.f;	
};

//cpp

UShopGlobalSettings::UShopGlobalSettings()
{
	
}

UShopGlobalSettings* UShopGlobalSettings::Get()
{
	static UShopGlobalSettings* obj=nullptr;
	if (obj==nullptr)
	{
		obj = LoadObject<UShopGlobalSettings>(nullptr, TEXT("/Game/Blueprint/DataAsset/DA_ShopGlobalSettings"));
		obj->AddToRoot();
	}
	return obj;
}

7、WorldSetting : 设置自己的WorldSetting

使用方法:

UCLASS(Abstract)
class UPlayerWidget : public UUserWidget
{
	GENERATED_BODY()
public:
public:
	virtual void NativePreConstruct()override;
	virtual void NativeConstruct()override;
public:
	UPROPERTY(meta = (BindWidget))
		class UTextBlock* DifficultyTextBlock;
};

void UPlayerWidget::NativePreConstruct()
{
	Super::NativePreConstruct();

	
}

void UPlayerWidget::NativeConstruct()
{
	Super::NativeConstruct();

	AWorldSettings* settings= UGameplayStatics::GetGameMode(this)->GetWorld()->GetWorldSettings();
	AShopWorldSettings* shopSettings=Cast<AShopWorldSettings>(settings);
	if (shopSettings!=nullptr)
	{
		DifficultyTextBlock->SetText(UKismetTextLibrary::Conv_FloatToText(shopSettings->LevelDifficulty, ERoundingMode::HalfToEven));
	}

}

高级:

8 Settings.ini

8.1 UDeveloperSetting

创建一个C++文件继承DeveloperSettings

UCLASS(config = DataDrivenProjectSettings, defaultconfig)
class UDataDrivenProjectSettings :public UDeveloperSettings
{
	GENERATED_BODY()
public:
	/** 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("DataDriven"); }
	/** The unique name for your section of settings, uses the class's FName. */
	virtual FName GetSectionName() const override { return TEXT("DataDriven"); }
public:

	UFUNCTION(BlueprintPure, DisplayName = "DataDrivenProjectSettings")
		static UDataDrivenProjectSettings* Get() { return GetMutableDefault<UDataDrivenProjectSettings>(); }
public:
	UPROPERTY(Config, EditAnywhere, BlueprintReadWrite, Category = Shop)
	float PriceOff = 50.f;

	UPROPERTY(Config, EditAnywhere, BlueprintReadWrite, Category = Player)
	float PlayerStartLevel = 10.f;

};

重新编译之后,在项目设置里面会出现如下信息

修改其中的值,在项目Config目录里会出现新的文件

蓝图调用:

8.2 对类配置

调用父类方法

UCLASS(config = CustomConfig)
class ACustomConfigActor :public AActor
{
	GENERATED_BODY()
public:
	ACustomConfigActor();
public:
	UPROPERTY(Config, EditAnywhere, BlueprintReadWrite, Category = MyCustom)
	float MaxLife = 100.f;

	UPROPERTY(transient, EditAnywhere, BlueprintReadWrite, Category = MyCustom)
	float CurrentLife = 50.f;
public:
	virtual void BeginPlay()override;

	UFUNCTION(BlueprintCallable)
	void AddMaxLifeAndSave(float val);


};

//cpp
ACustomConfigActor::ACustomConfigActor()
{
}

void ACustomConfigActor::BeginPlay()
{
	Super::BeginPlay();
	LoadConfig();
}

void ACustomConfigActor::AddMaxLifeAndSave(float val)
{
	MaxLife+=val;
	SaveConfig();
}

9、ConsoleVariables: 方便用于调试

dd.ShopEnabled 接数值

UCLASS(BlueprintType,Blueprintable)
class AConsoleVariableActor :public AActor
{
	GENERATED_BODY()
public:
	AConsoleVariableActor();
public:
	virtual void BeginPlay()override;
	virtual void Tick(float DeltaSeconds)override;
};

static TAutoConsoleVariable<bool> CVarDDShopEnabled(
	TEXT("dd.ShopEnabled"),
	false,
	TEXT("The switch to enable shop or not."),
	ECVF_Default);

static TAutoConsoleVariable<int> CVarDDShopCount(
	TEXT("dd.ShopCount"),
	3,
	TEXT("The count of shop."),
	ECVF_Default);

static TAutoConsoleVariable<FString> CVarDDShopName(
	TEXT("dd.ShopName"),
	TEXT("Jack"),
	TEXT("The name of shop."),
	ECVF_Default);

AConsoleVariableActor::AConsoleVariableActor()
{
	PrimaryActorTick.bCanEverTick=true;
}

void AConsoleVariableActor::BeginPlay()
{
	Super::BeginPlay();
}

void AConsoleVariableActor::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);

	FString str=FString::Printf(TEXT("dd.ShopEnabled: %s"), CVarDDShopEnabled.GetValueOnGameThread()?TEXT("true"):TEXT("false"));
	str += FString::Printf(TEXT("\ndd.ShopCount: %d"), CVarDDShopCount.GetValueOnGameThread());
	str += FString::Printf(TEXT("\ndd.ShopName: %s"), *CVarDDShopName.GetValueOnGameThread());
	
	GEngine->AddOnScreenDebugMessage(0,5.f,FColor::Red, str);

}

10、原始数据

10.1 txt

FString ARawDataActor::ReadTxtFile(FString path)
{
	FString realPath = FPaths::ProjectDir() / path;
	FString content;
	FFileHelper::LoadFileToString(content, *realPath);
	
	return content;
}

10.2 Load Csv/Json as Table

bool ARawDataActor::LoadCsvAsTable(FString path, TArray<FShopItem>& Items)
{
	UDataTable* DataTable = NewObject<UDataTable>(GetTransientPackage(), FName(TEXT("TempDataTable")));
	DataTable->RowStruct = FShopItem::StaticStruct();

	FString realPath = FPaths::ProjectDir() / path;
	FString content;

	if (!FFileHelper::LoadFileToString(content, *realPath))
	{
		return false;
	}

	DataTable->CreateTableFromCSVString(content);	//CreateTableFromJSONString

	static const FString ContextString(TEXT("GENERAL"));
	DataTable->ForeachRow<FShopItem>(ContextString, [&Items](const FName& key, const FShopItem& value)
		{
			Items.Add(value);
		});

	return true;
}

bool ARawDataActor::LoadJsonAsTable(FString path, TArray<FShopItem>& Items)
{
	FString realPath = FPaths::ProjectDir() / path;
	FString content;
	FFileHelper::LoadFileToString(content, *realPath);

	TSharedPtr<FJsonObject> jsonRoot = MakeShareable(new FJsonObject());
	TSharedRef<FJsonStringReader> jsonReader= FJsonStringReader::Create(content);

	TArray<TSharedPtr<FJsonValue>> OutArray;

	if (FJsonSerializer::Deserialize<TCHAR>(jsonReader, OutArray))
	{
		for (TSharedPtr<FJsonValue> itemJson: OutArray)
		{
			const TSharedPtr<FJsonObject>& obj=itemJson->AsObject();
			FShopItem& newItem= Items.AddDefaulted_GetRef();
			newItem.Name=FText::FromString(obj->GetStringField(TEXT("Name")));
			newItem.Icon=LoadObject<UTexture2D>(nullptr,*obj->GetStringField(TEXT("Icon")));
			newItem.Price = obj->GetNumberField(TEXT("Price"));
		}
		return true;
	}
	return false;
}

10.3 Excel DirectExcel

bool UExcelWorkbook::StartWatch(const UObject* WorldContextObject, FExcelWorkbookChangedDelegate onChanged, bool autoReload /*= true*/, float rate/*=1.f*/)
{
#ifdef WIN32

	//wchar_t watchDirectory[512] = { 0 };
	//MultiByteToWideChar(CP_ACP, 0, (char*)*mPath, strlen((char*)*mPath), watchDirectory, sizeof(watchDirectory) / sizeof(wchar_t));
	FString path = FPaths::GetPath(mPath);
	const wchar_t* p = *path;

	mFindHandle = ::FindFirstChangeNotification(p, 0, FILE_NOTIFY_CHANGE_LAST_WRITE);
	if (INVALID_HANDLE_VALUE == mFindHandle)
	{
		DWORD errorCode = GetLastError();
		UE_LOG(LogDirectExcel, Error, L"%d", errorCode);
		return false;
	}

	UWorld* world = GEngine->GetWorldFromContextObjectChecked(WorldContextObject);
	world->GetTimerManager().SetTimer(mWatchTimer, [this, WorldContextObject, onChanged, autoReload]
	{
		DWORD dwWait = ::WaitForSingleObject(mFindHandle, 0);
		UE_LOG(LogDirectExcel, Warning, TEXT("Watch result:%d."), dwWait);
		if (dwWait == WAIT_FAILED)
		{
			DWORD errorCode = GetLastError();
			UE_LOG(LogDirectExcel, Error, L"%d", errorCode);
			StopWatch(WorldContextObject);
			return;
		}

		if (WAIT_OBJECT_0 == dwWait)
		{
			bool isOpen = true;
			if (autoReload)
			{
				isOpen = Reload();
			}

			if (isOpen)
			{
				onChanged.ExecuteIfBound(this);
			}
			else
			{
				onChanged.ExecuteIfBound(nullptr);
			}

			if (!::FindNextChangeNotification(mFindHandle))
			{
				::FindCloseChangeNotification(mFindHandle);
				mFindHandle = NULL;
				UE_LOG(LogDirectExcel, Warning, TEXT("Lost watch."));
			}
		}

	}, rate, true);
#endif

	return true;

}

10.4 SQL

UCLASS(BlueprintType,Blueprintable)
class ASqlDataActor :public AActor
{
	GENERATED_BODY()
public:
	ASqlDataActor();
public:
	virtual void BeginPlay()override;
public:
	UFUNCTION(BlueprintCallable)
		bool LoadSqlAsTable(FString path,TArray<FShopItem>& Items);
};

//CPP
ASqlDataActor::ASqlDataActor()
{
}

void ASqlDataActor::BeginPlay()
{
	Super::BeginPlay();
}

bool ASqlDataActor::LoadSqlAsTable(FString path, TArray<FShopItem>& Items)
{
	FSQLiteDatabaseConnection db;
	if (!db.Open(*path, nullptr, nullptr))
	{
		return false;
	}

	FString query = FString::Printf(TEXT("SELECT Name,Icon,Price FROM ShopItems"));

	FDataBaseRecordSet* outRecords = nullptr;
	if (!db.Execute(*query, outRecords))
	{
		delete outRecords;
		return false;
	}

	int count = outRecords->GetRecordCount();
	if (count == 0)
	{
		delete outRecords;
		return false;
	}

	int result = -1;
	for (FDataBaseRecordSet::TIterator i(outRecords); i; ++i)
	{
		FShopItem& newItem = Items.AddDefaulted_GetRef();
		for (FDatabaseColumnInfo column : i->GetColumnNames())
		{
			if (column.ColumnName == TEXT("Name"))
			{
				newItem.Name = FText::FromString(i->GetString(*column.ColumnName));

			}
			else if (column.ColumnName == TEXT("Icon"))
			{
				newItem.Icon = LoadObject<UTexture2D>(nullptr, *i->GetString(*column.ColumnName));
			}
			else if (column.ColumnName == TEXT("Price"))
			{
				newItem.Price = i->GetFloat(*column.ColumnName);
			}

		}

	}
	delete outRecords;
	db.Close();
	
	return true;
}

11、工具:

12、提取数据保存到表格

使用插件:

其中有一些函数是无法直接弄出来的,所以要在C++中添加一些东西,将函数暴露在蓝图界面中:

UCLASS(Blueprintable, Category = "DataDriven")
class UMyDataTableFunctionLibrary : public UBlueprintFunctionLibrary

	GENERATED_BODY()
public:
#if WITH_EDITOR
	UFUNCTION(BlueprintCallable, Category = "Editor Scripting | DataTable", DisplayName = "AddRowToDataTable")
		static void AddVolumeToDataTable(UDataTable* DataTable, FName rowName,const FVolumeItem& row);

	UFUNCTION(BlueprintCallable, Category = "Editor Scripting | DataTable", DisplayName = "ClearDataTable")
		static void ClearDataTable(UDataTable* DataTable);

	UFUNCTION(BlueprintCallable, Category = "Editor Scripting | DataTable", DisplayName = "DataTable_RemoveRow")
		static void DataTable_RemoveRow(UDataTable* DataTable, FName rowName);
#endif
;

void UMyDataTableFunctionLibrary::AddVolumeToDataTable(UDataTable* DataTable, FName rowName, const FVolumeItem& row)

	if (DataTable == nullptr)
	
		return;
	
	DataTable->AddRow(rowName, row);
	DataTable->GetOutermost()->MarkPackageDirty();


void UMyDataTableFunctionLibrary::ClearDataTable(UDataTable* DataTable)

	if (DataTable == nullptr)
	
		return;
	
	DataTable->EmptyTable();
	DataTable->GetOutermost()->MarkPackageDirty();


void UMyDataTableFunctionLibrary::DataTable_RemoveRow(UDataTable* DataTable, FName rowName)

	if (DataTable == nullptr)
	
		return;
	
	DataTable->RemoveRow(rowName);
	DataTable->GetOutermost()->MarkPackageDirty();

DataTable->GetOutermost()->MarkPackageDirty();

这个代码就让小星星出现,代表已经对他进行了修改。

13、关于无法编译成功的问题

将启用状态改成false。


DataDriven.Build.cs中添加PublicDependencyModuleNames.Add("DeveloperSettings");

然后就可以成功编译运行了!

在名为Watch代码的文件夹中有部分插件中的代码,可以借鉴参考一下。

14、CSV写入DataTable

原文链接:童年的琴:第6期 UE4 动态读写DataTable数据表

//.h
// Declare General Log Category, header file .h
DECLARE_LOG_CATEGORY_EXTERN(LogUtiliesNode, Log, All);

/**
 * 
 */
UCLASS()
class DATADERIVEDEXCISE_API UDataTableBFLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

	/**
	* Empty and fill a Data Table from CSV string.
	* @param	CSVString	The Data that representing the contents of a CSV file.
	* @return	True if the operation succeeds, check the log for errors if it didn't succeed.
	*/
UFUNCTION(BlueprintCallable, DisplayName = "Fill Data Table from CSV String", Category = "DataTable")
	static bool FillDataTableFromCSVString(UDataTable* DataTable, const FString& CSVString);

/**
	* Empty and fill a Data Table from CSV file.
	* @param	CSVFilePath	The file path of the CSV file.
	* @return	True if the operation succeeds, check the log for errors if it didn't succeed.
	*/
UFUNCTION(BlueprintCallable, DisplayName = "Fill Data Table from CSV File", Category = "DataTable")
	static bool FillDataTableFromCSVFile(UDataTable* DataTable, const FString& CSVFilePath);

/**
	* Empty and fill a Data Table from JSON string.
	* @param	JSONString	The Data that representing the contents of a JSON file.
	* @return	True if the operation succeeds, check the log for errors if it didn't succeed.
	*/
UFUNCTION(BlueprintCallable, DisplayName = "Fill Data Table from JSON String", Category = "DataTable")
	static bool FillDataTableFromJSONString(UDataTable* DataTable, const FString& JSONString);

/**
	* Empty and fill a Data Table from JSON file.
	* @param	JSONFilePath	The file path of the JSON file.
	* @return	True if the operation succeeds, check the log for errors if it didn't succeed.
	*/
UFUNCTION(BlueprintCallable, DisplayName = "Fill Data Table from JSON File", Category = "DataTable")
	static bool FillDataTableFromJSONFile(UDataTable* DataTable, const FString& JSONFilePath);

/** Output entire contents of table as CSV string */
UFUNCTION(BlueprintCallable, DisplayName = "Get Table As CSV String", Category = "DataTable")
	static void GetDataTableAsCSVString(UDataTable* DataTable, FString& CSVString);

/** Output entire contents of table as CSV File */
UFUNCTION(BlueprintCallable, DisplayName = "Get Table As CSV File", Category = "DataTable")
	static void GetDataTableAsCSVFile(UDataTable* DataTable, const FString& CSVFilePath);
	
};

//cpp
//Declare General Log Category, source file .cpp
DEFINE_LOG_CATEGORY(LogUtiliesNode);

bool UDataTableBFLibrary::FillDataTableFromCSVString(UDataTable* DataTable, const FString& CSVString)
{
	if (!DataTable || (CSVString.Len() == 0))
	{
		UE_LOG(LogUtiliesNode, Warning, TEXT("FillDataTableFromCSVString -> Can't fill DataTable with CSVString: %."), *CSVString);
		return false;
	}
	// Call bulit-in function
	TArray<FString> Errors = DataTable->CreateTableFromCSVString(CSVString);
	if (Errors.Num())
	{
		// It has some error message
		for (const FString& Error : Errors)
		{
			UE_LOG(LogUtiliesNode, Warning, TEXT("%s"), *Error);
		}
		return false;
	}

	return true;
}

bool UDataTableBFLibrary::FillDataTableFromCSVFile(UDataTable* DataTable, const FString& CSVFilePath)
{
	FString CSVString;
	if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*CSVFilePath))
	{
		// Supports all combination of ANSI/Unicode files and platforms.
		FFileHelper::LoadFileToString(CSVString, *CSVFilePath);
	}
	else
	{
		UE_LOG(LogUtiliesNode, Warning, TEXT("FillDataTableFromCSVFile -> Cannot find CSV file %s"), *CSVFilePath);
		return false;
	}
	return UDataTableBFLibrary::FillDataTableFromCSVString(DataTable, CSVString);
}

bool UDataTableBFLibrary::FillDataTableFromJSONString(UDataTable* DataTable, const FString& JSONString)
{
	if (!DataTable || (JSONString.Len() == 0))
	{
		UE_LOG(LogUtiliesNode, Warning, TEXT("FillDataTableFromJSONString -> Can't fill DataTable with JSONString: %."), *JSONString);
		return false;
	}
	// Call bulit-in function
	TArray<FString> Errors = DataTable->CreateTableFromJSONString(JSONString);

	if (Errors.Num())
	{
		// It has some error message
		for (const FString& Error : Errors)
		{
			UE_LOG(LogUtiliesNode, Warning, TEXT("%s"), *Error);
		}
		return false;
	}

	return true;
}

bool UDataTableBFLibrary::FillDataTableFromJSONFile(UDataTable* DataTable, const FString& JSONFilePath)
{
	FString JSONString;
	if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*JSONFilePath))
	{
		// Supports all combination of ANSI/Unicode files and platforms.
		FFileHelper::LoadFileToString(JSONString, *JSONFilePath);
	}
	else
	{
		UE_LOG(LogUtiliesNode, Warning, TEXT("FillDataTableFromJSONFile -> Cannot find CSV file %s"), *JSONFilePath);
		return false;
	}
	return UDataTableBFLibrary::FillDataTableFromJSONString(DataTable, JSONString);
}

void UDataTableBFLibrary::GetDataTableAsCSVString(UDataTable* DataTable, FString& CSVString)
{
	CSVString = FString();

	if (!DataTable || (DataTable->RowStruct == nullptr))
	{
		UE_LOG(LogTemp, Warning, TEXT("UGenericMiscLibrary::GetTableAsCSV : Missing DataTable or RowStruct !"));
		return;
	}

	// First build array of properties
	TArray<FProperty*> StructProps;
	for (TFieldIterator<FProperty> It(DataTable->RowStruct); It; ++It)
	{
		FProperty* Prop = *It;
		check(Prop != nullptr);
		StructProps.Add(Prop);
	}

	// First row, column titles, taken from properties
	CSVString += TEXT("---");
	for (int32 PropIdx = 0; PropIdx < StructProps.Num(); PropIdx++)
	{
		CSVString += TEXT(",");
		CSVString += StructProps[PropIdx]->GetName();
	}
	CSVString += TEXT("\n");

	// Now iterate over rows
	for (auto RowIt = DataTable->GetRowMap().CreateConstIterator(); RowIt; ++RowIt)
	{
		FName RowName = RowIt.Key();
		CSVString += RowName.ToString();

		uint8* RowData = RowIt.Value();
		for (int32 PropIdx = 0; PropIdx < StructProps.Num(); PropIdx++)
		{
			CSVString += TEXT(",");
			CSVString += DataTableUtils::GetPropertyValueAsString(StructProps[PropIdx], RowData, EDataTableExportFlags::None);
		}
		CSVString += TEXT("\n");
	}
}



void UDataTableBFLibrary::GetDataTableAsCSVFile(UDataTable* DataTable, const FString& CSVFilePath)
{
	FString CSVString;
	UDataTableBFLibrary::GetDataTableAsCSVString(DataTable, CSVString);
	if (CSVString.Len() == 0)
	{
		return;
	}
	FFileHelper::SaveStringToFile(CSVString, *CSVFilePath, FFileHelper::EEncodingOptions::ForceUTF8);
}

蓝图调用:

15、Json读写

UE4包含Json和JsonUtilities这两个模块

原文链接:【UE4】UE4读写Json文件 - Goulandis

void UDataTableBFLibrary::CreateJson()
{
	FString filePath = FPaths::GetProjectFilePath() + TEXT("MysqlConfig/Connect.json");
	FString jsonStr;
	TSharedRef<TJsonWriter<>> jsonWriter = TJsonWriterFactory<>::Create(&jsonStr);
	jsonWriter->WriteObjectStart();
	jsonWriter->WriteValue(TEXT("server"), TEXT("127.0.0.1"));
	jsonWriter->WriteObjectEnd();
	jsonWriter->Close();
	FFileHelper::SaveStringToFile(jsonStr, *filePath);
}

序列化写入:

void AMyActor::Test()
{
	TSharedPtr<FJsonObject> rootObj = MakeShareable(new FJsonObject());
	rootObj->SetStringField("root", "1");
	TArray<TSharedPtr<FJsonValue>> arrValue;
	TSharedPtr<FJsonValueString> tmp = MakeShareable(new FJsonValueString("array"));
	arrValue.Add(tmp);
	rootObj->SetArrayField("array", arrValue);
	FString filePath = FPaths::GameContentDir() + TEXT("MysqlConfig/text.json");
	FString jsonStr;
	TSharedRef<TJsonWriter<TCHAR>> jsonWriter = TJsonWriterFactory<TCHAR>::Create(&jsonStr);
	FJsonSerializer::Serialize(rootObj.ToSharedRef(), jsonWriter);
	FFileHelper::SaveStringToFile(jsonStr, *filePath);
	UE_LOG(LogTemp, Error, TEXT("%s"),*filePath);
}

反序列化读取:

TArray<FName> AMysqlJsonCpp::ReadMysqlConnectConfig()
{
	FString filePath = FPaths::GameContentDir() + TEXT("MysqlConfig/Connect.json");
	if (FPaths::FileExists(filePath))
	{
		FString server;
		FString dbName;
		FString userId;
		FString passwd;
		TArray<FName> connectConfig;
		FString fileStr;
		FFileHelper::LoadFileToString(fileStr, *filePath);
		TSharedPtr<FJsonObject> rootObject = MakeShareable(new FJsonObject());
		TSharedRef<TJsonReader<>> jsonReader = TJsonReaderFactory<>::Create(fileStr);
		if (FJsonSerializer::Deserialize(jsonReader, rootObject))
		{
			server = rootObject->GetStringField("server");
			dbName = rootObject->GetStringField("dbName");
			userId = rootObject->GetStringField("userId");
			passwd = rootObject->GetStringField("passwd");
		}
		connectConfig.Add(FName(*server));
		connectConfig.Add(FName(*dbName));
		connectConfig.Add(FName(*userId));
		connectConfig.Add(FName(*passwd));
	}

	return TArray<FName>();
}
 

源码仓库:张乂卓从头学UE4/UE4Learn_DataDeriven

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张乂卓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值