使用 AutoSave 插件管理文件
修复 AVoxelWorld::CenterAgent 为空时 RE 修复区块不能根据距离正常卸载的问题
This commit is contained in:
parent
d1103c580b
commit
0663e3192e
@ -6,6 +6,24 @@
|
||||
#include "ProceduralMeshComponent.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)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
@ -24,14 +42,35 @@ AVoxelChunk::AVoxelChunk(const class FObjectInitializer& ObjectInitializer)
|
||||
|
||||
void AVoxelChunk::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
UGameInstance* GameInstance = GetGameInstance();
|
||||
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
|
||||
{
|
||||
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.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)
|
||||
{
|
||||
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.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);
|
||||
|
||||
@ -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)
|
||||
{
|
||||
if (!Data->IsLoaded()) return;
|
||||
|
||||
static FVoxelMeshData CubeTopFaceBuffer = FVoxelMeshData::CubeTopFace;
|
||||
static FVoxelMeshData CubeBottomFaceBuffer = FVoxelMeshData::CubeBottomFace;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
const FVoxelBlockType& TopVoxelBlock = VoxelSubsystem->GetBlockType(Z + 1 < 256 ? 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& FrontVoxelBlock = VoxelSubsystem->GetBlockType(X + 1 < 16 ? 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& LeftVoxelBlock = VoxelSubsystem->GetBlockType(Y - 1 >= 0 ? 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& TopVoxelBlock = VoxelSubsystem->GetBlockType(Z + 1 < 256 ? (*Data)->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 ? (*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 ? (*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 ? (*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 ? (*Data)->Blocks[X][Y + 1][Z].Type : (RightChunk ? RightChunk->GetBlockByRelativeLocation(FIntVector(X, 0, Z)).Type : TEXT("Air")));
|
||||
|
||||
if (TopVoxelBlock.Shape != EVoxelBlockShape::Cube)
|
||||
{
|
||||
@ -321,3 +293,8 @@ void AVoxelChunk::FlushMeshSection(int32 SectionIndex)
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
void AVoxelChunk::OnDataLoaded(const FString & Filename)
|
||||
{
|
||||
VoxelWorld->AddChunkToMeshFlushBuffer(ChunkLocation);
|
||||
}
|
||||
|
@ -1,20 +1,46 @@
|
||||
#include "VoxelHelper.h"
|
||||
|
||||
#include "VoxelWorld.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
AVoxelWorld * UVoxelHelper::CreateVoxelWorld(UObject* WorldContextObject, const FVoxelWorldSetting& WorldSetting)
|
||||
{
|
||||
if (!IsWorldSettingValid(WorldContextObject, WorldSetting)) return nullptr;
|
||||
|
||||
UWorld* World = WorldContextObject->GetWorld();
|
||||
|
||||
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;
|
||||
|
||||
UGameplayStatics::FinishSpawningActor(VoxelWorld, FTransform());
|
||||
|
||||
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)
|
||||
{
|
||||
OutChunkLocation.X = InWorldLocation.X / 16;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "Block/VoxelBlock.h"
|
||||
#include "Chunk/VoxelChunk.h"
|
||||
#include "VoxelAgentInterface.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
const TArray<FIntPoint> ChunkLoadOrder =
|
||||
{
|
||||
@ -160,6 +161,10 @@ void AVoxelWorld::BeginPlay()
|
||||
|
||||
UGameInstance* GameInstance = GetGameInstance();
|
||||
VoxelSubsystem = GameInstance->GetSubsystem<UVoxelSubsystem>();
|
||||
|
||||
Data = MakeShared<FSaveStructPtr<FVoxelWorldData>>(GetGameInstance()->GetSubsystem<UAutoSaveSubsystem>(), WorldSetting.ArchiveFolder / TEXT("VoxelWorld"));
|
||||
|
||||
check(Data->IsValid());
|
||||
}
|
||||
|
||||
void AVoxelWorld::Tick(float DeltaSeconds)
|
||||
@ -169,7 +174,6 @@ void AVoxelWorld::Tick(float DeltaSeconds)
|
||||
ManageChunk();
|
||||
|
||||
FlushMeshs();
|
||||
|
||||
}
|
||||
|
||||
void AVoxelWorld::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
@ -180,6 +184,8 @@ void AVoxelWorld::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
for (const FIntPoint& Chunk : ChunksToUnload)
|
||||
UnloadChunk(Chunk);
|
||||
|
||||
Data = nullptr;
|
||||
|
||||
Super::EndPlay(EndPlayReason);
|
||||
}
|
||||
|
||||
@ -223,14 +229,22 @@ void AVoxelWorld::LoadChunk(const FIntPoint & ChunkLocation)
|
||||
|
||||
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->ChunkLocation = ChunkLocation;
|
||||
NewVoxelChunk->SetActorLocation(FVector(ChunkLocation.X * 1600.0f, ChunkLocation.Y * 1600.0f, 0.0f));
|
||||
NewVoxelChunk->AttachToActor(this, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
NewVoxelChunk->FlushMaterials();
|
||||
NewVoxelChunk->Load();
|
||||
AddChunkToMeshFlushBuffer(ChunkLocation);
|
||||
|
||||
UGameplayStatics::FinishSpawningActor(NewVoxelChunk, ChunkTransform);
|
||||
|
||||
Chunks.Add(ChunkLocation, NewVoxelChunk);
|
||||
|
||||
@ -241,7 +255,6 @@ void AVoxelWorld::UnloadChunk(const FIntPoint & ChunkLocation)
|
||||
{
|
||||
if (!Chunks.Contains(ChunkLocation)) return;
|
||||
|
||||
Chunks[ChunkLocation]->Unload();
|
||||
Chunks[ChunkLocation]->Destroy();
|
||||
|
||||
Chunks.Remove(ChunkLocation);
|
||||
@ -259,9 +272,16 @@ void AVoxelWorld::FlushMaterials()
|
||||
|
||||
void AVoxelWorld::ManageChunk()
|
||||
{
|
||||
FIntPoint RootChunk;
|
||||
if (GetGameInstance()->GetSubsystem<UAutoSaveSubsystem>()->GetIdleThreadNum() <= 0) return;
|
||||
|
||||
FIntPoint RootChunk = FIntPoint(0, 0);
|
||||
|
||||
if (CenterAgent.GetObject())
|
||||
{
|
||||
FIntVector RLocation;
|
||||
UVoxelHelper::WorldToRelativeLocation(IVoxelAgentInterface::Execute_GetAgentLocation(CenterAgent.GetObject()), RootChunk, RLocation);
|
||||
}
|
||||
|
||||
|
||||
// Load
|
||||
for (const FIntPoint& Chunk : ChunkLoadOrder)
|
||||
@ -286,7 +306,7 @@ void AVoxelWorld::ManageChunk()
|
||||
const FIntPoint WorldLocation = Chunk.Key;
|
||||
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)
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "SaveStruct.h"
|
||||
#include "Block/VoxelBlock.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "VoxelChunk.generated.h"
|
||||
@ -9,7 +10,24 @@ class AVoxelWorld;
|
||||
class UVoxelSubsystem;
|
||||
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)
|
||||
class VOXEL_API AVoxelChunk : public AActor
|
||||
@ -24,6 +42,8 @@ public:
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Voxel|Chunk")
|
||||
AVoxelWorld* GetVoxelWorld() const { return VoxelWorld; }
|
||||
|
||||
@ -59,16 +79,15 @@ private:
|
||||
|
||||
uint16 FlushMeshFlags;
|
||||
|
||||
FVoxelBlock Blocks[16][16][256];
|
||||
TSharedPtr<FSaveStructPtr<FVoxelChunkData>> Data;
|
||||
|
||||
FVoxelMeshData MeshSectionBuffer;
|
||||
|
||||
private:
|
||||
|
||||
void Load();
|
||||
|
||||
void Unload();
|
||||
|
||||
void FlushMeshSection(int32 SectionIndex);
|
||||
|
||||
UFUNCTION()
|
||||
void OnDataLoaded(const FString& Filename);
|
||||
|
||||
};
|
||||
|
@ -17,6 +17,9 @@ public:
|
||||
UFUNCTION(BlueprintCallable, Category = "Voxel|Helper", meta = (WorldContext = "WorldContextObject"))
|
||||
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")
|
||||
static void WorldToRelativeLocation(const FIntVector& InWorldLocation, FIntPoint& OutChunkLocation, FIntVector& OutRelativeLocation);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "SaveStruct.h"
|
||||
#include "GameFramework/Info.h"
|
||||
#include "VoxelWorld.generated.h"
|
||||
|
||||
@ -22,6 +23,12 @@ struct VOXEL_API FVoxelWorldSetting
|
||||
|
||||
};
|
||||
|
||||
USTRUCT()
|
||||
struct FVoxelWorldData : public FSaveStruct
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class VOXEL_API AVoxelWorld : public AInfo
|
||||
{
|
||||
@ -79,10 +86,14 @@ private:
|
||||
UPROPERTY()
|
||||
TSet<FIntPoint> MeshFlushBuffer;
|
||||
|
||||
TSharedPtr<FSaveStructPtr<FVoxelWorldData>> Data;
|
||||
|
||||
private:
|
||||
|
||||
void ManageChunk();
|
||||
|
||||
void FlushMeshs();
|
||||
|
||||
bool TestWorldSettingValid();
|
||||
|
||||
};
|
||||
|
@ -39,6 +39,7 @@ public class Voxel : ModuleRules
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
"ProceduralMeshComponent",
|
||||
"AutoSave",
|
||||
// ... add private dependencies that you statically link with here ...
|
||||
}
|
||||
);
|
||||
|
@ -25,6 +25,10 @@
|
||||
{
|
||||
"Name": "ProceduralMeshComponent",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "AutoSave",
|
||||
"Enabled": true
|
||||
}
|
||||
]
|
||||
}
|
Reference in New Issue
Block a user