三.当房屋生成成功,我们就需要把TMap里的数据存到数据库里。不然一点停止运行,就会所以数据都不见了。这里使用DataTable来存储。
1.DataTable是UE常用的表,虽然不是专门用来存档的,但也可以这么用。
DataTable表,实际是每一行的名字,对于每一行的内容。它可以根据你的结构体自动转换为表的每一行。
我们首先创造结构体,继承自TableRowBase。就是表行的基类,里面的数据类型,和TMap里BuildInfo保持一致,方便同步。
cpp
struct FBuildTableStruct:public FTableRowBase
{
GENERATED_USTRUCT_BODY();
UPROPERTY(EditAnywhere)
int ID = 0;
//类型
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Type = "";
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int Area = 100;
//使用人数()
//蓝图可访问通信
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int ResidentPopulation = 100;
//价值()
//蓝图可访问通信
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int Pirce = 100;
//位置
//蓝图可访问通信
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FVector Position = FVector::Zero();
//方位
//蓝图可访问通信
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FRotator Rotation = FRotator::ZeroRotator;
// 大小
//蓝图可访问通信
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FVector Scale = FVector(1, 1, 1);
};
创建表,并选择表里的每一行的数据是上面的结构体。


表里的RowName,是系统自动添加的用于标识每一行。一开始表是空的,这是已经存入数据后的样子。

2.我们就写一个ATableManagerActor来管理存储。前面的是通用的,对表Tablet的数据进行增删查改。后面是根据不同的需求,封装了前面对表操作的功能。核心目的就是把 TMap里的数据,随时同步到Table里去。它们之间的主要是靠ID属性对应,RowName 保持和 ID相同。
cpp
ATableManagerActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ATableManagerActor();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
UFUNCTION(BlueprintCallable, DisplayName = "clearDataTable", Category = "DataTable")
void clearDataTable(UDataTable* DataTable);
UFUNCTION(BlueprintCallable, DisplayName = "addDataTableRow", Category = "DataTable")
void addDataTableRow(UDataTable* DataTable, FName rowName, const FBuildTableStruct& row);
UFUNCTION(BlueprintCallable, DisplayName = "removeDataTableRow", Category = "DataTable")
void removeDataTableRow(UDataTable* DataTable, FName rowName);
UFUNCTION(BlueprintCallable,DisplayName = "EditeDataTableRow",Category = "DataTable")
void editeDataTableRow(FBuildTableStruct tmp);
//从表里拿所有的信息
UFUNCTION(BlueprintCallable, DisplayName = "findAllRow", Category = "DataTable")
void findAllRow();
//从表里拿删除所有的信息
UFUNCTION(BlueprintCallable, DisplayName = "findAllRow", Category = "DataTable")
void deletAllRow();
UFUNCTION(BlueprintCallable, DisplayName = "saveToALLTable", Category = "DataTable")
void saveToALLTable();
UFUNCTION(BlueprintCallable, DisplayName = "DataTableToCSV", Category = "DataTable")
void DataTableToCSV();
UFUNCTION(BlueprintCallable, DisplayName = "DataTableToCSV", Category = "DataTable")
FBuildTableStruct GetBuildInfoFromDT(int ID);
UFUNCTION(BlueprintCallable, DisplayName = "DataTableToCSV", Category = "DataTable")
void CommiteBuildInfo();
UFUNCTION(BlueprintCallable, DisplayName = "Inittial", Category = "DataTable")
void Inittial();
UFUNCTION(BlueprintCallable, DisplayName = "ShowClickBuild",Category = "DataTable")
void ShowClickBuildInfo(ABuildBase* curBuid);
UFUNCTION()
void SetBuildEditUI(ULZJUserWidget* UI);
UPROPERTY()
UDataTable* BuildInfoDataTable;
UPROPERTY()
TMap<int,FBuildTableStruct> Rows;
UPROPERTY()
UBuildManagerInstance* BuildManagerIns;
UPROPERTY()
UBuildFactory* BuildFactory;
//
UPROPERTY()
ABuildBase* ClickBuild;
UPROPERTY()
FBuildTableStruct ClicBuildInfo;
UPROPERTY()
ULZJUserWidget* BuildEditUI;
bool isClick;
};
3.我们开始实现,每一行数据存入表中。首先拿到表的资源,再拿到上篇文章的 房屋管理者。然后实现,对表的增删查改。当房屋管理者的TMap发生改变,也对表里的数据进行同样操作。
cpp
// Called when the game starts or when spawned
void ATableManagerActor::BeginPlay()
{
Super::BeginPlay();
BuildInfoDataTable = LoadObject<UDataTable>(this, TEXT("/Script/Engine.DataTable'/LZJCore/DTBuildInfo.DTBuildInfo'"));
findAllRow();
BuildManagerIns = GetWorld()->GetGameInstance()->GetSubsystem<UBuildManagerInstance>();
BuildFactory = GetWorld()->GetGameInstance()->GetSubsystem<UBuildFactory>();
//TArray<AActor*> TBActors;
//UGameplayStatics::GetAllActorsOfClass(GetWorld(), ATableManagerActor::StaticClass(), TBActors);
TArray<UUserWidget*> Actors;
//TArray<UUserWidget*>& FoundWidgets, TSubclassOf<UUserWidget> WidgetClass,
UWidgetBlueprintLibrary::GetAllWidgetsOfClass(GetWorld(), Actors, ULZJUserWidget::StaticClass());
if (!Actors.IsEmpty())
{
BuildEditUI = Cast<ULZJUserWidget>(Actors[0]);
}
}
// Called every frame
void ATableManagerActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ATableManagerActor::clearDataTable(UDataTable* DataTable)
{
if (DataTable == nullptr)
{
return;
}
DataTable->EmptyTable();
DataTable->GetOutermost()->MarkPackageDirty();
}
void ATableManagerActor::addDataTableRow(UDataTable* DataTable, FName rowName, const FBuildTableStruct& row)
{
if (DataTable == nullptr)
{
return;
}
DataTable->AddRow(rowName, row);
DataTable->GetOutermost()->MarkPackageDirty();
}
void ATableManagerActor::removeDataTableRow(UDataTable* DataTable, FName rowName)
{
if (DataTable == nullptr)
{
return;
}
DataTable->RemoveRow(rowName);
DataTable->GetOutermost()->MarkPackageDirty();
}
void ATableManagerActor::editeDataTableRow(FBuildTableStruct tmp)
{
if (BuildInfoDataTable->IsValidLowLevel())
{
FString Str = FString::FromInt(tmp.ID); // 行名
FName RowName = FName(Str);
FBuildTableStruct* RowData = BuildInfoDataTable->FindRow<FBuildTableStruct>(RowName, TEXT("Context"));
if (RowData)
{
RowData->Area = tmp.Area;
RowData->Pirce = tmp.Pirce;
RowData->ResidentPopulation = tmp.ResidentPopulation;
//RowData->= tmp.Area;
BuildInfoDataTable->MarkPackageDirty(); // 标记为需要保存
}
}
}
void ATableManagerActor::findAllRow()
{
if (BuildInfoDataTable->IsValidLowLevel())
{
//BuildInfoDataTable->GetTableData();
if (!BuildInfoDataTable) return;
TArray<FName> RowNames = BuildInfoDataTable->GetRowNames();
for (const auto& Name : RowNames)
{
for (auto it : BuildInfoDataTable->GetRowMap())
{
FString rowName = (it.Key).ToString();
//FBuildTableStruct为你的FStruct
FBuildTableStruct* pRow = (FBuildTableStruct*)it.Value;
//输出需根据你的FStruct进行调整
//UE_LOG(LogTemp, Warning, TEXT("read by traversal --- RowName:%s, Name:%s, price:%d, introduct:%s"), *rowName, *(pRow->ID), pRow->ProductPrice, *(pRow->ProductIntroduce));
Rows.Add(pRow->ID,*pRow);
}
}
}
}
void ATableManagerActor::deletAllRow()
{
}
void ATableManagerActor::saveToALLTable()
{
if (BuildInfoDataTable->IsValidLowLevel())
{
//BuildInfoDataTable->GetTableData();
if (!BuildInfoDataTable) return;
TArray<FName> RowNames = BuildInfoDataTable->GetRowNames();
TMap<int, ABuildBase*> Cpoy = BuildManagerIns->m_TargetMap; //拷贝值
for (auto& Elem : Cpoy)
{
ABuildBase* curBuildBase = Elem.Value;
FBuildTableStruct* BuildInfo = new FBuildTableStruct(); //结构体
BuildInfo->ID = curBuildBase->m_targetID;
FString IntString = FString::FromInt(BuildInfo->ID);
FName RowName = FName(*IntString);
BuildInfo->Area = curBuildBase->m_Area;
BuildInfo->ResidentPopulation = curBuildBase->m_ResidentPopulation;
BuildInfo->Pirce = curBuildBase->m_Price;
//BuildInfo->ResidentPopulation = curBuildBase->m_ResidentPopulation;
BuildInfo->Type = curBuildBase->m_Type;
BuildInfo->Position = curBuildBase->m_Position;
BuildInfo->Rotation = curBuildBase->m_Rotation;
BuildInfoDataTable->AddRow(RowName, *BuildInfo);
}
保存为资产
/*FString PackageName = TEXT("/Game/Data/DynamicDataTable");
UPackage* Package = CreatePackage(*PackageName);
DynamicDataTable->Rename(*FPaths::GetBaseFilename(PackageName), Package);
Package->MarkPackageDirty();
FAssetRegistryModule::AssetCreated(DynamicDataTable);
FString PackageFileName = FPackageName::LongPackageNameToFilename(
PackageName, FPackageName::GetAssetPackageExtension());
bool bSaved = UPackage::SavePackage(
Package,
DynamicDataTable,
RF_Public | RF_Standalone,
*PackageFileName);
if (bSaved)
{
UE_LOG(LogTemp, Log, TEXT("Dynamic DataTable saved successfully!"));
}*/
//UPackage* Package = FindPackage(nullptr, *FPackageName::FilenameToLongPackageName(BuildInfoDataTable->GetPathName()));
//if (Package)
//{
// Package->SetDirtyFlag(true);
//const TSoftObjectPtr<UDataTable> SourceDataTable = BuildInfoDataTable;
//UEditorAssetLibrary::SaveAsset(SourceDataTable, false);
//}
}
/*Tarray<UPackage*>PackageToSave;
PackageToSave.Add(Table->GetOutermost());
FEditorFileUtils::EPromptReturnCode RetValue = FEditorFileUtils::PromptForCheckoutAndSave(PackageToSave, false, false);*/
TArray<UPackage*> PackagesToSave;
PackagesToSave.Add(BuildInfoDataTable->GetOutermost());
FEditorFileUtils::PromptForCheckoutAndSave(PackagesToSave, false, /*bPromptToSave=*/ false);
}
void ATableManagerActor::DataTableToCSV()
{
FString Path = FPaths::ProjectDir() + TEXT("DataDrive/UserInfo2.csv");
Path = FPaths::ConvertRelativePathToFull(*Path);
FPlatformFileManager::Get().Get().GetPlatformFile().DeleteFile(*Path);
if (BuildInfoDataTable)
{
FString CSVString = BuildInfoDataTable->GetTableAsCSV();
FString CSVPath = FPaths::ProjectDir() + TEXT("DataDrive/UserInfo2.csv");
FFileHelper::SaveStringToFile(CSVString, *CSVPath, FFileHelper::EEncodingOptions::ForceUTF8);
}
}
FBuildTableStruct ATableManagerActor::GetBuildInfoFromDT(int ID)
{
FBuildTableStruct tmp;
if (BuildInfoDataTable->IsValidLowLevel())
{
FString Str = FString::FromInt(ID); // 行名
FName RowName = FName(Str);
FBuildTableStruct* RowData = BuildInfoDataTable->FindRow<FBuildTableStruct>(RowName, TEXT("Context"));
if (RowData)
{
// 使用找到的数据
UE_LOG(LogTemp, Warning, TEXT("Health: %d"), RowData->ID);
tmp = *RowData;
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Row not found!"));
}
}
return tmp;
}
void ATableManagerActor::CommiteBuildInfo()
{
FBuildTableStruct tmp;
}
void ATableManagerActor::Inittial()
{
findAllRow();
//TMap<int, FBuildTableStruct> Rows;
// 假设MyMap已有数据...
//BuildManagerIns->InitialBuilds(Rows);
//for (auto It = Rows.CreateIterator(); It; ++It) {
// int ID = It.Key(); // 获取键
// FBuildTableStruct Build = It.Value(); // 获取值
// //UE_LOG(LogTemp, Warning, TEXT("Key: %s, Value: %d"), *Key, Value);
//}
BuildFactory->InitialBuilds(Rows);
}
//拿到点击的 ID,并查表拿到它的建筑的信息》
void ATableManagerActor::ShowClickBuildInfo(ABuildBase* curBuid)
{
if (curBuid->IsValidLowLevel())
{
int ID = curBuid->m_targetID;
ClicBuildInfo = GetBuildInfoFromDT(ID);
isClick = true;
if (BuildEditUI)
{
BuildEditUI->ShowEditBuildInfo(ClicBuildInfo);
}
}
else
{
return;
}
isClick = false;
}
void ATableManagerActor::SetBuildEditUI(ULZJUserWidget* UI)
{
BuildEditUI = UI;
}
这里将DataTable 导入到CSV,使用的是DataTable里的API, GetTableAsCSV();
cpp
void ATableManagerActor::DataTableToCSV()
{
FString Path = FPaths::ProjectDir() + TEXT("DataDrive/UserInfo2.csv");
Path = FPaths::ConvertRelativePathToFull(*Path);
FPlatformFileManager::Get().Get().GetPlatformFile().DeleteFile(*Path);
if (BuildInfoDataTable)
{
FString CSVString = BuildInfoDataTable->GetTableAsCSV();
FString CSVPath = FPaths::ProjectDir() + TEXT("DataDrive/UserInfo2.csv");
FFileHelper::SaveStringToFile(CSVString, *CSVPath, FFileHelper::EEncodingOptions::ForceUTF8);
}
}