Files
UnrealEngineUWP/Engine/Source/Editor/AnimGraph/Private/AnimBlueprintCompiler.h
Thomas Sarkanen e485a55acb Fix various issues with child anim BPs
If a child anim BP is made and is saved without saving its parent, then when the class is reloaded later it will not be able to find the parent's sparse class data in the linker (as it will have been generated again from scratch on load, which doesnt patch the linker until the asset is resaved). This leads to serialization size mismatches.
To address this (and because the sparse class data will always be regenerated as part of compile-on-load), we skip the portion of the CDO's archive that represents the serialized sparse class data if it is null after serialization. It can of course be legitimately null in a lot of cases (say a regular actor Blueprint), but this should have no ill effects and effectively be a seek to the current archive offset.

This CL also fixes a number of child anim BP-related issues. First of all it prevents a crash when accessing out-of-bounds AnimNodeData by ensuring it is correctly duplicated in all circumstances. It also correctly propogates values from root->child sparse class data (in the same manner that anim node data used to be propogated before). This deals with compile-on-load issues where the child classes sparse class data is regenerated without serializing the parent classes sparse class data (see crash fix above).

#jira UE-114674 - Creating a new child anim BP crashes
#rb Fred.Kimberley,Phillip.Kavan,Jurre.deBaare

[CL 16313070 by Thomas Sarkanen in ue5-main branch]
2021-05-13 10:56:35 -04:00

212 lines
9.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "KismetCompiler.h"
#include "Animation/AnimNodeBase.h"
#include "AnimGraphNode_Base.h"
#include "KismetCompilerModule.h"
#include "IAnimBlueprintCompilerCreationContext.h"
#include "Containers/ArrayView.h"
#include "IAnimBlueprintCompilationContext.h"
class UAnimationGraphSchema;
class UAnimGraphNode_SaveCachedPose;
class UAnimGraphNode_StateMachineBase;
class UAnimGraphNode_StateResult;
class UAnimGraphNode_CustomProperty;
class UAnimGraphNode_UseCachedPose;
class UAnimStateTransitionNode;
class UK2Node_CallFunction;
//
// Forward declarations.
//
class UAnimGraphNode_SaveCachedPose;
class UAnimGraphNode_UseCachedPose;
class UAnimGraphNode_LinkedInputPose;
class UAnimGraphNode_LinkedAnimGraphBase;
class UAnimGraphNode_LinkedAnimGraph;
class UAnimGraphNode_Root;
class FStructProperty;
class UBlueprintGeneratedClass;
struct FPoseLinkMappingRecord;
struct FAnimGraphNodePropertyBinding;
class FAnimBlueprintCompilerContext;
//////////////////////////////////////////////////////////////////////////
// FAnimBlueprintCompilerContext
class FAnimBlueprintCompilerContext : public FKismetCompilerContext
{
friend class FAnimBlueprintCompilerCreationContext;
friend class FAnimBlueprintCompilationContext;
friend class FAnimBlueprintVariableCreationContext;
friend class FAnimBlueprintCompilationBracketContext;
friend class FAnimBlueprintPostExpansionStepContext;
friend class FAnimBlueprintCopyTermDefaultsContext;
protected:
typedef FKismetCompilerContext Super;
public:
FAnimBlueprintCompilerContext(UAnimBlueprint* SourceSketch, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions);
virtual ~FAnimBlueprintCompilerContext();
protected:
// Implementation of FKismetCompilerContext interface
virtual void CreateClassVariablesFromBlueprint() override;
virtual UEdGraphSchema_K2* CreateSchema() override;
virtual void MergeUbergraphPagesIn(UEdGraph* Ubergraph) override;
virtual void ProcessOneFunctionGraph(UEdGraph* SourceGraph, bool bInternalFunction = false) override;
virtual void SpawnNewClass(const FString& NewClassName) override;
virtual void OnNewClassSet(UBlueprintGeneratedClass* ClassToUse) override;
virtual void OnPostCDOCompiled() override;
virtual void CopyTermDefaultsToDefaultObject(UObject* DefaultObject) override;
virtual void PostCompile() override;
virtual void PostCompileDiagnostics() override;
virtual void EnsureProperGeneratedClass(UClass*& TargetClass) override;
virtual void CleanAndSanitizeClass(UBlueprintGeneratedClass* ClassToClean, UObject*& InOldCDO) override;
virtual void FinishCompilingClass(UClass* Class) override;
virtual void PrecompileFunction(FKismetFunctionContext& Context, EInternalCompilerFlags InternalFlags) override;
virtual void SetCalculatedMetaDataAndFlags(UFunction* Function, UK2Node_FunctionEntry* EntryNode, const UEdGraphSchema_K2* Schema ) override;
virtual bool ShouldForceKeepNode(const UEdGraphNode* Node) const override;
virtual void PostExpansionStep(const UEdGraph* Graph) override;
// End of FKismetCompilerContext interface
protected:
typedef TArray<UEdGraphPin*> UEdGraphPinArray;
protected:
UScriptStruct* NewAnimBlueprintConstants;
UScriptStruct* NewAnimBlueprintMutables;
FStructProperty* NewMutablesProperty;
UAnimBlueprint* AnimBlueprint;
UAnimationGraphSchema* AnimSchema;
// Map of allocated v3 nodes that are members of the class
TMap<class UAnimGraphNode_Base*, FProperty*> AllocatedAnimNodes;
TMap<FProperty*, class UAnimGraphNode_Base*> AllocatedNodePropertiesToNodes;
TMap<FProperty*, class UAnimGraphNode_Base*> AllocatedNodeConstantPropertiesToNodes;
TMap<int32, FProperty*> AllocatedPropertiesByIndex;
// Map of true source objects (user edited ones) to the cloned ones that are actually compiled
TMap<class UAnimGraphNode_Base*, UAnimGraphNode_Base*> SourceNodeToProcessedNodeMap;
// Index of the nodes (must match up with the runtime discovery process of nodes, which runs thru the property chain)
int32 AllocateNodeIndexCounter;
TMap<class UAnimGraphNode_Base*, int32> AllocatedAnimNodeIndices;
// Map from pose link LinkID address
//@TODO: Bad structure for a list of these
TArray<FPoseLinkMappingRecord> ValidPoseLinkList;
// Stub graphs we generated for animation graph functions
TArray<UEdGraph*> GeneratedStubGraphs;
// True if any parent class is also generated from an animation blueprint
bool bIsDerivedAnimBlueprint;
// Graph schema classes that this compiler is aware of - they will skip default function processing
TArray<TSubclassOf<UEdGraphSchema>> KnownGraphSchemas;
// Expose compile options to handlers
using FKismetCompilerContext::CompileOptions;
// Records of folded properties gleaned from nodes
TArray<TSharedRef<IAnimBlueprintCompilationContext::FFoldedPropertyRecord>> ConstantPropertyRecords;
TArray<TSharedRef<IAnimBlueprintCompilationContext::FFoldedPropertyRecord>> MutablePropertyRecords;
// Allows lookups to see if a node participates in constant folding
TMap<UAnimGraphNode_Base*, TArray<TSharedRef<IAnimBlueprintCompilationContext::FFoldedPropertyRecord>>> NodeToFoldedPropertyRecordMap;
// Maps of extension <-> generated property on the instance
TMap<UAnimBlueprintExtension*, FStructProperty*> ExtensionToInstancePropertyMap;
TMap<FStructProperty*, UAnimBlueprintExtension*> InstancePropertyToExtensionMap;
// Maps of extension <-> generated property on the class
TMap<UAnimBlueprintExtension*, FStructProperty*> ExtensionToClassPropertyMap;
TMap<FStructProperty*, UAnimBlueprintExtension*> ClassPropertyToExtensionMap;
private:
// Get the generated class as an anim blueprint generated class
UAnimBlueprintGeneratedClass* GetNewAnimBlueprintClass() const { return CastChecked<UAnimBlueprintGeneratedClass>(NewClass); };
// Run a function on the passed-in graph and each subgraph of it
void ForAllSubGraphs(UEdGraph* InGraph, TFunctionRef<void(UEdGraph*)> InPerGraphFunction);
// Prunes any nodes that aren't reachable via a pose link
void PruneIsolatedAnimationNodes(const TArray<UAnimGraphNode_Base*>& RootSet, TArray<UAnimGraphNode_Base*>& GraphNodes);
// Compiles one animation node
void ProcessAnimationNode(UAnimGraphNode_Base* VisualAnimNode);
// Called during ProcessAnimationNode - gather property folding records for the node
void GatherFoldRecordsForAnimationNode(const UScriptStruct* InNodeType, FStructProperty* InNodeProperty, UAnimGraphNode_Base* InVisualAnimNode);
// Compiles an entire animation graph
void ProcessAllAnimationNodes();
// Processes all the supplied anim nodes
void ProcessAnimationNodes(TArray<UAnimGraphNode_Base*>& AnimNodeList);
// Process all the requested extensions
void ProcessExtensions();
// Gets all anim graph nodes that are piped into the provided node (traverses input pins)
void GetLinkedAnimNodes(UAnimGraphNode_Base* InGraphNode, TArray<UAnimGraphNode_Base*>& LinkedAnimNodes) const;
void GetLinkedAnimNodes_TraversePin(UEdGraphPin* InPin, TArray<UAnimGraphNode_Base*>& LinkedAnimNodes) const;
void GetLinkedAnimNodes_ProcessAnimNode(UAnimGraphNode_Base* AnimNode, TArray<UAnimGraphNode_Base*>& LinkedAnimNodes) const;
// Returns the allocation index of the specified node, processing it if it was pending
int32 GetAllocationIndexOfNode(UAnimGraphNode_Base* VisualAnimNode);
// Create transient stub functions for each anim graph we are compiling
void CreateAnimGraphStubFunctions();
// Clean up transient stub functions
void DestroyAnimGraphStubFunctions();
// Expands split pins for a graph
void ExpandSplitPins(UEdGraph* InGraph);
// Add the specified compiled-in attribute uniquely to the specified node
void AddAttributesToNode(UAnimGraphNode_Base* InNode, TArrayView<const FName> InAttributes) const;
// Get the current compiled-in attributes uniquely assigned to the specified node
TArrayView<const FName> GetAttributesFromNode(UAnimGraphNode_Base* InNode) const;
// Called at the start of compilation to (re-) create the mutable struct
void RecreateMutables();
// (Re-)creates sparse class data structure. Called at the start of compilation to (re-) create the internal sparse
// class data. For derived anim BPs this is called just-in-time before CDO copy. This is to ensure that the sparse
// class data is always updated, as in some cases as the layout does not change a full compilation of a (data-only)
// derived anim BP may be skipped.
void RecreateSparseClassData();
// Create a uniquely named variable corresponding to an object in the current class
FProperty* CreateUniqueVariable(UObject* InForObject, const FEdGraphPinType& Type);
/** Creates a variable on the specified struct */
FProperty* CreateStructVariable(UScriptStruct* InStruct, const FName VarName, const FEdGraphPinType& VarType);
/** Adds a record for a potentially-folded anim node property */
void AddFoldedPropertyRecord(UAnimGraphNode_Base* InAnimGraphNode, FStructProperty* InAnimNodeProperty, FProperty* InProperty, bool bInExposedOnPin, bool bInPinConnected);
/** Process any anim node properties that are 'foldable' */
void ProcessFoldedPropertyRecords();
// Check whether an anim node participates in constant folding
bool IsAnimGraphNodeFolded(UAnimGraphNode_Base* InNode) const;
// Copy the AnimNodeData array etc. from root anim BP class to a derived anim BP
void CopyAnimNodeDataFromRoot() const;
// Get the folded property record, if any, for the supplied node & named property
const IAnimBlueprintCompilationContext::FFoldedPropertyRecord* GetFoldedPropertyRecord(UAnimGraphNode_Base* InNode, FName InPropertyName) const;
};