初级:
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>();
}