176 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "UnrealSharpCompiler.h"
 | |
| 
 | |
| #include "BlueprintActionDatabase.h"
 | |
| #include "BlueprintCompilationManager.h"
 | |
| #include "CSBlueprintCompiler.h"
 | |
| #include "CSCompilerContext.h"
 | |
| #include "CSManager.h"
 | |
| #include "KismetCompiler.h"
 | |
| #include "TypeGenerator/CSBlueprint.h"
 | |
| #include "TypeGenerator/CSClass.h"
 | |
| #include "TypeGenerator/CSEnum.h"
 | |
| #include "TypeGenerator/CSInterface.h"
 | |
| #include "TypeGenerator/CSScriptStruct.h"
 | |
| 
 | |
| #define LOCTEXT_NAMESPACE "FUnrealSharpCompilerModule"
 | |
| 
 | |
| DEFINE_LOG_CATEGORY(LogUnrealSharpCompiler);
 | |
| 
 | |
| void FUnrealSharpCompilerModule::StartupModule()
 | |
| {
 | |
| 	UCSManager& CSManager = UCSManager::GetOrCreate();
 | |
| 	
 | |
| 	FKismetCompilerContext::RegisterCompilerForBP(UCSBlueprint::StaticClass(), [](UBlueprint* InBlueprint, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions)
 | |
| 	{
 | |
| 		return MakeShared<FCSCompilerContext>(CastChecked<UCSBlueprint>(InBlueprint), InMessageLog, InCompileOptions);
 | |
| 	});
 | |
| 	
 | |
| 	IKismetCompilerInterface& KismetCompilerModule = FModuleManager::LoadModuleChecked<IKismetCompilerInterface>("KismetCompiler");
 | |
| 	KismetCompilerModule.GetCompilers().Add(&BlueprintCompiler);
 | |
| 	
 | |
| 	CSManager.OnNewClassEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewClass);
 | |
| 	CSManager.OnNewEnumEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewEnum);
 | |
| 	CSManager.OnNewStructEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewStruct);
 | |
| 	CSManager.OnNewInterfaceEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewInterface);
 | |
| 	
 | |
| 	CSManager.OnProcessedPendingClassesEvent().AddRaw(this, &FUnrealSharpCompilerModule::RecompileAndReinstanceBlueprints);
 | |
| 	CSManager.OnManagedAssemblyLoadedEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnManagedAssemblyLoaded);
 | |
| 
 | |
| 	// Try to recompile and reinstance all blueprints when the module is loaded.
 | |
| 	CSManager.ForEachManagedPackage([this](const UPackage* Package)
 | |
| 	{
 | |
| 		ForEachObjectWithPackage(Package, [this](UObject* Object)
 | |
| 		{
 | |
| 			if (UBlueprint* Blueprint = Cast<UBlueprint>(Object))
 | |
| 			{
 | |
| 				OnNewClass(static_cast<UCSClass*>(Blueprint->GeneratedClass.Get()));
 | |
| 			}
 | |
| 			return true;
 | |
| 		}, false);
 | |
| 	});
 | |
| 	
 | |
| 	RecompileAndReinstanceBlueprints();
 | |
| }
 | |
| 
 | |
| void FUnrealSharpCompilerModule::ShutdownModule()
 | |
| {
 | |
|     
 | |
| }
 | |
| 
 | |
| void FUnrealSharpCompilerModule::RecompileAndReinstanceBlueprints()
 | |
| {
 | |
| 	if (UCSManager::Get().IsLoadingAnyAssembly())
 | |
| 	{
 | |
| 		// Wait until all assemblies are loaded, so we can recompile all blueprints at once.
 | |
| 		return;
 | |
| 	}
 | |
| 	
 | |
| 	if (ManagedComponentsToCompile.IsEmpty() && ManagedClassesToCompile.IsEmpty())
 | |
| 	{
 | |
| 		// Nothing to compile.
 | |
| 		return;
 | |
| 	}
 | |
| 	
 | |
| 	auto CompileBlueprints = [this](TArray<UBlueprint*>& Blueprints)
 | |
| 	{
 | |
| 		if (Blueprints.IsEmpty())
 | |
| 		{
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		for (int32 i = 0; i < Blueprints.Num(); ++i)
 | |
| 		{
 | |
| 			UBlueprint* Blueprint = Blueprints[i];
 | |
| 
 | |
| 			if (!Blueprint)
 | |
| 			{
 | |
| 				UE_LOGFMT(LogUnrealSharpCompiler, Error, "Blueprint is null, skipping compilation.");
 | |
| 				continue;
 | |
| 			}
 | |
| 			
 | |
| 			if (!IsValid(Blueprint))
 | |
| 			{
 | |
| 				UE_LOGFMT(LogUnrealSharpCompiler, Error, "Blueprint {0} is garbage, skipping compilation.", *Blueprint->GetName());
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			FKismetEditorUtilities::CompileBlueprint(Blueprint, EBlueprintCompileOptions::SkipGarbageCollection);
 | |
| 		}
 | |
| 		
 | |
| 		Blueprints.Reset();
 | |
| 	};
 | |
| 
 | |
| 	// Components needs be compiled first, as they are instantiated by the owning actor, and needs their size to be known.
 | |
| 	CompileBlueprints(ManagedComponentsToCompile);
 | |
| 	CompileBlueprints(ManagedClassesToCompile);
 | |
| 
 | |
| 	CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS, true);
 | |
| }
 | |
| 
 | |
| void FUnrealSharpCompilerModule::AddManagedReferences(FCSManagedReferencesCollection& Collection)
 | |
| {
 | |
| 	Collection.ForEachManagedReference([&](UStruct* Struct)
 | |
| 	{
 | |
| 		if (UCSClass* Class = Cast<UCSClass>(Struct))
 | |
| 		{
 | |
| 			OnNewClass(Class);
 | |
| 		}
 | |
| 	});
 | |
| }
 | |
| 
 | |
| void FUnrealSharpCompilerModule::OnNewClass(UCSClass* NewClass)
 | |
| {
 | |
| 	UBlueprint* Blueprint = Cast<UBlueprint>(NewClass->ClassGeneratedBy);
 | |
| 	if (!IsValid(Blueprint))
 | |
| 	{
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	auto AddToCompileList = [this](TArray<UBlueprint*>& List, UBlueprint* Blueprint)
 | |
| 	{
 | |
| 		if (List.Contains(Blueprint))
 | |
| 		{
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		List.Add(Blueprint);
 | |
| 	};
 | |
| 		
 | |
| 	if (NewClass->IsChildOf(UActorComponent::StaticClass()))
 | |
| 	{
 | |
| 		AddToCompileList(ManagedComponentsToCompile, Blueprint);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		AddToCompileList(ManagedClassesToCompile, Blueprint);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void FUnrealSharpCompilerModule::OnNewStruct(UCSScriptStruct* NewStruct)
 | |
| {
 | |
| 	AddManagedReferences(NewStruct->ManagedReferences);
 | |
| }
 | |
| 
 | |
| void FUnrealSharpCompilerModule::OnNewEnum(UCSEnum* NewEnum)
 | |
| {
 | |
| 	AddManagedReferences(NewEnum->ManagedReferences);
 | |
| }
 | |
| 
 | |
| void FUnrealSharpCompilerModule::OnNewInterface(UCSInterface* NewInterface)
 | |
| {
 | |
| 	if (!IsValid(GEditor))
 | |
| 	{
 | |
| 		return;
 | |
| 	}
 | |
| 	
 | |
| 	FBlueprintActionDatabase::Get().RefreshClassActions(NewInterface);
 | |
| }
 | |
| 
 | |
| void FUnrealSharpCompilerModule::OnManagedAssemblyLoaded(const FName& AssemblyName)
 | |
| {
 | |
| 	RecompileAndReinstanceBlueprints();
 | |
| }
 | |
| 
 | |
| #undef LOCTEXT_NAMESPACE
 | |
|     
 | |
| IMPLEMENT_MODULE(FUnrealSharpCompilerModule, UnrealSharpCompiler) |