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