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