使用 AutoSave 插件管理文件

修复 AVoxelWorld::CenterAgent 为空时 RE
修复区块不能根据距离正常卸载的问题
This commit is contained in:
_Redstone_c_ 2020-12-13 11:20:17 +08:00
parent d1103c580b
commit 0663e3192e
8 changed files with 168 additions and 107 deletions

View File

@ -6,6 +6,24 @@
#include "ProceduralMeshComponent.h" #include "ProceduralMeshComponent.h"
#include "KismetProceduralMeshLibrary.h" #include "KismetProceduralMeshLibrary.h"
bool FVoxelChunkData::Serialize(FArchive & Slot)
{
UScriptStruct* VoxelBlockStruct = FVoxelBlock::StaticStruct();
for (int32 X = 0; X < 16; ++X)
{
for (int32 Y = 0; Y < 16; ++Y)
{
for (int32 Z = 0; Z < 256; ++Z)
{
VoxelBlockStruct->SerializeItem(Slot, &Blocks[X][Y][Z], nullptr);
}
}
}
return true;
}
AVoxelChunk::AVoxelChunk(const class FObjectInitializer& ObjectInitializer) AVoxelChunk::AVoxelChunk(const class FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer) : Super(ObjectInitializer)
{ {
@ -24,14 +42,35 @@ AVoxelChunk::AVoxelChunk(const class FObjectInitializer& ObjectInitializer)
void AVoxelChunk::BeginPlay() void AVoxelChunk::BeginPlay()
{ {
Super::BeginPlay();
UGameInstance* GameInstance = GetGameInstance(); UGameInstance* GameInstance = GetGameInstance();
VoxelSubsystem = GameInstance->GetSubsystem<UVoxelSubsystem>(); VoxelSubsystem = GameInstance->GetSubsystem<UVoxelSubsystem>();
AttachToActor(GetOwner(), FAttachmentTransformRules::KeepRelativeTransform);
FlushMaterials();
ArchiveFile = VoxelWorld->GetWorldSetting().ArchiveFolder / FString::Printf(TEXT("%08X%08X"), ChunkLocation.X, ChunkLocation.Y);
FSaveStructLoadDelegate OnLoaded;
OnLoaded.BindUFunction(this, TEXT("OnDataLoaded"));
Data = MakeShared<FSaveStructPtr<FVoxelChunkData>>(GetGameInstance()->GetSubsystem<UAutoSaveSubsystem>(), ArchiveFile, OnLoaded);
check(Data->IsValid());
}
void AVoxelChunk::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Data = nullptr;
Super::EndPlay(EndPlayReason);
} }
const FVoxelBlock & AVoxelChunk::GetBlockByRelativeLocation(const FIntVector & Location) const const FVoxelBlock & AVoxelChunk::GetBlockByRelativeLocation(const FIntVector & Location) const
{ {
checkCode( checkCode(
if (!FMath::IsWithin(Location.X, 0, 16) if (!Data->IsLoaded()
|| !FMath::IsWithin(Location.X, 0, 16)
|| !FMath::IsWithin(Location.Y, 0, 16) || !FMath::IsWithin(Location.Y, 0, 16)
|| !FMath::IsWithin(Location.Z, 0, 256)) || !FMath::IsWithin(Location.Z, 0, 256))
{ {
@ -40,13 +79,14 @@ const FVoxelBlock & AVoxelChunk::GetBlockByRelativeLocation(const FIntVector & L
} }
); );
return Blocks[Location.X][Location.Y][Location.Z]; return (*Data)->Blocks[Location.X][Location.Y][Location.Z];
} }
void AVoxelChunk::SetBlockByRelativeLocation(const FIntVector& Location, const FVoxelBlock& NewBlock) void AVoxelChunk::SetBlockByRelativeLocation(const FIntVector& Location, const FVoxelBlock& NewBlock)
{ {
checkCode( checkCode(
if (!FMath::IsWithin(Location.X, 0, 16) if (!Data->IsLoaded()
|| !FMath::IsWithin(Location.X, 0, 16)
|| !FMath::IsWithin(Location.Y, 0, 16) || !FMath::IsWithin(Location.Y, 0, 16)
|| !FMath::IsWithin(Location.Z, 0, 256)) || !FMath::IsWithin(Location.Z, 0, 256))
{ {
@ -55,7 +95,7 @@ void AVoxelChunk::SetBlockByRelativeLocation(const FIntVector& Location, const F
} }
); );
Blocks[Location.X][Location.Y][Location.Z] = NewBlock; (*Data)->Blocks[Location.X][Location.Y][Location.Z] = NewBlock;
FlushMeshFlags |= 1 << (Location.Z / 16); FlushMeshFlags |= 1 << (Location.Z / 16);
@ -146,78 +186,10 @@ void AVoxelChunk::FlushMaterials()
} }
} }
void AVoxelChunk::Load()
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_VoxelChunk_Load);
if (VoxelWorld->GetWorldSetting().ArchiveFolder.IsEmpty())
{
ArchiveFile.Empty();
return;
}
ArchiveFile = VoxelWorld->GetWorldSetting().ArchiveFolder / FString::Printf(TEXT("%08X%08X"), ChunkLocation.X, ChunkLocation.Y) + ChunkFileExtension;
if (FPaths::FileExists(ArchiveFile))
{
TArray<uint8> ChunkDataBuffer;
if (FFileHelper::LoadFileToArray(ChunkDataBuffer, *ArchiveFile))
{
FMemoryReader MemoryReader(ChunkDataBuffer);
UScriptStruct* VoxelBlockStruct = FVoxelBlock::StaticStruct();
for (int32 X = 0; X < 16; ++X)
{
for (int32 Y = 0; Y < 16; ++Y)
{
for (int32 Z = 0; Z < 256; ++Z)
{
VoxelBlockStruct->SerializeItem(MemoryReader, &Blocks[X][Y][Z], nullptr);
}
}
}
UE_LOG(LogVoxel, Log, TEXT("Load Chunk %d, %d From File '%s'"), ChunkLocation.X, ChunkLocation.Y, *ArchiveFile);
}
}
}
void AVoxelChunk::Unload()
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_VoxelChunk_Unload);
if (ArchiveFile.IsEmpty()) return;
TArray<uint8> ChunkDataBuffer;
FMemoryWriter MemoryWriter(ChunkDataBuffer);
UScriptStruct* VoxelBlockStruct = FVoxelBlock::StaticStruct();
for (int32 X = 0; X < 16; ++X)
{
for (int32 Y = 0; Y < 16; ++Y)
{
for (int32 Z = 0; Z < 256; ++Z)
{
VoxelBlockStruct->SerializeItem(MemoryWriter, &Blocks[X][Y][Z], nullptr);
}
}
}
if (FFileHelper::SaveArrayToFile(ChunkDataBuffer, *ArchiveFile))
{
UE_LOG(LogVoxel, Log, TEXT("Save Chunk %d, %d To File '%s'"), ChunkLocation.X, ChunkLocation.Y, *ArchiveFile);
}
else
{
UE_LOG(LogVoxel, Error, TEXT("Failed To Save Chunk %d, %d To File '%s'"), ChunkLocation.X, ChunkLocation.Y, *ArchiveFile);
}
}
void AVoxelChunk::FlushMeshSection(int32 SectionIndex) void AVoxelChunk::FlushMeshSection(int32 SectionIndex)
{ {
if (!Data->IsLoaded()) return;
static FVoxelMeshData CubeTopFaceBuffer = FVoxelMeshData::CubeTopFace; static FVoxelMeshData CubeTopFaceBuffer = FVoxelMeshData::CubeTopFace;
static FVoxelMeshData CubeBottomFaceBuffer = FVoxelMeshData::CubeBottomFace; static FVoxelMeshData CubeBottomFaceBuffer = FVoxelMeshData::CubeBottomFace;
static FVoxelMeshData CubeFrontFaceBuffer = FVoxelMeshData::CubeFrontFace; static FVoxelMeshData CubeFrontFaceBuffer = FVoxelMeshData::CubeFrontFace;
@ -244,16 +216,16 @@ void AVoxelChunk::FlushMeshSection(int32 SectionIndex)
{ {
for (int32 Z = 0 + SectionIndex * 16; Z < 16 + SectionIndex * 16; ++Z) for (int32 Z = 0 + SectionIndex * 16; Z < 16 + SectionIndex * 16; ++Z)
{ {
const FVoxelBlockType& CurrentVoxelBlock = VoxelSubsystem->GetBlockType(Blocks[X][Y][Z].Type); const FVoxelBlockType& CurrentVoxelBlock = VoxelSubsystem->GetBlockType((*Data)->Blocks[X][Y][Z].Type);
if (CurrentVoxelBlock.Shape != EVoxelBlockShape::Cube) continue; if (CurrentVoxelBlock.Shape != EVoxelBlockShape::Cube) continue;
const FVoxelBlockType& TopVoxelBlock = VoxelSubsystem->GetBlockType(Z + 1 < 256 ? Blocks[X][Y][Z + 1].Type : TEXT("Air")); const FVoxelBlockType& TopVoxelBlock = VoxelSubsystem->GetBlockType(Z + 1 < 256 ? (*Data)->Blocks[X][Y][Z + 1].Type : TEXT("Air"));
const FVoxelBlockType& BottomVoxelBlock = VoxelSubsystem->GetBlockType(Z - 1 >= 0 ? Blocks[X][Y][Z - 1].Type : TEXT("Air")); const FVoxelBlockType& BottomVoxelBlock = VoxelSubsystem->GetBlockType(Z - 1 >= 0 ? (*Data)->Blocks[X][Y][Z - 1].Type : TEXT("Air"));
const FVoxelBlockType& FrontVoxelBlock = VoxelSubsystem->GetBlockType(X + 1 < 16 ? Blocks[X + 1][Y][Z].Type : (FrontChunk ? FrontChunk->GetBlockByRelativeLocation(FIntVector(0, Y, Z)).Type : TEXT("Air"))); const FVoxelBlockType& FrontVoxelBlock = VoxelSubsystem->GetBlockType(X + 1 < 16 ? (*Data)->Blocks[X + 1][Y][Z].Type : (FrontChunk ? FrontChunk->GetBlockByRelativeLocation(FIntVector(0, Y, Z)).Type : TEXT("Air")));
const FVoxelBlockType& BackVoxelBlock = VoxelSubsystem->GetBlockType(X - 1 >= 0 ? Blocks[X - 1][Y][Z].Type : (BackChunk ? BackChunk->GetBlockByRelativeLocation(FIntVector(15, Y, Z)).Type : TEXT("Air"))); const FVoxelBlockType& BackVoxelBlock = VoxelSubsystem->GetBlockType(X - 1 >= 0 ? (*Data)->Blocks[X - 1][Y][Z].Type : (BackChunk ? BackChunk->GetBlockByRelativeLocation(FIntVector(15, Y, Z)).Type : TEXT("Air")));
const FVoxelBlockType& LeftVoxelBlock = VoxelSubsystem->GetBlockType(Y - 1 >= 0 ? Blocks[X][Y - 1][Z].Type : (LeftChunk ? LeftChunk->GetBlockByRelativeLocation(FIntVector(X, 15, Z)).Type : TEXT("Air"))); const FVoxelBlockType& LeftVoxelBlock = VoxelSubsystem->GetBlockType(Y - 1 >= 0 ? (*Data)->Blocks[X][Y - 1][Z].Type : (LeftChunk ? LeftChunk->GetBlockByRelativeLocation(FIntVector(X, 15, Z)).Type : TEXT("Air")));
const FVoxelBlockType& RightVoxelBlock = VoxelSubsystem->GetBlockType(Y + 1 < 16 ? Blocks[X][Y + 1][Z].Type : (RightChunk ? RightChunk->GetBlockByRelativeLocation(FIntVector(X, 0, Z)).Type : TEXT("Air"))); const FVoxelBlockType& RightVoxelBlock = VoxelSubsystem->GetBlockType(Y + 1 < 16 ? (*Data)->Blocks[X][Y + 1][Z].Type : (RightChunk ? RightChunk->GetBlockByRelativeLocation(FIntVector(X, 0, Z)).Type : TEXT("Air")));
if (TopVoxelBlock.Shape != EVoxelBlockShape::Cube) if (TopVoxelBlock.Shape != EVoxelBlockShape::Cube)
{ {
@ -321,3 +293,8 @@ void AVoxelChunk::FlushMeshSection(int32 SectionIndex)
true true
); );
} }
void AVoxelChunk::OnDataLoaded(const FString & Filename)
{
VoxelWorld->AddChunkToMeshFlushBuffer(ChunkLocation);
}

View File

@ -1,20 +1,46 @@
#include "VoxelHelper.h" #include "VoxelHelper.h"
#include "VoxelWorld.h" #include "VoxelWorld.h"
#include "Kismet/GameplayStatics.h"
AVoxelWorld * UVoxelHelper::CreateVoxelWorld(UObject* WorldContextObject, const FVoxelWorldSetting& WorldSetting) AVoxelWorld * UVoxelHelper::CreateVoxelWorld(UObject* WorldContextObject, const FVoxelWorldSetting& WorldSetting)
{ {
if (!IsWorldSettingValid(WorldContextObject, WorldSetting)) return nullptr;
UWorld* World = WorldContextObject->GetWorld(); UWorld* World = WorldContextObject->GetWorld();
if (!World) return nullptr; if (!World) return nullptr;
AVoxelWorld* VoxelWorld = World->SpawnActor<AVoxelWorld>(); AVoxelWorld* VoxelWorld = Cast<AVoxelWorld>(
UGameplayStatics::BeginDeferredActorSpawnFromClass(
World,
AVoxelWorld::StaticClass(),
FTransform(),
ESpawnActorCollisionHandlingMethod::AlwaysSpawn,
nullptr
)
);
VoxelWorld->WorldSetting = WorldSetting; VoxelWorld->WorldSetting = WorldSetting;
UGameplayStatics::FinishSpawningActor(VoxelWorld, FTransform());
return VoxelWorld; return VoxelWorld;
} }
bool UVoxelHelper::IsWorldSettingValid(UObject * WorldContextObject, const FVoxelWorldSetting & WorldSetting)
{
FString TestFilePath = WorldSetting.ArchiveFolder / TEXT("TestFile");
if (!FFileHelper::SaveStringToFile(TEXT(""), *TestFilePath))
return false;
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
PlatformFile.DeleteFile(*TestFilePath);
return true;
}
void UVoxelHelper::WorldToRelativeLocation(const FIntVector & InWorldLocation, FIntPoint & OutChunkLocation, FIntVector & OutRelativeLocation) void UVoxelHelper::WorldToRelativeLocation(const FIntVector & InWorldLocation, FIntPoint & OutChunkLocation, FIntVector & OutRelativeLocation)
{ {
OutChunkLocation.X = InWorldLocation.X / 16; OutChunkLocation.X = InWorldLocation.X / 16;

View File

@ -6,6 +6,7 @@
#include "Block/VoxelBlock.h" #include "Block/VoxelBlock.h"
#include "Chunk/VoxelChunk.h" #include "Chunk/VoxelChunk.h"
#include "VoxelAgentInterface.h" #include "VoxelAgentInterface.h"
#include "Kismet/GameplayStatics.h"
const TArray<FIntPoint> ChunkLoadOrder = const TArray<FIntPoint> ChunkLoadOrder =
{ {
@ -160,6 +161,10 @@ void AVoxelWorld::BeginPlay()
UGameInstance* GameInstance = GetGameInstance(); UGameInstance* GameInstance = GetGameInstance();
VoxelSubsystem = GameInstance->GetSubsystem<UVoxelSubsystem>(); VoxelSubsystem = GameInstance->GetSubsystem<UVoxelSubsystem>();
Data = MakeShared<FSaveStructPtr<FVoxelWorldData>>(GetGameInstance()->GetSubsystem<UAutoSaveSubsystem>(), WorldSetting.ArchiveFolder / TEXT("VoxelWorld"));
check(Data->IsValid());
} }
void AVoxelWorld::Tick(float DeltaSeconds) void AVoxelWorld::Tick(float DeltaSeconds)
@ -169,7 +174,6 @@ void AVoxelWorld::Tick(float DeltaSeconds)
ManageChunk(); ManageChunk();
FlushMeshs(); FlushMeshs();
} }
void AVoxelWorld::EndPlay(const EEndPlayReason::Type EndPlayReason) void AVoxelWorld::EndPlay(const EEndPlayReason::Type EndPlayReason)
@ -180,6 +184,8 @@ void AVoxelWorld::EndPlay(const EEndPlayReason::Type EndPlayReason)
for (const FIntPoint& Chunk : ChunksToUnload) for (const FIntPoint& Chunk : ChunksToUnload)
UnloadChunk(Chunk); UnloadChunk(Chunk);
Data = nullptr;
Super::EndPlay(EndPlayReason); Super::EndPlay(EndPlayReason);
} }
@ -223,14 +229,22 @@ void AVoxelWorld::LoadChunk(const FIntPoint & ChunkLocation)
check(World); check(World);
AVoxelChunk* NewVoxelChunk = World->SpawnActor<AVoxelChunk>(); FTransform ChunkTransform(FVector(ChunkLocation.X * 1600.0f, ChunkLocation.Y * 1600.0f, 0.0f));
AVoxelChunk* NewVoxelChunk = Cast<AVoxelChunk>(
UGameplayStatics::BeginDeferredActorSpawnFromClass(
this,
AVoxelChunk::StaticClass(),
ChunkTransform,
ESpawnActorCollisionHandlingMethod::AlwaysSpawn,
this
)
);
NewVoxelChunk->VoxelWorld = this; NewVoxelChunk->VoxelWorld = this;
NewVoxelChunk->ChunkLocation = ChunkLocation; NewVoxelChunk->ChunkLocation = ChunkLocation;
NewVoxelChunk->SetActorLocation(FVector(ChunkLocation.X * 1600.0f, ChunkLocation.Y * 1600.0f, 0.0f));
NewVoxelChunk->AttachToActor(this, FAttachmentTransformRules::KeepRelativeTransform); UGameplayStatics::FinishSpawningActor(NewVoxelChunk, ChunkTransform);
NewVoxelChunk->FlushMaterials();
NewVoxelChunk->Load();
AddChunkToMeshFlushBuffer(ChunkLocation);
Chunks.Add(ChunkLocation, NewVoxelChunk); Chunks.Add(ChunkLocation, NewVoxelChunk);
@ -241,7 +255,6 @@ void AVoxelWorld::UnloadChunk(const FIntPoint & ChunkLocation)
{ {
if (!Chunks.Contains(ChunkLocation)) return; if (!Chunks.Contains(ChunkLocation)) return;
Chunks[ChunkLocation]->Unload();
Chunks[ChunkLocation]->Destroy(); Chunks[ChunkLocation]->Destroy();
Chunks.Remove(ChunkLocation); Chunks.Remove(ChunkLocation);
@ -259,9 +272,16 @@ void AVoxelWorld::FlushMaterials()
void AVoxelWorld::ManageChunk() void AVoxelWorld::ManageChunk()
{ {
FIntPoint RootChunk; if (GetGameInstance()->GetSubsystem<UAutoSaveSubsystem>()->GetIdleThreadNum() <= 0) return;
FIntPoint RootChunk = FIntPoint(0, 0);
if (CenterAgent.GetObject())
{
FIntVector RLocation; FIntVector RLocation;
UVoxelHelper::WorldToRelativeLocation(IVoxelAgentInterface::Execute_GetAgentLocation(CenterAgent.GetObject()), RootChunk, RLocation); UVoxelHelper::WorldToRelativeLocation(IVoxelAgentInterface::Execute_GetAgentLocation(CenterAgent.GetObject()), RootChunk, RLocation);
}
// Load // Load
for (const FIntPoint& Chunk : ChunkLoadOrder) for (const FIntPoint& Chunk : ChunkLoadOrder)
@ -286,7 +306,7 @@ void AVoxelWorld::ManageChunk()
const FIntPoint WorldLocation = Chunk.Key; const FIntPoint WorldLocation = Chunk.Key;
const FIntPoint RelativeLocation = WorldLocation - RootChunk; const FIntPoint RelativeLocation = WorldLocation - RootChunk;
const bool bInUnloadDistance = FMath::Abs(RelativeLocation.X) > ChunkUnloadDistance && FMath::Abs(RelativeLocation.Y) > ChunkUnloadDistance; const bool bInUnloadDistance = FMath::Abs(RelativeLocation.X) > ChunkUnloadDistance || FMath::Abs(RelativeLocation.Y) > ChunkUnloadDistance;
if (bInUnloadDistance) if (bInUnloadDistance)
{ {

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "SaveStruct.h"
#include "Block/VoxelBlock.h" #include "Block/VoxelBlock.h"
#include "GameFramework/Actor.h" #include "GameFramework/Actor.h"
#include "VoxelChunk.generated.h" #include "VoxelChunk.generated.h"
@ -9,7 +10,24 @@ class AVoxelWorld;
class UVoxelSubsystem; class UVoxelSubsystem;
class UProceduralMeshComponent; class UProceduralMeshComponent;
const FString ChunkFileExtension = TEXT(".voxelchunk"); USTRUCT()
struct FVoxelChunkData : public FSaveStruct
{
GENERATED_BODY()
FVoxelBlock Blocks[16][16][256];
bool Serialize(FArchive& Slot);
};
template<>
struct TStructOpsTypeTraits<FVoxelChunkData> : public TStructOpsTypeTraitsBase2<FVoxelChunkData>
{
enum
{
WithSerializer = true,
};
};
UCLASS(BlueprintType) UCLASS(BlueprintType)
class VOXEL_API AVoxelChunk : public AActor class VOXEL_API AVoxelChunk : public AActor
@ -24,6 +42,8 @@ public:
virtual void BeginPlay() override; virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
UFUNCTION(BlueprintCallable, Category = "Voxel|Chunk") UFUNCTION(BlueprintCallable, Category = "Voxel|Chunk")
AVoxelWorld* GetVoxelWorld() const { return VoxelWorld; } AVoxelWorld* GetVoxelWorld() const { return VoxelWorld; }
@ -59,16 +79,15 @@ private:
uint16 FlushMeshFlags; uint16 FlushMeshFlags;
FVoxelBlock Blocks[16][16][256]; TSharedPtr<FSaveStructPtr<FVoxelChunkData>> Data;
FVoxelMeshData MeshSectionBuffer; FVoxelMeshData MeshSectionBuffer;
private: private:
void Load();
void Unload();
void FlushMeshSection(int32 SectionIndex); void FlushMeshSection(int32 SectionIndex);
UFUNCTION()
void OnDataLoaded(const FString& Filename);
}; };

View File

@ -17,6 +17,9 @@ public:
UFUNCTION(BlueprintCallable, Category = "Voxel|Helper", meta = (WorldContext = "WorldContextObject")) UFUNCTION(BlueprintCallable, Category = "Voxel|Helper", meta = (WorldContext = "WorldContextObject"))
static AVoxelWorld* CreateVoxelWorld(UObject* WorldContextObject, const FVoxelWorldSetting& WorldSetting); static AVoxelWorld* CreateVoxelWorld(UObject* WorldContextObject, const FVoxelWorldSetting& WorldSetting);
UFUNCTION(BlueprintCallable, Category = "Voxel|Helper", meta = (WorldContext = "WorldContextObject"))
static bool IsWorldSettingValid(UObject* WorldContextObject, const FVoxelWorldSetting& WorldSetting);
UFUNCTION(BlueprintPure, Category = "Voxel|Helper") UFUNCTION(BlueprintPure, Category = "Voxel|Helper")
static void WorldToRelativeLocation(const FIntVector& InWorldLocation, FIntPoint& OutChunkLocation, FIntVector& OutRelativeLocation); static void WorldToRelativeLocation(const FIntVector& InWorldLocation, FIntPoint& OutChunkLocation, FIntVector& OutRelativeLocation);

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "SaveStruct.h"
#include "GameFramework/Info.h" #include "GameFramework/Info.h"
#include "VoxelWorld.generated.h" #include "VoxelWorld.generated.h"
@ -22,6 +23,12 @@ struct VOXEL_API FVoxelWorldSetting
}; };
USTRUCT()
struct FVoxelWorldData : public FSaveStruct
{
GENERATED_BODY()
};
UCLASS(BlueprintType) UCLASS(BlueprintType)
class VOXEL_API AVoxelWorld : public AInfo class VOXEL_API AVoxelWorld : public AInfo
{ {
@ -79,10 +86,14 @@ private:
UPROPERTY() UPROPERTY()
TSet<FIntPoint> MeshFlushBuffer; TSet<FIntPoint> MeshFlushBuffer;
TSharedPtr<FSaveStructPtr<FVoxelWorldData>> Data;
private: private:
void ManageChunk(); void ManageChunk();
void FlushMeshs(); void FlushMeshs();
bool TestWorldSettingValid();
}; };

View File

@ -39,6 +39,7 @@ public class Voxel : ModuleRules
"Slate", "Slate",
"SlateCore", "SlateCore",
"ProceduralMeshComponent", "ProceduralMeshComponent",
"AutoSave",
// ... add private dependencies that you statically link with here ... // ... add private dependencies that you statically link with here ...
} }
); );

View File

@ -25,6 +25,10 @@
{ {
"Name": "ProceduralMeshComponent", "Name": "ProceduralMeshComponent",
"Enabled": true "Enabled": true
},
{
"Name": "AutoSave",
"Enabled": true
} }
] ]
} }