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) |