void USkookumScriptListener::add_dynamic_function(FName callback_name, UClass * callback_owner_class_p, FNativeFuncPtr exec_p)
  {
  // Find the function
  UFunction * function_p = StaticClass()->FindFunctionByName(callback_name, EIncludeSuperFlag::ExcludeSuper);
  if (!function_p)
    {
    // Duplicate the signature function object

    // Find callback event object on owner class
    UMulticastDelegateProperty * event_property_p = CastChecked<UMulticastDelegateProperty>(callback_owner_class_p->FindPropertyByName(callback_name));

    // Duplicate it
    FObjectDuplicationParameters dupe_parameters(event_property_p->SignatureFunction, StaticClass());
    //Parameters.CreatedObjects = &DuplicatedObjectList;
    dupe_parameters.DestName = callback_name;
    function_p = Cast<UFunction>(StaticDuplicateObjectEx(dupe_parameters));

    // Adjust parameters
    function_p->FunctionFlags |= FUNC_Public | FUNC_BlueprintCallable | FUNC_Native;
    function_p->SetNativeFunc(exec_p);
    function_p->StaticLink(true);
    for (TFieldIterator<UProperty> param_it(function_p); param_it; ++param_it)
      {
      // Callback parameters are always inputs
      (*param_it)->PropertyFlags &= ~CPF_OutParm;
      }

    // Make method known to its class
    function_p->Next = StaticClass()->Children;
    StaticClass()->Children = function_p;
    StaticClass()->AddFunctionToFunctionMap(function_p, function_p->GetFName());
    }
  }
// Clones (deep copies) a UEdGraph, including all of it's nodes and pins and their links,
// maintaining a mapping from the clone to the source nodes (even across multiple clonings)
UEdGraph* FEdGraphUtilities::CloneGraph(UEdGraph* InSource, UObject* NewOuter, FCompilerResultsLog* MessageLog, bool bCloningForCompile)
{
	// Duplicate the graph, keeping track of what was duplicated
	TMap<UObject*, UObject*> DuplicatedObjectList;

	UObject* UseOuter = (NewOuter != NULL) ? NewOuter : GetTransientPackage();
	FObjectDuplicationParameters Parameters(InSource, UseOuter);
	Parameters.CreatedObjects = &DuplicatedObjectList;

	if (bCloningForCompile || (NewOuter == NULL))
	{
		Parameters.ApplyFlags |= RF_Transient;
	}

	UEdGraph* ClonedGraph = CastChecked<UEdGraph>(StaticDuplicateObjectEx(Parameters));

	// Store backtrack links from each duplicated object to the original source object
	if (MessageLog != NULL)
	{
		for (TMap<UObject*, UObject*>::TIterator It(DuplicatedObjectList); It; ++It)
		{
			UObject* const Source = It.Key();
			UObject* const Dest = It.Value();

			MessageLog->NotifyIntermediateObjectCreation(Dest, Source);
		}
	}

	return ClonedGraph;
}
/**
 * Uses test maps in Engine and/or game content folder which are populated with a few blueprint instances
 * See InstanceTestMaps entries in the [Automation.Blueprint] config sections
 * For all blueprint instances in the map:
 *		Duplicates the instance 
 *		Compares the duplicated instance properties to the original instance properties
 */
bool FBlueprintInstancesTest::RunTest(const FString& InParameters)
{
	FBlueprintAutomationTestUtilities::LoadMap(InParameters);

	// Pause before running test
	ADD_LATENT_AUTOMATION_COMMAND(FDelayLatentCommand(2.f));

	// Grab BP instances from map
	TSet<AActor*> BlueprintInstances;
	for ( FActorIterator It(GWorld); It; ++It )
	{
		AActor* Actor = *It;

		UClass* ActorClass = Actor->GetClass();

		if (ActorClass->ClassGeneratedBy && ActorClass->ClassGeneratedBy->IsA( UBlueprint::StaticClass() ) )
		{
			BlueprintInstances.Add(Actor);
		}
	}

	bool bPropertiesMatch = true;
	FCompilerResultsLog ResultLog;
	TSet<UPackage*> PackagesUserRefusedToFullyLoad;
	ObjectTools::FPackageGroupName PGN;

	for (auto BpIter = BlueprintInstances.CreateIterator(); BpIter; ++BpIter )
	{
		AActor* BPInstance = *BpIter;
		UObject* BPInstanceOuter = BPInstance ? BPInstance->GetOuter() : NULL;

		TMap<FString,FString> BPNativePropertyValues;
		BPInstance->GetNativePropertyValues(BPNativePropertyValues);

		// Grab the package and save out its dirty state
		UPackage* ActorPackage = BPInstance->GetOutermost();
		FBlueprintAutomationTestUtilities::FPackageCleaner Cleaner(ActorPackage);

		// Use this when duplicating the object to keep a list of everything that was duplicated
		//TMap<UObject*, UObject*> DuplicatedObjectList;

		FObjectDuplicationParameters Parameters(BPInstance, BPInstanceOuter);
		//Parameters.CreatedObjects = &DuplicatedObjectList;
		Parameters.DestName = MakeUniqueObjectName( BPInstanceOuter, AActor::StaticClass(), BPInstance->GetFName() );

		// Duplicate the object
		AActor* ClonedInstance = Cast<AActor>(StaticDuplicateObjectEx(Parameters));

		if (!FBlueprintAutomationTestUtilities::CompareObjects(BPInstance, ClonedInstance, ResultLog))
		{
			bPropertiesMatch = false;
			break;
		}

		// Ensure we can't save package in editor
		FBlueprintAutomationTestUtilities::DontSavePackage(ActorPackage);
	}

	// Start a new map for now
	// @todo find a way return to previous map thats a 100% reliably
	GEditor->CreateNewMapForEditing();

	ADD_LATENT_AUTOMATION_COMMAND(FDelayLatentCommand(2.f));

	return bPropertiesMatch;
}