Hey!
In our game we care about patches (in .pak file sense) being lean and containing only changes we expect, so I was investigating issues of cooking indeterminism (i.e. cooking the same unchanged asset twice resulting in different output files) and fixing them. Below are engine issues I’ve found and fixed. Maybe you can tell if fixes are okay or maybe I’ve misunderstood something?
UProceduralMeshComponent::ProcMeshBodySetup
We have some blueprints which create ProceduralMeshComponents on construction. Construction of procedural meshes is perfectly deterministic in all such cases but each time it’s constructed GUID of body setup is recreated, leading to indeterministic output. I replaced FGuid::NewGuid() with FGuid::NewDeterministicGuid(GetPathName()) which seems to be fine in this case.
FProcMeshSection::SectionLocalBox
This issue is just one of manifestation of more general bug: calculation of zero mask in unversioned property serialization is done by comparing memory representation of a property with zeros which is indeterministic if property contains padding bytes. In the case of UProceduralMeshComponent there is an issue with SectionLocalBox inside of ProcMeshSections. FBox has padding bytes so comparison memory with zero can fail. Trying to fix unversioned property serialization would be to much of a change so I added a crutch doing Memzero on SectionLocalBox in FProcMeshSection constructor, which is not exactly safe but does the job.
StaticMeshComponent::BodyInstance
I’ve found this issue in serialization of LevelSequence with StaticMeshActor with default collision for which mesh has NoCollision profile. The issue seems to be in the fact that in the case of default collision StaticMeshComponent loads collision parameters from mesh in UStaticMeshComponent::UpdateCollisionFromMesh method which is called only after mesh is compiled. So if component is being cooked before mesh is compiled then collision parameters are not loaded from mesh resulting in output being indeterministic. I’ve fixed it adding the following piece into UStaticMeshComponent::Serialize before Super::Serialize():
#if WITH_EDITOR
if (Ar.IsCooking() && bUseDefaultCollision)
{
if (UStaticMesh* Mesh = GetStaticMesh())
{
if (Mesh->IsCompiling())
{
FStaticMeshCompilingManager::Get().FinishCompilation({ Mesh });
}
}
UpdateCollisionFromStaticMesh();
}
#endif
[Attachment Removed]