使用 AutoSave 插件管理文件
修复 AVoxelWorld::CenterAgent 为空时 RE 修复区块不能根据距离正常卸载的问题
This commit is contained in:
parent
d1103c580b
commit
0663e3192e
@ -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);
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -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 ...
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -25,6 +25,10 @@
|
|||||||
{
|
{
|
||||||
"Name": "ProceduralMeshComponent",
|
"Name": "ProceduralMeshComponent",
|
||||||
"Enabled": true
|
"Enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "AutoSave",
|
||||||
|
"Enabled": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
Reference in New Issue
Block a user