2014-08-08 15:35:56 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "BlueprintGraphPrivatePCH.h"
# include "BlueprintNodeTemplateCache.h"
2014-08-08 18:11:40 -04:00
# include "BlueprintEditorUtils.h" // for FindFirstNativeClass(), FindBlueprintForGraph()
2014-08-08 15:35:56 -04:00
# include "EdGraph/EdGraph.h"
2014-08-08 18:11:40 -04:00
# include "KismetEditorUtilities.h" // for CreateBlueprint()
# include "BlueprintNodeSpawner.h" // for NodeClass/Invoke()
2014-09-13 15:13:16 -04:00
# include "BlueprintEditorSettings.h"
DEFINE_LOG_CATEGORY_STATIC ( LogBlueprintNodeCache , Log , All ) ;
2014-08-08 15:35:56 -04:00
/*******************************************************************************
* Static FBlueprintNodeTemplateCache Helpers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
namespace BlueprintNodeTemplateCacheImpl
{
2014-09-15 15:52:55 -04:00
/** */
static int32 ActiveMemFootprint = 0 ;
/** Used to track the average blueprint size (so that we can try to predict when a blueprint would fail to be cached) */
static int32 MadeBlueprintCount = 0 ;
static int32 AverageBlueprintSize = 0 ;
/** Metadata tag used to identify graphs created by this system. */
static const FName TemplateGraphMetaTag ( TEXT ( " NodeTemplateCache_Graph " ) ) ;
2014-08-08 15:35:56 -04:00
/**
2014-09-15 15:52:55 -04:00
* Checks to see if this node is compatible with the given graph ( to know if
* a node template can be spawned within it ) .
2014-08-08 15:35:56 -04:00
*
2014-09-15 15:52:55 -04:00
* @ param NodeObj The CDO of the node you want to spawn .
* @ param Graph The graph you want to check compatibility for .
* @ return True if the node and graph are compatible ( for templating purposes ) .
2014-08-08 15:35:56 -04:00
*/
static bool IsCompatible ( UEdGraphNode * NodeObj , UEdGraph * Graph ) ;
/**
2014-09-15 15:52:55 -04:00
* Looks through a blueprint for compatible graphs ( ones that the specified
* node can spawn into ) .
2014-08-08 15:35:56 -04:00
*
2014-09-15 15:52:55 -04:00
* @ param BlueprintOuter The blueprint to search through .
* @ param NodeObj The CDO of the node you want to spawn .
* @ param IsCompatibleFunc An option callback function to further filter out incompatible nodes .
* @ return The first compatible graph found ( null if no graph was found ) .
2014-08-08 15:35:56 -04:00
*/
2014-09-15 15:52:55 -04:00
static UEdGraph * FindCompatibleGraph ( UBlueprint * BlueprintOuter , UEdGraphNode * NodeObj , bool ( * IsCompatibleFunc ) ( UEdGraph * ) = nullptr ) ;
2014-08-08 15:35:56 -04:00
/**
2014-09-15 15:52:55 -04:00
* Creates a transient , temporary blueprint . Intended to be used as a
* template - node ' s outer ( grandparent ) .
2014-08-08 15:35:56 -04:00
*
2014-09-15 15:52:55 -04:00
* @ param BlueprintClass The class of blueprint to make .
* @ param ParentClass The class type of blueprint to make ( actor , object , etc . ) .
* @ param GeneratedClassType The type of class that the blueprint should generate .
* @ return A newly spawned ( transient ) blueprint .
2014-08-08 15:35:56 -04:00
*/
static UBlueprint * MakeCompatibleBlueprint ( TSubclassOf < UBlueprint > BlueprintClass , UClass * ParentClass , TSubclassOf < UBlueprintGeneratedClass > GeneratedClassType ) ;
/**
2014-09-15 15:52:55 -04:00
* Creates a new transient graph , for template node use ( meant to be used as
* a template node ' s outer ) .
2014-08-08 15:35:56 -04:00
*
2014-09-15 15:52:55 -04:00
* @ param BlueprintOuter The blueprint to nest the new graph under .
* @ param SchemaClass The schema to assign the new graph .
* @ return A newly created graph .
2014-08-08 15:35:56 -04:00
*/
static UEdGraph * AddGraph ( UBlueprint * BlueprintOuter , TSubclassOf < UEdGraphSchema > SchemaClass ) ;
2014-09-13 15:13:16 -04:00
/**
2014-09-15 15:52:55 -04:00
* Adds metadata to the supplied graph , flagging it as a graph belonging to
* the BlueprintNodeTemplateCache ( so we can easily identify it later on ) .
2014-09-13 15:13:16 -04:00
*
2014-09-15 15:52:55 -04:00
* @ param NewGraph The graph to flag .
2014-09-13 15:13:16 -04:00
*/
2014-09-15 15:52:55 -04:00
static void MarkGraphForTemplateUse ( UEdGraph * NewGraph ) ;
2014-09-13 15:13:16 -04:00
/**
2014-09-15 15:52:55 -04:00
* Determines if the specified graph is one that was allocated by
* BlueprintNodeTemplateCache ( to house template nodes ) .
2014-09-13 15:13:16 -04:00
*
2014-09-15 15:52:55 -04:00
* @ param ParentGraph The graph you want checked .
* @ return True if this graph belongs to a BlueprintNodeTemplateCache , false if not .
*/
static bool IsTemplateOuter ( UEdGraph * ParentGraph ) ;
/**
* Converts the cache memory cap into bytes ( form user settings ) .
2014-09-13 15:13:16 -04:00
*
2014-09-15 15:52:55 -04:00
* @ return The user defined cache cap ( in bytes ) .
2014-09-13 15:13:16 -04:00
*/
static int32 GetCacheCapSize ( ) ;
2014-09-15 15:52:55 -04:00
/**
* Totals the size of the specified object , along with any other objects
* that have it in their outer chain . Does not account for any allocated
* memory that belongs to the object ( s ) .
*
* @ param Object The object you want an estimated byte size for .
* @ return An estimated size ( in bytes ) . . . currently does not account for any allocated memory that the object may be responsible for .
*/
static int32 ApproximateMemFootprint ( UObject const * Object ) ;
2014-08-08 15:35:56 -04:00
}
//------------------------------------------------------------------------------
static bool BlueprintNodeTemplateCacheImpl : : IsCompatible ( UEdGraphNode * NodeObj , UEdGraph * Graph )
{
return NodeObj - > CanCreateUnderSpecifiedSchema ( Graph - > GetSchema ( ) ) ;
}
//------------------------------------------------------------------------------
2014-09-15 15:52:55 -04:00
static UEdGraph * BlueprintNodeTemplateCacheImpl : : FindCompatibleGraph ( UBlueprint * BlueprintOuter , UEdGraphNode * NodeObj , bool ( * IsCompatibleFunc ) ( UEdGraph * ) )
2014-08-08 15:35:56 -04:00
{
UEdGraph * FoundGraph = nullptr ;
TArray < UObject * > BlueprintChildObjs ;
GetObjectsWithOuter ( BlueprintOuter , BlueprintChildObjs , /*bIncludeNestedObjects =*/ false , /*ExclusionFlags =*/ RF_PendingKill ) ;
for ( UObject * Child : BlueprintChildObjs )
{
UEdGraph * ChildGraph = Cast < UEdGraph > ( Child ) ;
2014-09-15 15:52:55 -04:00
bool bIsCompatible = ( ChildGraph ! = nullptr ) & & IsCompatible ( NodeObj , ChildGraph ) ;
if ( bIsCompatible & & ( IsCompatibleFunc ! = nullptr ) )
{
bIsCompatible = IsCompatibleFunc ( ChildGraph ) ;
}
if ( bIsCompatible )
2014-08-08 15:35:56 -04:00
{
FoundGraph = ChildGraph ;
break ;
}
}
return FoundGraph ;
}
//------------------------------------------------------------------------------
static UBlueprint * BlueprintNodeTemplateCacheImpl : : MakeCompatibleBlueprint ( TSubclassOf < UBlueprint > BlueprintClass , UClass * ParentClass , TSubclassOf < UBlueprintGeneratedClass > GeneratedClassType )
{
EBlueprintType BlueprintType = BPTYPE_Normal ;
// @TODO: BPTYPE_LevelScript requires a level outer, which we don't want to have here... can we get away without it?
// if (BlueprintClass->IsChildOf<ULevelScriptBlueprint>())
// {
// BlueprintType = BPTYPE_LevelScript;
// }
if ( GeneratedClassType = = nullptr )
{
GeneratedClassType = UBlueprintGeneratedClass : : StaticClass ( ) ;
}
UPackage * BlueprintOuter = GetTransientPackage ( ) ;
FString const DesiredName = FString : : Printf ( TEXT ( " PROTO_BP_%s " ) , * BlueprintClass - > GetName ( ) ) ;
FName const BlueprintName = MakeUniqueObjectName ( BlueprintOuter , BlueprintClass , FName ( * DesiredName ) ) ;
BlueprintClass = FBlueprintEditorUtils : : FindFirstNativeClass ( BlueprintClass ) ;
UBlueprint * NewBlueprint = FKismetEditorUtilities : : CreateBlueprint ( ParentClass , BlueprintOuter , BlueprintName , BlueprintType , BlueprintClass , GeneratedClassType ) ;
NewBlueprint - > SetFlags ( RF_Transient ) ;
2014-09-15 19:08:11 -04:00
+ + MadeBlueprintCount ;
2014-09-15 15:52:55 -04:00
float const AproxBlueprintSize = ApproximateMemFootprint ( NewBlueprint ) ;
// track the average blueprint size, so that we can attempt to predict
// whether a blueprint will fail to be cached (when the cache is near full)
2014-09-15 19:08:11 -04:00
AverageBlueprintSize = AverageBlueprintSize * ( ( float ) ( MadeBlueprintCount - 1 ) / MadeBlueprintCount ) +
2014-09-15 15:52:55 -04:00
( AproxBlueprintSize / MadeBlueprintCount ) + 0.5f ;
2014-08-08 15:35:56 -04:00
return NewBlueprint ;
}
//------------------------------------------------------------------------------
static UEdGraph * BlueprintNodeTemplateCacheImpl : : AddGraph ( UBlueprint * BlueprintOuter , TSubclassOf < UEdGraphSchema > SchemaClass )
{
UClass * GraphClass = UEdGraph : : StaticClass ( ) ;
FName const GraphName = MakeUniqueObjectName ( BlueprintOuter , GraphClass , FName ( TEXT ( " TEMPLATE_NODE_OUTER " ) ) ) ;
UEdGraph * NewGraph = ConstructObject < UEdGraph > ( GraphClass , BlueprintOuter , GraphName , RF_Transient ) ;
NewGraph - > Schema = SchemaClass ;
2014-09-15 15:52:55 -04:00
MarkGraphForTemplateUse ( NewGraph ) ;
2014-08-08 15:35:56 -04:00
return NewGraph ;
}
2014-09-13 15:13:16 -04:00
//------------------------------------------------------------------------------
2014-09-15 15:52:55 -04:00
static void BlueprintNodeTemplateCacheImpl : : MarkGraphForTemplateUse ( UEdGraph * NewGraph )
{
UPackage * TemplatePackage = NewGraph - > GetOutermost ( ) ;
UMetaData * PackageMetadata = TemplatePackage - > GetMetaData ( ) ;
PackageMetadata - > SetValue ( NewGraph , TemplateGraphMetaTag , TEXT ( " true " ) ) ;
}
//------------------------------------------------------------------------------
bool BlueprintNodeTemplateCacheImpl : : IsTemplateOuter ( UEdGraph * ParentGraph )
{
2014-09-23 13:59:55 -04:00
if ( ParentGraph - > HasAnyFlags ( RF_Transactional ) )
2014-09-15 15:52:55 -04:00
{
UPackage * GraphPackage = ParentGraph - > GetOutermost ( ) ;
UMetaData * PackageMetadata = GraphPackage - > GetMetaData ( ) ;
return PackageMetadata - > HasValue ( ParentGraph , TemplateGraphMetaTag ) ;
}
return false ;
}
//------------------------------------------------------------------------------
static int32 BlueprintNodeTemplateCacheImpl : : GetCacheCapSize ( )
{
UBlueprintEditorSettings const * BpSettings = GetDefault < UBlueprintEditorSettings > ( ) ;
// have to convert from MB to bytes
return ( BpSettings - > NodeTemplateCacheCapMB * 1024.f * 1024.f ) + 0.5f ;
}
//------------------------------------------------------------------------------
static int32 BlueprintNodeTemplateCacheImpl : : ApproximateMemFootprint ( UObject const * Object )
2014-09-13 15:13:16 -04:00
{
TArray < UObject * > ChildObjs ;
2014-09-15 15:52:55 -04:00
GetObjectsWithOuter ( Object , ChildObjs , /*bIncludeNestedObjects =*/ true ) ;
2014-09-13 15:13:16 -04:00
int32 ApproimateDataSize = sizeof ( * Object ) ;
for ( UObject * ChildObj : ChildObjs )
{
// @TODO: doesn't account for any internal allocated memory (for member TArrays, etc.)
ApproimateDataSize + = sizeof ( * ChildObj ) ;
}
return ApproimateDataSize ;
}
2014-09-15 15:52:55 -04:00
/*******************************************************************************
* FBlueprintNodeTemplateCache
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-09-13 15:13:16 -04:00
2014-08-08 15:35:56 -04:00
//------------------------------------------------------------------------------
FBlueprintNodeTemplateCache : : FBlueprintNodeTemplateCache ( )
2014-09-15 15:52:55 -04:00
: ApproximateObjectMem ( 0 )
2014-08-08 15:35:56 -04:00
{
using namespace BlueprintNodeTemplateCacheImpl ; // for MakeCompatibleBlueprint()
2014-09-13 15:13:16 -04:00
UBlueprint * StandardBlueprint = MakeCompatibleBlueprint ( UBlueprint : : StaticClass ( ) , AActor : : StaticClass ( ) , UBlueprintGeneratedClass : : StaticClass ( ) ) ;
2014-09-15 15:52:55 -04:00
CacheBlueprintOuter ( StandardBlueprint ) ;
2014-09-13 15:13:16 -04:00
UBlueprint * AnimBlueprint = MakeCompatibleBlueprint ( UAnimBlueprint : : StaticClass ( ) , UAnimInstance : : StaticClass ( ) , UAnimBlueprintGeneratedClass : : StaticClass ( ) ) ;
2014-09-15 15:52:55 -04:00
CacheBlueprintOuter ( AnimBlueprint ) ;
2014-08-08 15:35:56 -04:00
}
//------------------------------------------------------------------------------
UEdGraphNode * FBlueprintNodeTemplateCache : : GetNodeTemplate ( UBlueprintNodeSpawner const * NodeSpawner , UEdGraph * TargetGraph )
{
using namespace BlueprintNodeTemplateCacheImpl ;
2014-09-15 15:52:55 -04:00
bool bIsOverMemCap = false ;
auto LogCacheFullMsg = [ & bIsOverMemCap ] ( )
{
if ( ! bIsOverMemCap )
{
static int32 LoggedCapSize = - 1 ;
int32 const CurrentCacheSize = GetCacheCapSize ( ) ;
// log only once for each cap size change
if ( LoggedCapSize ! = CurrentCacheSize )
{
UE_LOG ( LogBlueprintNodeCache , Display , TEXT ( " The blueprint template-node cache is full. As a result, you may experience interactions which are slower than normal. To avoid this, increase the cache's cap in the blueprint editor prefences. " ) ) ;
LoggedCapSize = CurrentCacheSize ;
}
bIsOverMemCap = true ;
}
} ;
2014-08-08 15:35:56 -04:00
UEdGraphNode * TemplateNode = nullptr ;
if ( UEdGraphNode * * FoundNode = NodeTemplateCache . Find ( NodeSpawner ) )
{
TemplateNode = * FoundNode ;
}
else if ( NodeSpawner - > NodeClass ! = nullptr )
{
UEdGraphNode * NodeCDO = NodeSpawner - > NodeClass - > GetDefaultObject < UEdGraphNode > ( ) ;
check ( NodeCDO ! = nullptr ) ;
UBlueprint * TargetBlueprint = nullptr ;
TSubclassOf < UBlueprint > BlueprintClass ;
bool const bHasTargetGraph = ( TargetGraph ! = nullptr ) ;
if ( bHasTargetGraph )
{
// by the time we're asking for a prototype for this spawner, we should
// be sure that it is compatible with the TargetGraph
2014-08-21 18:50:33 -04:00
//check(IsCompatible(NodeCDO, TargetGraph));
2014-08-08 15:35:56 -04:00
2014-08-21 18:50:33 -04:00
TargetBlueprint = FBlueprintEditorUtils : : FindBlueprintForGraph ( TargetGraph ) ;
2014-08-08 15:35:56 -04:00
check ( TargetBlueprint ! = nullptr ) ;
2014-08-21 18:50:33 -04:00
BlueprintClass = TargetBlueprint - > GetClass ( ) ;
2014-09-15 15:52:55 -04:00
// check used to help identify user interactable graphs (as opposed to
// intermediate/transient graphs).
auto IsCompatibleUserGraph = [ ] ( UEdGraph * Graph ) - > bool
{
return ! Graph - > HasAnyFlags ( RF_Transient ) ;
} ;
TargetGraph = FindCompatibleGraph ( TargetBlueprint , NodeCDO , IsCompatibleUserGraph ) ;
2014-08-21 18:50:33 -04:00
check ( TargetGraph ! = nullptr ) ;
2014-08-08 15:35:56 -04:00
}
UBlueprint * CompatibleBlueprint = nullptr ;
UEdGraph * CompatibleOuter = nullptr ;
// find a compatible outer (don't want to have to create a new one if we don't have to)
for ( UBlueprint * Blueprint : TemplateOuters )
{
CompatibleOuter = FindCompatibleGraph ( Blueprint , NodeCDO ) ;
2014-09-15 15:52:55 -04:00
if ( CompatibleOuter ! = nullptr )
{
MarkGraphForTemplateUse ( CompatibleOuter ) ;
}
2014-08-08 15:35:56 -04:00
if ( CompatibleOuter ! = nullptr )
{
CompatibleBlueprint = Blueprint ;
break ;
}
else if ( ( BlueprintClass ! = nullptr ) & & Blueprint - > GetClass ( ) - > IsChildOf ( BlueprintClass ) )
{
CompatibleBlueprint = Blueprint ;
}
}
2014-09-15 15:52:55 -04:00
// reset ActiveMemFootprint, so calls to CacheBlueprintOuter()/CacheTemplateNode()
// use the most up-to-date value (users could have since modified the
// nodes, so they could have grown in size... like with AllocateDefaultPins)
//
// @TODO: GetEstimateCacheSize() is (most likely) inaccurate, seeing as
// external systems mutate template-nodes (such as calling
// AllocateDefaultPins), and this returns a size estimate from
// when the node was first spawned (it is too slow to recalculate
// the size of the object hierarchy here)
ActiveMemFootprint = GetEstimateCacheSize ( ) ;
int32 const CacheCapSize = GetCacheCapSize ( ) ;
if ( ActiveMemFootprint > CacheCapSize )
{
LogCacheFullMsg ( ) ;
// @TODO: evict nodes until we're back under the cap (in case the cap
// was changed at runtime, or external user modified node sizes)
}
2014-08-08 15:35:56 -04:00
// if a TargetGraph was supplied, and we couldn't find a suitable outer
// for this template-node, then attempt to emulate that graph
if ( bHasTargetGraph )
{
if ( CompatibleBlueprint = = nullptr )
{
2014-09-15 15:52:55 -04:00
// if the cache is near full, attempt to predict if this
// impending cache will fail (if so, we don't want to waste the
// cycles on allocating a temp blueprint)
if ( ! bIsOverMemCap & & ( ( AverageBlueprintSize = = 0 ) | |
( ActiveMemFootprint + AverageBlueprintSize < = CacheCapSize ) ) )
2014-08-08 15:35:56 -04:00
{
2014-09-15 15:52:55 -04:00
TSubclassOf < UBlueprintGeneratedClass > GeneratedClassType = UBlueprintGeneratedClass : : StaticClass ( ) ;
if ( TargetBlueprint - > GeneratedClass ! = nullptr )
{
GeneratedClassType = TargetBlueprint - > GeneratedClass - > GetClass ( ) ;
}
2014-08-08 15:35:56 -04:00
2014-09-15 15:52:55 -04:00
CompatibleBlueprint = MakeCompatibleBlueprint ( BlueprintClass , TargetBlueprint - > ParentClass , GeneratedClassType ) ;
if ( ! CacheBlueprintOuter ( CompatibleBlueprint ) )
{
LogCacheFullMsg ( ) ;
}
// this graph may come default with a compatible graph
CompatibleOuter = FindCompatibleGraph ( CompatibleBlueprint , NodeCDO ) ;
if ( CompatibleOuter ! = nullptr )
{
MarkGraphForTemplateUse ( CompatibleOuter ) ;
}
}
else
2014-09-13 15:13:16 -04:00
{
2014-09-15 15:52:55 -04:00
CompatibleBlueprint = TargetBlueprint ;
CompatibleOuter = FindCompatibleGraph ( TargetBlueprint , NodeCDO , & BlueprintNodeTemplateCacheImpl : : IsTemplateOuter ) ;
2014-08-08 15:35:56 -04:00
2014-09-15 15:52:55 -04:00
LogCacheFullMsg ( ) ;
}
2014-08-08 15:35:56 -04:00
}
if ( CompatibleOuter = = nullptr )
{
CompatibleOuter = AddGraph ( CompatibleBlueprint , TargetGraph - > Schema ) ;
2014-09-15 15:52:55 -04:00
if ( CompatibleBlueprint ! = TargetBlueprint )
{
int32 const ApproxGraphSize = ApproximateMemFootprint ( CompatibleOuter ) ;
ActiveMemFootprint + = ApproxGraphSize ;
ApproximateObjectMem + = ApproxGraphSize ;
}
2014-08-08 15:35:56 -04:00
}
}
if ( CompatibleOuter ! = nullptr )
{
2014-09-10 16:14:07 -04:00
TemplateNode = NodeSpawner - > Invoke ( CompatibleOuter , IBlueprintNodeBinder : : FBindingSet ( ) , FVector2D : : ZeroVector ) ;
2014-09-15 15:52:55 -04:00
if ( ! bIsOverMemCap & & ! CacheTemplateNode ( NodeSpawner , TemplateNode ) )
2014-09-13 15:13:16 -04:00
{
2014-09-15 15:52:55 -04:00
LogCacheFullMsg ( ) ;
2014-09-13 15:13:16 -04:00
}
2014-08-08 15:35:56 -04:00
}
}
return TemplateNode ;
}
2014-09-12 12:56:24 -04:00
//------------------------------------------------------------------------------
UEdGraphNode * FBlueprintNodeTemplateCache : : GetNodeTemplate ( UBlueprintNodeSpawner const * NodeSpawner , ENoInit ) const
{
UEdGraphNode * TemplateNode = nullptr ;
if ( UEdGraphNode * const * FoundNode = NodeTemplateCache . Find ( NodeSpawner ) )
{
return * FoundNode ;
}
return nullptr ;
}
2014-08-08 15:35:56 -04:00
//------------------------------------------------------------------------------
void FBlueprintNodeTemplateCache : : ClearCachedTemplate ( UBlueprintNodeSpawner const * NodeSpawner )
{
2014-09-15 15:52:55 -04:00
NodeTemplateCache . Remove ( NodeSpawner ) ;
// GC should take care of the rest
2014-08-08 15:35:56 -04:00
}
2014-09-13 15:13:16 -04:00
//------------------------------------------------------------------------------
2014-09-15 15:52:55 -04:00
int32 FBlueprintNodeTemplateCache : : GetEstimateCacheSize ( ) const
2014-09-13 15:13:16 -04:00
{
2014-09-15 15:52:55 -04:00
int32 TotalEstimatedSize = ApproximateObjectMem ;
2014-09-13 15:13:16 -04:00
TotalEstimatedSize + = TemplateOuters . GetAllocatedSize ( ) ;
2014-09-15 15:52:55 -04:00
TotalEstimatedSize + = NodeTemplateCache . GetAllocatedSize ( ) ;
TotalEstimatedSize + = sizeof ( * this ) ;
2014-09-13 15:13:16 -04:00
return TotalEstimatedSize ;
}
2014-09-15 15:52:55 -04:00
//------------------------------------------------------------------------------
int32 FBlueprintNodeTemplateCache : : RecalculateCacheSize ( )
{
ApproximateObjectMem = 0 ;
for ( UBlueprint * Blueprint : TemplateOuters )
{
// if we didn't run garbage collection at the top, then this could also
// account for nodes that were never stored (because the cache was too full)
ApproximateObjectMem + = BlueprintNodeTemplateCacheImpl : : ApproximateMemFootprint ( Blueprint ) ;
}
return ApproximateObjectMem ;
}
//------------------------------------------------------------------------------
bool FBlueprintNodeTemplateCache : : IsTemplateOuter ( UEdGraph * ParentGraph )
{
return BlueprintNodeTemplateCacheImpl : : IsTemplateOuter ( ParentGraph ) ;
}
2014-08-08 15:35:56 -04:00
//------------------------------------------------------------------------------
void FBlueprintNodeTemplateCache : : AddReferencedObjects ( FReferenceCollector & Collector )
{
for ( auto & TemplateEntry : NodeTemplateCache )
{
Collector . AddReferencedObject ( TemplateEntry . Value ) ;
}
Collector . AddReferencedObjects ( TemplateOuters ) ;
}
2014-09-13 15:13:16 -04:00
//------------------------------------------------------------------------------
2014-09-15 15:52:55 -04:00
bool FBlueprintNodeTemplateCache : : CacheBlueprintOuter ( UBlueprint * Blueprint )
2014-09-13 15:13:16 -04:00
{
2014-09-15 15:52:55 -04:00
using namespace BlueprintNodeTemplateCacheImpl ;
int32 const ApproxBlueprintSize = ApproximateMemFootprint ( Blueprint ) ;
2014-09-13 15:13:16 -04:00
2014-09-15 15:52:55 -04:00
if ( ActiveMemFootprint + ApproxBlueprintSize > GetCacheCapSize ( ) )
2014-09-13 15:13:16 -04:00
{
return false ;
}
else
{
2014-09-15 15:52:55 -04:00
ApproximateObjectMem + = ApproxBlueprintSize ;
2014-09-13 15:13:16 -04:00
TemplateOuters . Add ( Blueprint ) ;
return true ;
}
}
//------------------------------------------------------------------------------
bool FBlueprintNodeTemplateCache : : CacheTemplateNode ( UBlueprintNodeSpawner const * NodeSpawner , UEdGraphNode * NewNode )
{
2014-09-15 15:52:55 -04:00
using namespace BlueprintNodeTemplateCacheImpl ;
2014-09-13 15:13:16 -04:00
if ( NewNode = = nullptr )
{
return true ;
}
int32 const ApproxNodeSize = BlueprintNodeTemplateCacheImpl : : ApproximateMemFootprint ( NewNode ) ;
2014-09-15 15:52:55 -04:00
if ( ActiveMemFootprint + ApproxNodeSize > GetCacheCapSize ( ) )
2014-09-13 15:13:16 -04:00
{
return false ;
}
else
{
2014-09-15 15:52:55 -04:00
ApproximateObjectMem + = ApproxNodeSize ;
2014-09-13 15:13:16 -04:00
NodeTemplateCache . Add ( NodeSpawner , NewNode ) ;
return true ;
}
}