From 47148e0a0de05daf0580cf3d4ab45cc9660e872e Mon Sep 17 00:00:00 2001 From: Fr0zka Date: Mon, 26 Oct 2026 19:19:07 +0100 Subject: [PATCH] build: VoxelForge compiles in Unreal 5.7 on Linux (L65); Linux-only Unreal trace timing fields Linux UE builds failed on the Core wrapper module: the Linux-only PerModuleInline.gen.cpp saw Standalone/Compat shadow headers instead of the engine's, and WITH_EDITOR was redefined under -Werror. Compat headers now forward to the engine headers with include_next for generated Linux module TUs (canonical Core TUs opt into the Compat definitions via CoreNamespacePreamble.h); CoreMinimal.h undefines WITH_EDITOR first. VoxelForgeCore.Build.cs enables that forwarding and AVX2 on Linux only; VoxelForge.Build.cs disables Unity on Linux only. Portability: std::int64_t consistently in VoxelContentManager.cpp; grouped &&/|| in VoxelRedefinedDensityField.cpp. Linux-only trace fields split Core generateTile / mesh copy / RMC stream build. Standalone Clang and GCC whole-view hashes are unchanged vs 3202193. The Unreal spawn trace is blocked by the owner's new assets (SW route sweep fails). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1 --- .../Private/VoxelContentManager.cpp | 8 +- .../Private/VoxelRedefinedDensityField.cpp | 4 +- .../VoxelForge/Private/VoxelStartupTrace.cpp | 14 ++- Source/VoxelForge/Private/VoxelWorld.cpp | 29 ++++++ Source/VoxelForge/Public/VoxelStartupTrace.h | 3 + Source/VoxelForge/Public/VoxelWorld.h | 4 + Source/VoxelForge/VoxelForge.Build.cs | 7 ++ Source/VoxelForgeCore/VoxelForgeCore.Build.cs | 7 ++ Standalone/Compat/AssetRegistry/AssetData.h | 7 +- .../AssetRegistry/AssetRegistryModule.h | 7 +- Standalone/Compat/Async/ParallelFor.h | 7 +- Standalone/Compat/CoreMinimal.h | 9 ++ Standalone/Compat/Dom/JsonObject.h | 7 +- Standalone/Compat/Dom/JsonValue.h | 7 +- Standalone/Compat/Engine/DataAsset.h | 7 +- Standalone/Compat/GameplayTagContainer.h | 7 +- Standalone/Compat/HAL/CriticalSection.h | 7 +- Standalone/Compat/HAL/Event.h | 7 +- Standalone/Compat/HAL/FileManager.h | 7 +- Standalone/Compat/HAL/IConsoleManager.h | 7 +- Standalone/Compat/HAL/PlatformProcess.h | 7 +- Standalone/Compat/HAL/PlatformTime.h | 7 +- Standalone/Compat/Json.h | 6 ++ Standalone/Compat/Math/RandomStream.h | 7 +- Standalone/Compat/Misc/CommandLine.h | 7 +- Standalone/Compat/Misc/Crc.h | 7 +- Standalone/Compat/Misc/FileHelper.h | 7 +- Standalone/Compat/Misc/Parse.h | 7 +- Standalone/Compat/Misc/Paths.h | 7 +- Standalone/Compat/Misc/ScopeLock.h | 7 +- Standalone/Compat/Misc/ScopeRWLock.h | 7 +- Standalone/Compat/Misc/SecureHash.h | 7 +- Standalone/Compat/Modules/ModuleManager.h | 7 +- .../ProfilingDebugging/CpuProfilerTrace.h | 7 +- .../Compat/Serialization/CustomVersion.h | 7 +- .../Compat/Serialization/JsonSerializer.h | 7 +- Standalone/Compat/Serialization/JsonWriter.h | 7 +- Standalone/Compat/Stats/Stats.h | 6 ++ Standalone/Compat/Templates/SubclassOf.h | 7 +- Standalone/Compat/Templates/UniquePtr.h | 7 +- Standalone/Compat/UObject/EnumProperty.h | 7 +- Standalone/Compat/UObject/FieldIterator.h | 7 +- Standalone/Compat/UObject/Object.h | 7 +- Standalone/Compat/UObject/UObjectGlobals.h | 7 +- Standalone/Compat/UObject/UnrealType.h | 7 +- Standalone/Core/src/CoreNamespacePreamble.h | 4 + .../WorldAssemblerM3/Linux65/REPORT.md | 93 +++++++++++++++++++ 47 files changed, 389 insertions(+), 43 deletions(-) create mode 100644 Standalone/Research/WorldAssemblerM3/Linux65/REPORT.md diff --git a/Source/VoxelForge/Private/VoxelContentManager.cpp b/Source/VoxelForge/Private/VoxelContentManager.cpp index 65d0b9c..6da827f 100644 --- a/Source/VoxelForge/Private/VoxelContentManager.cpp +++ b/Source/VoxelForge/Private/VoxelContentManager.cpp @@ -241,10 +241,10 @@ static std::vector VF_ContentFeatur { using namespace VoxelForgeCore; constexpr double Q = WorldAssemblySubvoxelsPerVoxel; - const std::array Min{static_cast(std::floor(MinX*Q)), - static_cast(std::floor(MinY*Q)),static_cast(std::floor(MinZ*Q))}; - const std::array Max{static_cast(std::ceil(MaxX*Q)), - static_cast(std::ceil(MaxY*Q)),static_cast(std::ceil(MaxZ*Q))}; + const std::array Min{static_cast(std::floor(MinX*Q)), + static_cast(std::floor(MinY*Q)),static_cast(std::floor(MinZ*Q))}; + const std::array Max{static_cast(std::ceil(MaxX*Q)), + static_cast(std::ceil(MaxY*Q)),static_cast(std::ceil(MaxZ*Q))}; std::vector Queries; if (Surface) if (const auto* Plan = Surface->FindPlan(StrateIndex)) diff --git a/Source/VoxelForge/Private/VoxelRedefinedDensityField.cpp b/Source/VoxelForge/Private/VoxelRedefinedDensityField.cpp index 8fa58fa..05f5c9b 100644 --- a/Source/VoxelForge/Private/VoxelRedefinedDensityField.cpp +++ b/Source/VoxelForge/Private/VoxelRedefinedDensityField.cpp @@ -2590,8 +2590,8 @@ static float EvaluateInternal(const UVoxelGenerator& Generator, { EnsurePlan(Generator); } - const bool bChunkResolved = Context != nullptr && Context->bChunkResolved - || ParameterizedContext != nullptr && ParameterizedContext->bChunkResolved; + const bool bChunkResolved = (Context != nullptr && Context->bChunkResolved) + || (ParameterizedContext != nullptr && ParameterizedContext->bChunkResolved); const FIntVector Chunk = Context != nullptr && Context->bChunkResolved ? Context->Chunk : ParameterizedContext != nullptr && ParameterizedContext->bChunkResolved diff --git a/Source/VoxelForge/Private/VoxelStartupTrace.cpp b/Source/VoxelForge/Private/VoxelStartupTrace.cpp index bbc4e07..8f52456 100644 --- a/Source/VoxelForge/Private/VoxelStartupTrace.cpp +++ b/Source/VoxelForge/Private/VoxelStartupTrace.cpp @@ -297,7 +297,11 @@ void RecordTile(const FTileSample& Sample) "\"submitted_t_s\":%s,\"worker_start_t_s\":%s,\"worker_end_t_s\":%s,\"worker_thread_id\":%u," "\"verdict\":%d,\"proof\":%d,\"empty\":%d,\"vertices\":%d,\"triangles\":%d,\"geometry_bytes\":%llu," "\"request_to_apply_s\":%s,\"queue_wait_s\":%s,\"worker_queue_s\":%s,\"result_queue_s\":%s,\"worker_task_s\":%s," - "\"generation_s\":%s,\"classify_s\":%s,\"mesh_s\":%s,\"stream_s\":%s,\"apply_s\":%s"), + "\"generation_s\":%s," +#if PLATFORM_LINUX + "\"core_generate_s\":%s,\"mesh_copy_s\":%s,\"rmc_stream_build_s\":%s," +#endif + "\"classify_s\":%s,\"mesh_s\":%s,\"stream_s\":%s,\"apply_s\":%s"), Sample.TileX, Sample.TileY, Sample.TileZ, Sample.Level, Sample.WorkPriority, static_cast(Sample.RequestOrdinal), @@ -312,8 +316,12 @@ void RecordTile(const FTileSample& Sample) static_cast(Sample.GeometryBytes), *Number(Sample.RequestToApplySeconds), *Number(Sample.QueueWaitSeconds), *Number(Sample.WorkerQueueSeconds), *Number(Sample.ResultQueueSeconds), - *Number(Sample.WorkerTaskSeconds), - *Number(Sample.GenerationSeconds), *Number(Sample.ClassifySeconds), + *Number(Sample.WorkerTaskSeconds), *Number(Sample.GenerationSeconds), +#if PLATFORM_LINUX + *Number(Sample.CoreGenerateSeconds), *Number(Sample.MeshCopySeconds), + *Number(Sample.StreamBuildSeconds), +#endif + *Number(Sample.ClassifySeconds), *Number(Sample.MeshSeconds), *Number(Sample.StreamSeconds), *Number(Sample.ApplySeconds))); } diff --git a/Source/VoxelForge/Private/VoxelWorld.cpp b/Source/VoxelForge/Private/VoxelWorld.cpp index a39a2a7..2313ad8 100644 --- a/Source/VoxelForge/Private/VoxelWorld.cpp +++ b/Source/VoxelForge/Private/VoxelWorld.cpp @@ -9960,6 +9960,9 @@ bool AVoxelWorld::ApplyTileResult(FChunkResult& Result) Sample.QueueWaitSeconds = WorkerQueueSeconds + ResultQueueSeconds; Sample.WorkerTaskSeconds = WorkerTaskSeconds; Sample.GenerationSeconds = GenerationSeconds; + Sample.CoreGenerateSeconds = Result.CoreGenerateSeconds; + Sample.MeshCopySeconds = Result.MeshCopySeconds; + Sample.StreamBuildSeconds = Result.StreamBuildSeconds; Sample.ClassifySeconds = Result.ClassifySeconds; Sample.MeshSeconds = Result.MeshSeconds; Sample.StreamSeconds = Result.StreamSeconds; @@ -13235,6 +13238,11 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Result.WorkPriority = WorkPriority; Result.GenerationStartCycles = FPlatformTime::Cycles64(); Result.GenerationOrdinal = NextStreamingGenerationOrdinal.fetch_add(1, std::memory_order_relaxed) + 1; +#if PLATFORM_LINUX + const bool bMeasureWorkerPhases = VoxelForgeStartupTrace::IsActive(); +#else + constexpr bool bMeasureWorkerPhases = false; +#endif auto EnqueueObsolete = [&]() { @@ -13290,7 +13298,14 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority FReadScopeLock Lock(State->WorldLock); if (State->World) { + const uint64 CoreGenerateStartCycles = bMeasureWorkerPhases + ? FPlatformTime::Cycles64() : 0; CoreMesh = State->World->generateTile(CoreKey, Options, CoreError); + if (CoreGenerateStartCycles != 0) + { + Result.CoreGenerateSeconds = FPlatformTime::ToSeconds64( + FPlatformTime::Cycles64() - CoreGenerateStartCycles); + } } } Result.GenerationEndCycles = FPlatformTime::Cycles64(); @@ -13332,6 +13347,8 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority if (!Result.bEmpty) { + const uint64 MeshCopyStartCycles = bMeasureWorkerPhases + ? FPlatformTime::Cycles64() : 0; FVoxelMeshData MeshData; MeshData.Vertices.Reserve(Result.NumVertices); MeshData.Normals.Reserve(Result.NumVertices); @@ -13352,8 +13369,20 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority MeshData.NumSurfaceVertices = static_cast(CoreMesh->groups.surfaceVertexCount); MeshData.NumCeilingTriangles = Result.NumCeilingTriangles; MeshData.NumSkirtTriangles = Result.NumSkirtTriangles; + if (MeshCopyStartCycles != 0) + { + Result.MeshCopySeconds = FPlatformTime::ToSeconds64( + FPlatformTime::Cycles64() - MeshCopyStartCycles); + } + const uint64 StreamBuildStartCycles = bMeasureWorkerPhases + ? FPlatformTime::Cycles64() : 0; Result.Streams = MakeShared(); BuildTileStreamSet(*Result.Streams, MeshData); + if (StreamBuildStartCycles != 0) + { + Result.StreamBuildSeconds = FPlatformTime::ToSeconds64( + FPlatformTime::Cycles64() - StreamBuildStartCycles); + } } Result.GenerationEndCycles = FPlatformTime::Cycles64(); if (Cancellation->bObsolete.load(std::memory_order_acquire) diff --git a/Source/VoxelForge/Public/VoxelStartupTrace.h b/Source/VoxelForge/Public/VoxelStartupTrace.h index 191a834..a187f94 100644 --- a/Source/VoxelForge/Public/VoxelStartupTrace.h +++ b/Source/VoxelForge/Public/VoxelStartupTrace.h @@ -35,6 +35,9 @@ namespace VoxelForgeStartupTrace double ResultQueueSeconds = 0.0; double WorkerTaskSeconds = 0.0; double GenerationSeconds = 0.0; + double CoreGenerateSeconds = 0.0; + double MeshCopySeconds = 0.0; + double StreamBuildSeconds = 0.0; double ClassifySeconds = 0.0; double MeshSeconds = 0.0; double StreamSeconds = 0.0; diff --git a/Source/VoxelForge/Public/VoxelWorld.h b/Source/VoxelForge/Public/VoxelWorld.h index 9e04f3a..e41234a 100644 --- a/Source/VoxelForge/Public/VoxelWorld.h +++ b/Source/VoxelForge/Public/VoxelWorld.h @@ -145,6 +145,10 @@ struct FChunkResult // per-tile profiling remains opt-in. uint64 GenerationStartCycles = 0; uint64 GenerationEndCycles = 0; + // Optional phase timings recorded only while the bounded startup trace is active. + double CoreGenerateSeconds = 0.0; + double MeshCopySeconds = 0.0; + double StreamBuildSeconds = 0.0; uint64 ApplyStartCycles = 0; EVoxelTileWorkPriority WorkPriority = EVoxelTileWorkPriority::Horizon; // Ordinals make admitted order and actual worker start order auditable across MPSC results. diff --git a/Source/VoxelForge/VoxelForge.Build.cs b/Source/VoxelForge/VoxelForge.Build.cs index 5289152..a4d903e 100644 --- a/Source/VoxelForge/VoxelForge.Build.cs +++ b/Source/VoxelForge/VoxelForge.Build.cs @@ -7,6 +7,13 @@ public class VoxelForge : ModuleRules { public VoxelForge(ReadOnlyTargetRules Target) : base(Target) { + if (Target.Platform == UnrealTargetPlatform.Linux) + { + // Test translation units have independent anonymous-namespace helpers that collide in + // Linux Unity batches. Keep Linux compilation one source per TU; Windows remains unchanged. + bUseUnity = false; + } + // PCH = Precompiled Headers - speeds up compilation // UseExplicitOrSharedPCHs is the modern recommended setting PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; diff --git a/Source/VoxelForgeCore/VoxelForgeCore.Build.cs b/Source/VoxelForgeCore/VoxelForgeCore.Build.cs index 92128d7..349ad94 100644 --- a/Source/VoxelForgeCore/VoxelForgeCore.Build.cs +++ b/Source/VoxelForgeCore/VoxelForgeCore.Build.cs @@ -39,6 +39,13 @@ public class VoxelForgeCore : ModuleRules PublicDependencyModuleNames.Add("Core"); CppStandard = CppStandardVersion.Cpp20; + if (Target.Platform == UnrealTargetPlatform.Linux) + { + // The compatibility include directory contains Unreal-shaped placeholders. On Linux, + // let generated module TUs pass those names through to UE while Core shims opt in. + PrivateDefinitions.Add("VFCORE_COMPAT_FORWARD_HEADERS=1"); + MinCpuArchX64 = MinimumCpuArchitectureX64.AVX2; + } // Canonical Standalone code predates UE's stricter warning defaults; keep this narrow to legal local shadowing. CppCompileWarningSettings.ShadowVariableWarningLevel = WarningLevel.Off; FPSemantics = FPSemanticsMode.Precise; diff --git a/Standalone/Compat/AssetRegistry/AssetData.h b/Standalone/Compat/AssetRegistry/AssetData.h index 7b9637e..83268e3 100644 --- a/Standalone/Compat/AssetRegistry/AssetData.h +++ b/Standalone/Compat/AssetRegistry/AssetData.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/AssetRegistry/AssetRegistryModule.h b/Standalone/Compat/AssetRegistry/AssetRegistryModule.h index 7b9637e..40f67a7 100644 --- a/Standalone/Compat/AssetRegistry/AssetRegistryModule.h +++ b/Standalone/Compat/AssetRegistry/AssetRegistryModule.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Async/ParallelFor.h b/Standalone/Compat/Async/ParallelFor.h index 7b9637e..86410f0 100644 --- a/Standalone/Compat/Async/ParallelFor.h +++ b/Standalone/Compat/Async/ParallelFor.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/CoreMinimal.h b/Standalone/Compat/CoreMinimal.h index dfeace2..b1c85fc 100644 --- a/Standalone/Compat/CoreMinimal.h +++ b/Standalone/Compat/CoreMinimal.h @@ -1,5 +1,10 @@ #pragma once +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#else + // Deliberately small UE-style surface used by the copied VoxelForge CPU sources. // This is a value/container compatibility layer; it does not start or link Unreal. #include @@ -45,6 +50,9 @@ #define GENERATED_UCLASS_BODY() #define VOXELFORGE_API #define FORCEINLINE inline +#ifdef WITH_EDITOR +#undef WITH_EDITOR +#endif #define WITH_EDITOR 0 #define TRACE_CPUPROFILER_EVENT_SCOPE(...) #define PRAGMA_DISABLE_SHADOW_VARIABLE_WARNINGS @@ -705,3 +713,4 @@ struct FParse struct FCrc { static uint32 MemCrc32(const void*Data,int32 Length,uint32 Crc=0){const auto*P=static_cast(Data);uint32 V=~Crc;for(int32 I=0;I>1)^(0xEDB88320u&static_cast(-static_cast(V&1)));}return ~V;} static uint32 StrCrc32(const char*S,uint32 Crc=0){return MemCrc32(S,static_cast(std::strlen(S)),Crc);} }; template using TAtomic = std::atomic; class FThreadSafeCounter { public:int32 Increment(){return ++Value;}int32 Decrement(){return --Value;}int32 GetValue()const{return Value.load();}void Reset(){Value.store(0);}private:std::atomicValue{0};}; +#endif diff --git a/Standalone/Compat/Dom/JsonObject.h b/Standalone/Compat/Dom/JsonObject.h index 7b9637e..82f4a39 100644 --- a/Standalone/Compat/Dom/JsonObject.h +++ b/Standalone/Compat/Dom/JsonObject.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Dom/JsonValue.h b/Standalone/Compat/Dom/JsonValue.h index 7b9637e..3b19201 100644 --- a/Standalone/Compat/Dom/JsonValue.h +++ b/Standalone/Compat/Dom/JsonValue.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Engine/DataAsset.h b/Standalone/Compat/Engine/DataAsset.h index 7b9637e..ab798e2 100644 --- a/Standalone/Compat/Engine/DataAsset.h +++ b/Standalone/Compat/Engine/DataAsset.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/GameplayTagContainer.h b/Standalone/Compat/GameplayTagContainer.h index 7b9637e..518865c 100644 --- a/Standalone/Compat/GameplayTagContainer.h +++ b/Standalone/Compat/GameplayTagContainer.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/HAL/CriticalSection.h b/Standalone/Compat/HAL/CriticalSection.h index 7b9637e..453dd30 100644 --- a/Standalone/Compat/HAL/CriticalSection.h +++ b/Standalone/Compat/HAL/CriticalSection.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/HAL/Event.h b/Standalone/Compat/HAL/Event.h index 7b9637e..5b820ed 100644 --- a/Standalone/Compat/HAL/Event.h +++ b/Standalone/Compat/HAL/Event.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/HAL/FileManager.h b/Standalone/Compat/HAL/FileManager.h index 7b9637e..4cbcf67 100644 --- a/Standalone/Compat/HAL/FileManager.h +++ b/Standalone/Compat/HAL/FileManager.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/HAL/IConsoleManager.h b/Standalone/Compat/HAL/IConsoleManager.h index 7b9637e..c67098d 100644 --- a/Standalone/Compat/HAL/IConsoleManager.h +++ b/Standalone/Compat/HAL/IConsoleManager.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/HAL/PlatformProcess.h b/Standalone/Compat/HAL/PlatformProcess.h index 7b9637e..62629e9 100644 --- a/Standalone/Compat/HAL/PlatformProcess.h +++ b/Standalone/Compat/HAL/PlatformProcess.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/HAL/PlatformTime.h b/Standalone/Compat/HAL/PlatformTime.h index 7b9637e..bfb3689 100644 --- a/Standalone/Compat/HAL/PlatformTime.h +++ b/Standalone/Compat/HAL/PlatformTime.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Json.h b/Standalone/Compat/Json.h index 46ceee1..6516a98 100644 --- a/Standalone/Compat/Json.h +++ b/Standalone/Compat/Json.h @@ -1,5 +1,10 @@ #pragma once +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#else + #include #include #include @@ -162,3 +167,4 @@ namespace VFJson return Parser(std::move(Text)).Parse(Out, Error); } } +#endif diff --git a/Standalone/Compat/Math/RandomStream.h b/Standalone/Compat/Math/RandomStream.h index 7b9637e..dad04d9 100644 --- a/Standalone/Compat/Math/RandomStream.h +++ b/Standalone/Compat/Math/RandomStream.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Misc/CommandLine.h b/Standalone/Compat/Misc/CommandLine.h index 7b9637e..8206bbe 100644 --- a/Standalone/Compat/Misc/CommandLine.h +++ b/Standalone/Compat/Misc/CommandLine.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Misc/Crc.h b/Standalone/Compat/Misc/Crc.h index 7b9637e..c92619c 100644 --- a/Standalone/Compat/Misc/Crc.h +++ b/Standalone/Compat/Misc/Crc.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Misc/FileHelper.h b/Standalone/Compat/Misc/FileHelper.h index 7b9637e..12945be 100644 --- a/Standalone/Compat/Misc/FileHelper.h +++ b/Standalone/Compat/Misc/FileHelper.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Misc/Parse.h b/Standalone/Compat/Misc/Parse.h index 7b9637e..5aed288 100644 --- a/Standalone/Compat/Misc/Parse.h +++ b/Standalone/Compat/Misc/Parse.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Misc/Paths.h b/Standalone/Compat/Misc/Paths.h index 7b9637e..5a3de39 100644 --- a/Standalone/Compat/Misc/Paths.h +++ b/Standalone/Compat/Misc/Paths.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Misc/ScopeLock.h b/Standalone/Compat/Misc/ScopeLock.h index 7b9637e..32a0220 100644 --- a/Standalone/Compat/Misc/ScopeLock.h +++ b/Standalone/Compat/Misc/ScopeLock.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Misc/ScopeRWLock.h b/Standalone/Compat/Misc/ScopeRWLock.h index 7b9637e..882d545 100644 --- a/Standalone/Compat/Misc/ScopeRWLock.h +++ b/Standalone/Compat/Misc/ScopeRWLock.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Misc/SecureHash.h b/Standalone/Compat/Misc/SecureHash.h index 7b9637e..a5b4b60 100644 --- a/Standalone/Compat/Misc/SecureHash.h +++ b/Standalone/Compat/Misc/SecureHash.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Modules/ModuleManager.h b/Standalone/Compat/Modules/ModuleManager.h index 7b9637e..e22ec4f 100644 --- a/Standalone/Compat/Modules/ModuleManager.h +++ b/Standalone/Compat/Modules/ModuleManager.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/ProfilingDebugging/CpuProfilerTrace.h b/Standalone/Compat/ProfilingDebugging/CpuProfilerTrace.h index 7b9637e..3c247dc 100644 --- a/Standalone/Compat/ProfilingDebugging/CpuProfilerTrace.h +++ b/Standalone/Compat/ProfilingDebugging/CpuProfilerTrace.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Serialization/CustomVersion.h b/Standalone/Compat/Serialization/CustomVersion.h index 7b9637e..0353ec8 100644 --- a/Standalone/Compat/Serialization/CustomVersion.h +++ b/Standalone/Compat/Serialization/CustomVersion.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Serialization/JsonSerializer.h b/Standalone/Compat/Serialization/JsonSerializer.h index 7b9637e..bb231f1 100644 --- a/Standalone/Compat/Serialization/JsonSerializer.h +++ b/Standalone/Compat/Serialization/JsonSerializer.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Serialization/JsonWriter.h b/Standalone/Compat/Serialization/JsonWriter.h index 7b9637e..a7794e4 100644 --- a/Standalone/Compat/Serialization/JsonWriter.h +++ b/Standalone/Compat/Serialization/JsonWriter.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Stats/Stats.h b/Standalone/Compat/Stats/Stats.h index 1cd9ff4..3fc7909 100644 --- a/Standalone/Compat/Stats/Stats.h +++ b/Standalone/Compat/Stats/Stats.h @@ -1,4 +1,9 @@ #pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#else #define STATCAT_Advanced 0 #define DECLARE_STATS_GROUP(Name,Group,Category) constexpr int32 Group=0 #define DECLARE_DWORD_COUNTER_STAT_EXTERN(Name,Stat,Group,Api) constexpr int32 Stat=0 @@ -8,3 +13,4 @@ #define SET_DWORD_STAT(Stat,Value) ((void)0) #define SCOPE_CYCLE_COUNTER(Stat) ((void)0) #define QUICK_SCOPE_CYCLE_COUNTER(Stat) ((void)0) +#endif diff --git a/Standalone/Compat/Templates/SubclassOf.h b/Standalone/Compat/Templates/SubclassOf.h index 7b9637e..35b9226 100644 --- a/Standalone/Compat/Templates/SubclassOf.h +++ b/Standalone/Compat/Templates/SubclassOf.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/Templates/UniquePtr.h b/Standalone/Compat/Templates/UniquePtr.h index 7b9637e..dda77bd 100644 --- a/Standalone/Compat/Templates/UniquePtr.h +++ b/Standalone/Compat/Templates/UniquePtr.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/UObject/EnumProperty.h b/Standalone/Compat/UObject/EnumProperty.h index 7b9637e..67ce80f 100644 --- a/Standalone/Compat/UObject/EnumProperty.h +++ b/Standalone/Compat/UObject/EnumProperty.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/UObject/FieldIterator.h b/Standalone/Compat/UObject/FieldIterator.h index 7b9637e..ff0a40d 100644 --- a/Standalone/Compat/UObject/FieldIterator.h +++ b/Standalone/Compat/UObject/FieldIterator.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/UObject/Object.h b/Standalone/Compat/UObject/Object.h index 7b9637e..a627196 100644 --- a/Standalone/Compat/UObject/Object.h +++ b/Standalone/Compat/UObject/Object.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/UObject/UObjectGlobals.h b/Standalone/Compat/UObject/UObjectGlobals.h index 7b9637e..60772af 100644 --- a/Standalone/Compat/UObject/UObjectGlobals.h +++ b/Standalone/Compat/UObject/UObjectGlobals.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Compat/UObject/UnrealType.h b/Standalone/Compat/UObject/UnrealType.h index 7b9637e..4a76817 100644 --- a/Standalone/Compat/UObject/UnrealType.h +++ b/Standalone/Compat/UObject/UnrealType.h @@ -1 +1,6 @@ -#pragma once \ No newline at end of file +#pragma once + +#if defined(VFCORE_COMPAT_FORWARD_HEADERS) && !defined(VFCORE_USE_COMPAT) \ + && (defined(__clang__) || defined(__GNUC__)) +#include_next +#endif diff --git a/Standalone/Core/src/CoreNamespacePreamble.h b/Standalone/Core/src/CoreNamespacePreamble.h index 405e9d1..5362f75 100644 --- a/Standalone/Core/src/CoreNamespacePreamble.h +++ b/Standalone/Core/src/CoreNamespacePreamble.h @@ -1,5 +1,9 @@ #pragma once +// Core implementation TUs opt into the standalone Unreal-shaped compatibility headers. UE's +// Linux-generated module TUs leave this unset so those same header names forward to the engine. +#define VFCORE_USE_COMPAT 1 + // Every standard or platform header used by the copied implementation must be included before // its wrapper opens vfcore::detail. This prevents system declarations from being nested in the // private namespace when the implementation includes its Unreal-shaped compatibility headers. diff --git a/Standalone/Research/WorldAssemblerM3/Linux65/REPORT.md b/Standalone/Research/WorldAssemblerM3/Linux65/REPORT.md new file mode 100644 index 0000000..365f93a --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux65/REPORT.md @@ -0,0 +1,93 @@ +# Linux65 report + +Date: 2026-10-26. No commit, push, or stash was made. The pre-existing untracked `Linux18/exports/` was left alone. + +## Linux Unreal build + +UE 5.7.4 / bundled Clang 20 builds pass with zero errors. The clean HEAD build completed 78 actions in 93.54 s; L14 (`a176d07`) completed 157 actions in 170.69 s. Final incremental builds after the Linux-only trace timing guards also pass. Logs are `Saved/Linux/l65/head-build5.log`, `l14-build1.log`, `head-build-final.log`, and `l14-build-final.log`. + +Builds used CPUs 0–11, a 6 GiB RSS limit, at most 8 actions, AVX2, and `-NoUBA`. UBA stalled before starting compiler actions. Three existing RMC deprecation warnings remain: two `RemoveSectionGroup` calls and one `CreateSectionGroup` call in `VoxelWorld.cpp`. + +Fixes: + +- The Compat wrappers now forward to UE headers with `include_next` for generated Linux module TUs. `CoreNamespacePreamble.h` opts canonical Core TUs into the Compat definitions. `CoreMinimal.h` undefines `WITH_EDITOR` before defining the standalone value. +- `VoxelForgeCore.Build.cs` enables that forwarding and AVX2 only on Linux. `VoxelForge.Build.cs` disables Unity only on Linux to avoid duplicate anonymous test helpers. +- `VoxelContentManager.cpp` uses `std::int64_t` consistently; `VoxelRedefinedDensityField.cpp` groups the mixed `&&`/`||` expression. +- Linux-only trace fields measure Core `generateTile`, mesh copy, and RMC stream-set construction. The `PLATFORM_LINUX` guards keep Windows worker behavior and trace JSON unchanged. + +### Files changed for the owner's Windows build review + +All `Source/` changes: + +- `Source/VoxelForge/Private/VoxelContentManager.cpp` +- `Source/VoxelForge/Private/VoxelRedefinedDensityField.cpp` +- `Source/VoxelForge/Private/VoxelStartupTrace.cpp` +- `Source/VoxelForge/Private/VoxelWorld.cpp` +- `Source/VoxelForge/Public/VoxelStartupTrace.h` +- `Source/VoxelForge/Public/VoxelWorld.h` +- `Source/VoxelForge/VoxelForge.Build.cs` +- `Source/VoxelForgeCore/VoxelForgeCore.Build.cs` + +All changed `Standalone/Compat` headers: + +- `AssetRegistry/AssetData.h`, `AssetRegistry/AssetRegistryModule.h` +- `Async/ParallelFor.h`, `CoreMinimal.h` +- `Dom/JsonObject.h`, `Dom/JsonValue.h`, `Engine/DataAsset.h`, `GameplayTagContainer.h` +- `HAL/CriticalSection.h`, `HAL/Event.h`, `HAL/FileManager.h`, `HAL/IConsoleManager.h`, `HAL/PlatformProcess.h`, `HAL/PlatformTime.h` +- `Json.h`, `Math/RandomStream.h` +- `Misc/CommandLine.h`, `Misc/Crc.h`, `Misc/FileHelper.h`, `Misc/Parse.h`, `Misc/Paths.h`, `Misc/ScopeLock.h`, `Misc/ScopeRWLock.h`, `Misc/SecureHash.h` +- `Modules/ModuleManager.h`, `ProfilingDebugging/CpuProfilerTrace.h` +- `Serialization/CustomVersion.h`, `Serialization/JsonSerializer.h`, `Serialization/JsonWriter.h`, `Stats/Stats.h` +- `Templates/SubclassOf.h`, `Templates/UniquePtr.h` +- `UObject/EnumProperty.h`, `UObject/FieldIterator.h`, `UObject/Object.h`, `UObject/UObjectGlobals.h`, `UObject/UnrealType.h` + +Also changed: `Standalone/Core/src/CoreNamespacePreamble.h`. + +## Unreal spawn trace + +The U1 trace is `Tools/TestVoxelForgeCoreWorldHost.ps1 -TimeoutSeconds 900 -CoreVoxelSizeCm 25 -StreamingTraceOnly`. It runs `UnrealEditor-Cmd -run=VoxelForgeExplore` with `-coreworldtest=1`, `-coreworldstreamtrace=1`, `/Game/VoxelForge/DA_Settings.DA_Settings`, seed 0, 25 cm Core voxels, 600 cm/s movement, and the Legacy/default streaming flags. It creates a transient `UWorld`; no map is loaded. + +The exact pre-U2 owner packages are unavailable in this Linux workspace. Both hosts used identical copies of the five current `/home/jahni/VoxelM/DA_*.uasset` files (post-U2), with matching SHA-256s in both projects: + +| Asset | SHA-256 | +|---|---| +| `DA_Settings` | `8abe8243104980260feca0a6f4cf4927768e8e568221a6f6a2c2694f6d15d454` | +| `DA_Strate1` | `a9ca6cddd102250a893e379350b1d0f4aaf04c4f7fca70e0db46052a067d2cfb` | +| `DA_Strate2` | `8f9a12a3181635149e6f79f192e0ddaf6b6577442ee324071a7749dcc78b9a0c` | +| `DA_Strate3` | `5470d538c3c5e88237463e71bca9e2eb170dfe3a0543c0f33298d9fb010fd2f9` | +| `DA_Strate4` | `a98e33e1cd42f374d6cb70f5071e8ebba74d91ed59d2fd3201782dab84d28f5c` | + +The minimal host lacked the two First Person Blueprints used by the commandlet's speed fixture. Stock UE template copies also lacked a valid sprint graph, so the isolated trace build trees used the test's established 600/6000 speed defaults only for `-StreamingTraceOnly`; no tracked source was changed for this workaround. The trace loop itself takes its 600 cm/s movement value from the command line. + +| Measure | L14 | HEAD (`e157847`) | +|---|---:|---:| +| Tiles per LOD | Not reached | Not reached | +| Cells per tile | Not reached | Not reached | +| Initial worker-seconds | Not reached | Not reached | +| LOD0 tile worker p50 / p95 | Not reached | Not reached | +| Full initial set ready | Not reached | Not reached | +| Walkable ring count / ready time | Not reached | Not reached | +| `generateTile` / mesh copy / RMC stream build | Not reached | Not reached | + +Both commandlets stop before spawning `AVoxelWorld` with the same error: `SurfaceWorld route candidates failed the capsule and support sweep.` No tile trace file was produced. Thus this run cannot identify the Windows worker-time regression or separate Core generation from Unreal packaging. The failure is consistent across L14 and HEAD, but whether the post-U2 asset set or the route audit itself is responsible is unresolved; no fix is justified from this run. + +L14 was exported from `a176d07` to the requested `Saved/Linux/l65/l14tree/Plugins/VoxelForge`. The sandbox did not permit creating the sibling `/home/jahni/VFHostL14`, so its second host project is nested at `/home/jahni/VFHost/VFHostL14/VFHostL14.uproject`. The supplied `/home/jahni/VFHost/VFHost.uproject` was restored byte-for-byte after testing. RealtimeMeshComponent's original source tree was not modified. + +## Failed runs + +- Initial builds hit a read-only UBT config path, then a read-only RMC intermediate timestamp, then a UBA stall. The next compile found Linux Unity duplicate test helpers; disabling Unity on Linux fixed it. A final incremental attempt made after restoring the original host descriptor again hit the RMC read-only timestamp; rebuilding with the local RMC copy passed. +- Two early trace launches rejected an output directory outside the host project. The next launch stopped on the absent staged character Blueprint. Stock UE template Blueprints then failed to provide a sprint value; the trace-only defaults got past that gate. Both final revisions then stopped at the identical SurfaceWorld route audit above. + +There were 12 build invocations, within the 15-attempt Part A limit. + +## Orchestrator review (Claude) + +Accepted. **The Linux UE build compiles VoxelForge with 0 errors** (HEAD and L14). I checked that the Compat and +`Source/` changes don't alter Core output: standalone Clang and GCC rebuilds produce **identical whole-view hashes** +to `3202193` on the pre-U2 data, for both SW and FI. The RealtimeMeshComponent tree is unmodified: its 203 git "M" +entries are CRLF-only (empty diff with whitespace and CR ignored, no file newer than this round outside +Intermediate/Binaries). The Unreal trace is blocked for both L14 and HEAD by the **owner's new assets**: +`SurfaceWorld route candidates failed the capsule and support sweep` before `AVoxelWorld` spawns (consistent with +L64: SW route 24/33 unsupported). The `verify.py` tiers still assume the old two-strate owner data and fail on the U2 +export; they need a pinned regression dataset plus new-plan baselines. `Source/` files to include in the owner's next +Windows build are listed above.