UE5.3 C++ 房屋管理系统(二)

三.当房屋生成成功,我们就需要把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);
	}
}
相关推荐
不爱说话的采儿1 天前
UE5详细保姆教程(第四章)
笔记·ue5·游戏引擎·课程设计
二DUAN帝1 天前
UE实现路径回放、自动驾驶功能简记
人工智能·websocket·机器学习·ue5·自动驾驶·ue4·cesiumforue
温玉琳琅1 天前
【UE5】虚幻引擎小百科
ue5·游戏引擎·虚幻
远离UE42 天前
UE 材质 变体 概念
ue5·材质
吴梓穆5 天前
UE5 重新编译插件版本
ue5
HECUgauss5 天前
UE5 使用过程遇到的问题
ue5
小白学过的代码5 天前
ue5.4和webul通信
开发语言·javascript·ue5
m0_552200825 天前
《UE5_C++多人TPS完整教程》学习笔记40 ——《P41 装备(武器)姿势(Equipped Pose)》
c++·游戏·ue5
漫游者Nova5 天前
虚幻引擎Unreal Engine5恐怖游戏设计制作教程,从入门到精通从零开始完整项目开发实战详细讲解中英字幕
ue5·游戏引擎·虚幻·游戏开发完整教程·恐怖游戏开发
ue星空7 天前
UE5音频技术
ue5