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);
	}
}
相关推荐
ue星空10 小时前
UE5用TextureGraph制作瓷砖贴图材质
ue5·材质
藤蔓疯长10 小时前
UE5骨骼插槽蓝图
ue5
飞起的猪10 小时前
【虚幻引擎】UE5独立游戏开发全流程(商业级架构)
ue5·游戏引擎·游戏开发·虚幻·独立开发·游戏设计·引擎架构
朗迹 - 张伟1 天前
UE5 PCG学习笔记
笔记·学习·ue5
笑鸿的学习笔记2 天前
虚幻引擎5-Unreal Engine笔记之摄像机与场景捕获相关概念的解析
笔记·ue5·虚幻
☆平常心☆3 天前
UE5通过C++实现TcpSocket连接
c++·ue5
电子云与长程纠缠3 天前
UE5中制作动态数字Decal
学习·ue5·编辑器·贴图
笑鸿的学习笔记4 天前
虚幻引擎5-Unreal Engine笔记之常用核心类的继承关系
笔记·ue5·虚幻
笑鸿的学习笔记5 天前
虚幻引擎5-Unreal Engine笔记之UE编辑器退出时的保存弹框
笔记·ue5·虚幻