Lua向C#逻辑迁移 一期 #13

将整个插件代码上传
This commit is contained in:
2025-10-26 21:48:39 +08:00
parent 56994b3927
commit 648386cd73
785 changed files with 53683 additions and 2 deletions

View File

@ -0,0 +1,27 @@
#include "CSGlueGenerator.h"
#include "UnrealSharpRuntimeGlue.h"
#include "Logging/StructuredLog.h"
#include "UnrealSharpProcHelper/CSProcHelper.h"
void UCSGlueGenerator::SaveRuntimeGlue(const FCSScriptBuilder& ScriptBuilder, const FString& FileName, const FString& Suffix)
{
const FString Path = FPaths::Combine(FCSProcHelper::GetProjectGlueFolderPath(), FileName + Suffix);
FString CurrentRuntimeGlue;
FFileHelper::LoadFileToString(CurrentRuntimeGlue, *Path);
if (CurrentRuntimeGlue == ScriptBuilder.ToString())
{
// No changes, return
return;
}
if (!FFileHelper::SaveStringToFile(ScriptBuilder.ToString(), *Path))
{
UE_LOGFMT(LogUnrealSharpRuntimeGlue, Error, "Failed to save runtime glue to {0}", *Path);
return;
}
UE_LOGFMT(LogUnrealSharpRuntimeGlue, Display, "Saved {0}", *FileName);
FUnrealSharpRuntimeGlueModule::Get().GetOnRuntimeGlueChanged().Broadcast(this, Path);
}

View File

@ -0,0 +1,13 @@
#include "CSRuntimeGlueSettings.h"
#include "DefaultGenerators/CSAssetManagerGlueGenerator.h"
#include "DefaultGenerators/CSGameplayTagsGlueGenerator.h"
#include "DefaultGenerators/CSTraceTypeQueryGlueGenerator.h"
UCSRuntimeGlueSettings::UCSRuntimeGlueSettings()
{
CategoryName = "Plugins";
Generators.Add(UCSAssetManagerGlueGenerator::StaticClass());
Generators.Add(UCSTraceTypeQueryGlueGenerator::StaticClass());
Generators.Add(UCSGameplayTagsGlueGenerator::StaticClass());
}

View File

@ -0,0 +1,194 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "DefaultGenerators/CSAssetManagerGlueGenerator.h"
#include "Engine/AssetManager.h"
#include "Engine/AssetManagerSettings.h"
void UCSAssetManagerGlueGenerator::Initialize()
{
if (UAssetManager::IsInitialized())
{
TryRegisterAssetTypes();
}
else
{
FModuleManager::Get().OnModulesChanged().AddUObject(this, &UCSAssetManagerGlueGenerator::OnModulesChanged);
}
}
void UCSAssetManagerGlueGenerator::TryRegisterAssetTypes()
{
if (bHasRegisteredAssetTypes || !UAssetManager::IsInitialized())
{
return;
}
UAssetManager::Get().CallOrRegister_OnCompletedInitialScan(
FSimpleMulticastDelegate::FDelegate::CreateUObject(this, &ThisClass::OnCompletedInitialScan));
bHasRegisteredAssetTypes = true;
}
void UCSAssetManagerGlueGenerator::OnModulesChanged(FName InModuleName, EModuleChangeReason InModuleChangeReason)
{
if (InModuleChangeReason != EModuleChangeReason::ModuleLoaded)
{
return;
}
TryRegisterAssetTypes();
}
void UCSAssetManagerGlueGenerator::OnCompletedInitialScan()
{
IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
AssetRegistry.OnAssetRemoved().AddUObject(this, &ThisClass::OnAssetRemoved);
AssetRegistry.OnAssetRenamed().AddUObject(this, &ThisClass::OnAssetRenamed);
AssetRegistry.OnInMemoryAssetCreated().AddUObject(this, &ThisClass::OnInMemoryAssetCreated);
AssetRegistry.OnInMemoryAssetDeleted().AddUObject(this, &ThisClass::OnInMemoryAssetDeleted);
UAssetManager::Get().Register_OnAddedAssetSearchRoot(
FOnAddedAssetSearchRoot::FDelegate::CreateUObject(this, &ThisClass::OnAssetSearchRootAdded));
UAssetManagerSettings* Settings = UAssetManagerSettings::StaticClass()->GetDefaultObject<UAssetManagerSettings>();
Settings->OnSettingChanged().AddUObject(this, &ThisClass::OnAssetManagerSettingsChanged);
ProcessAssetIds();
}
void UCSAssetManagerGlueGenerator::OnAssetRemoved(const FAssetData& AssetData)
{
if (!IsRegisteredAssetType(AssetData))
{
return;
}
WaitUpdateAssetTypes();
}
void UCSAssetManagerGlueGenerator::OnAssetRenamed(const FAssetData& AssetData, const FString& OldObjectPath)
{
OnAssetRemoved(AssetData);
}
void UCSAssetManagerGlueGenerator::OnInMemoryAssetCreated(UObject* Object)
{
if (!IsRegisteredAssetType(Object))
{
return;
}
WaitUpdateAssetTypes();
}
void UCSAssetManagerGlueGenerator::OnInMemoryAssetDeleted(UObject* Object)
{
OnInMemoryAssetCreated(Object);
}
void UCSAssetManagerGlueGenerator::OnAssetSearchRootAdded(const FString& RootPath)
{
WaitUpdateAssetTypes();
}
void UCSAssetManagerGlueGenerator::OnAssetManagerSettingsChanged(UObject* Object,
FPropertyChangedEvent& PropertyChangedEvent)
{
WaitUpdateAssetTypes();
GEditor->GetTimerManager()->SetTimerForNextTick(
FTimerDelegate::CreateUObject(this, &ThisClass::ProcessAssetTypes));
}
bool UCSAssetManagerGlueGenerator::IsRegisteredAssetType(UClass* Class)
{
if (!IsValid(Class))
{
return false;
}
UAssetManager& AssetManager = UAssetManager::Get();
const UAssetManagerSettings& Settings = AssetManager.GetSettings();
bool bIsPrimaryAsset = false;
for (const FPrimaryAssetTypeInfo& PrimaryAssetType : Settings.PrimaryAssetTypesToScan)
{
if (Class->IsChildOf(PrimaryAssetType.GetAssetBaseClass().Get()))
{
bIsPrimaryAsset = true;
break;
}
}
return bIsPrimaryAsset;
}
FString ReplaceSpecialCharacters(const FString& Input)
{
FString ModifiedString = Input;
FRegexPattern Pattern(TEXT("[^a-zA-Z0-9_]"));
FRegexMatcher Matcher(Pattern, ModifiedString);
while (Matcher.FindNext())
{
int32 MatchStart = Matcher.GetMatchBeginning();
int32 MatchEnd = Matcher.GetMatchEnding();
ModifiedString = ModifiedString.Mid(0, MatchStart) + TEXT("_") + ModifiedString.Mid(MatchEnd);
Matcher = FRegexMatcher(Pattern, ModifiedString);
}
return ModifiedString;
}
void UCSAssetManagerGlueGenerator::ProcessAssetIds()
{
UAssetManager& AssetManager = UAssetManager::Get();
const UAssetManagerSettings& Settings = AssetManager.GetSettings();
FCSScriptBuilder ScriptBuilder(FCSScriptBuilder::IndentType::Tabs);
ScriptBuilder.AppendLine();
ScriptBuilder.AppendLine(TEXT("using UnrealSharp.CoreUObject;"));
ScriptBuilder.AppendLine();
ScriptBuilder.AppendLine(TEXT("public static class AssetIds"));
ScriptBuilder.OpenBrace();
for (const FPrimaryAssetTypeInfo& PrimaryAssetType : Settings.PrimaryAssetTypesToScan)
{
TArray<FPrimaryAssetId> PrimaryAssetIdList;
AssetManager.GetPrimaryAssetIdList(PrimaryAssetType.PrimaryAssetType, PrimaryAssetIdList);
for (const FPrimaryAssetId& AssetType : PrimaryAssetIdList)
{
FString AssetName = PrimaryAssetType.PrimaryAssetType.ToString() + TEXT(".") + AssetType.PrimaryAssetName.
ToString();
AssetName = ReplaceSpecialCharacters(AssetName);
ScriptBuilder.AppendLine(FString::Printf(
TEXT("public static readonly FPrimaryAssetId %s = new(\"%s\", \"%s\");"),
*AssetName, *AssetType.PrimaryAssetType.GetName().ToString(), *AssetType.PrimaryAssetName.ToString()));
}
}
ScriptBuilder.CloseBrace();
SaveRuntimeGlue(ScriptBuilder, TEXT("AssetIds"));
}
void UCSAssetManagerGlueGenerator::ProcessAssetTypes()
{
UAssetManager& AssetManager = UAssetManager::Get();
const UAssetManagerSettings& Settings = AssetManager.GetSettings();
FCSScriptBuilder ScriptBuilder(FCSScriptBuilder::IndentType::Tabs);
ScriptBuilder.AppendLine();
ScriptBuilder.AppendLine(TEXT("using UnrealSharp.CoreUObject;"));
ScriptBuilder.AppendLine();
ScriptBuilder.AppendLine(TEXT("public static class AssetTypes"));
ScriptBuilder.OpenBrace();
for (const FPrimaryAssetTypeInfo& PrimaryAssetType : Settings.PrimaryAssetTypesToScan)
{
FString AssetTypeName = ReplaceSpecialCharacters(PrimaryAssetType.PrimaryAssetType.ToString());
ScriptBuilder.AppendLine(FString::Printf(TEXT("public static readonly FPrimaryAssetType %s = new(\"%s\");"),
*AssetTypeName, *PrimaryAssetType.PrimaryAssetType.ToString()));
}
ScriptBuilder.CloseBrace();
SaveRuntimeGlue(ScriptBuilder, TEXT("AssetTypes"));
}

View File

@ -0,0 +1,71 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "DefaultGenerators/CSGameplayTagsGlueGenerator.h"
#include "CSScriptBuilder.h"
#include "GameplayTagsModule.h"
#include "GameplayTagsSettings.h"
void UCSGameplayTagsGlueGenerator::Initialize()
{
IGameplayTagsModule::OnTagSettingsChanged.AddUObject(this, &UCSGameplayTagsGlueGenerator::ProcessGameplayTags);
IGameplayTagsModule::OnGameplayTagTreeChanged.AddUObject(this, &UCSGameplayTagsGlueGenerator::ProcessGameplayTags);
ProcessGameplayTags();
}
void UCSGameplayTagsGlueGenerator::ProcessGameplayTags()
{
TArray<const FGameplayTagSource*> Sources;
UGameplayTagsManager& GameplayTagsManager = UGameplayTagsManager::Get();
const int32 NumValues = StaticEnum<EGameplayTagSourceType>()->NumEnums();
for (int32 Index = 0; Index < NumValues; Index++)
{
EGameplayTagSourceType SourceType = static_cast<EGameplayTagSourceType>(Index);
GameplayTagsManager.FindTagSourcesWithType(SourceType, Sources);
}
FCSScriptBuilder ScriptBuilder(FCSScriptBuilder::IndentType::Tabs);
ScriptBuilder.AppendLine(TEXT("using UnrealSharp.GameplayTags;"));
ScriptBuilder.AppendLine();
ScriptBuilder.AppendLine(TEXT("public static class GameplayTags"));
ScriptBuilder.OpenBrace();
TArray<FName> TagNames;
auto GenerateGameplayTag = [&ScriptBuilder, &TagNames](const FGameplayTagTableRow& RowTag)
{
if (TagNames.Contains(RowTag.Tag))
{
return;
}
const FString TagName = RowTag.Tag.ToString();
const FString TagNameVariable = TagName.Replace(TEXT("."), TEXT("_"));
ScriptBuilder.AppendLine(
FString::Printf(TEXT("public static readonly FGameplayTag %s = new(\"%s\");"), *TagNameVariable, *TagName));
TagNames.Add(RowTag.Tag);
};
for (const FGameplayTagSource* Source : Sources)
{
if (Source->SourceTagList)
{
for (const FGameplayTagTableRow& RowTag : Source->SourceTagList->GameplayTagList)
{
GenerateGameplayTag(RowTag);
}
}
if (Source->SourceRestrictedTagList)
{
for (const FGameplayTagTableRow& RowTag : Source->SourceRestrictedTagList->RestrictedGameplayTagList)
{
GenerateGameplayTag(RowTag);
}
}
}
ScriptBuilder.CloseBrace();
SaveRuntimeGlue(ScriptBuilder, TEXT("GameplayTags"));
}

View File

@ -0,0 +1,105 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "DefaultGenerators/CSTraceTypeQueryGlueGenerator.h"
void UCSTraceTypeQueryGlueGenerator::Initialize()
{
UCollisionProfile* CollisionProfile = UCollisionProfile::Get();
CollisionProfile->LoadProfileConfig(true);
CollisionProfile->OnLoadProfileConfig.AddUObject(this, &ThisClass::OnCollisionProfileChanged);
ProcessTraceTypeQuery();
}
void UCSTraceTypeQueryGlueGenerator::OnCollisionProfileChanged(UCollisionProfile* CollisionProfile)
{
GEditor->GetTimerManager()->SetTimerForNextTick(FTimerDelegate::CreateUObject(this, &ThisClass::ProcessTraceTypeQuery));
}
void UCSTraceTypeQueryGlueGenerator::ProcessTraceTypeQuery()
{
// Initialize CollisionProfile in-case it's not loaded yet
UCollisionProfile::Get();
FCSScriptBuilder ScriptBuilder(FCSScriptBuilder::IndentType::Tabs);
ScriptBuilder.AppendLine();
ScriptBuilder.AppendLine(TEXT("using UnrealSharp.Engine;"));
ScriptBuilder.AppendLine();
ScriptBuilder.AppendLine(TEXT("public enum ETraceChannel"));
ScriptBuilder.OpenBrace();
// Hardcoded values for Visibility and Camera. See CollisionProfile.cpp:356
{
ScriptBuilder.AppendLine(TEXT("Visibility = 0,"));
ScriptBuilder.AppendLine(TEXT("Camera = 1,"));
}
UEnum* TraceTypeQueryEnum = StaticEnum<ETraceTypeQuery>();
constexpr int32 NumChannels = TraceTypeQuery_MAX;
constexpr int32 StartIndex = 2;
for (int i = StartIndex; i < NumChannels; i++)
{
if (TraceTypeQueryEnum->HasMetaData(TEXT("Hidden"), i) || i == NumChannels - 1)
{
continue;
}
FString ChannelName = TraceTypeQueryEnum->GetMetaData(TEXT("ScriptName"), i);
ChannelName.RemoveFromStart(TEXT("ECC_"));
if (ChannelName.Len() > 0 && FChar::IsDigit(ChannelName[0]))
{
ChannelName = TEXT("_") + ChannelName;
}
ScriptBuilder.AppendLine(FString::Printf(TEXT("%s = %d,"), *ChannelName, i));
}
ScriptBuilder.CloseBrace();
ScriptBuilder.AppendLine();
ScriptBuilder.AppendLine(TEXT("public static class TraceChannelStatics"));
ScriptBuilder.OpenBrace();
ScriptBuilder.AppendLine(TEXT("public static ETraceTypeQuery ToQuery(this ETraceChannel traceTypeQueryHelper)"));
ScriptBuilder.OpenBrace();
ScriptBuilder.AppendLine(TEXT("return (ETraceTypeQuery)traceTypeQueryHelper;"));
ScriptBuilder.CloseBrace();
ScriptBuilder.CloseBrace();
UEnum* ObjectTypeEnum = StaticEnum<EObjectTypeQuery>();
ScriptBuilder.AppendLine();
ScriptBuilder.AppendLine(TEXT("public enum ECollisionChannel"));
ScriptBuilder.OpenBrace();
for (int32 i = 0; i < ObjectTypeQuery_MAX; i++)
{
FString ObjectTypeName = ObjectTypeEnum->GetMetaData(TEXT("ScriptName"), i);
if (ObjectTypeName.IsEmpty())
{
continue;
}
ObjectTypeName.RemoveFromStart(TEXT("ECC_"));
ScriptBuilder.AppendLine(FString::Printf(TEXT("%s = %d,"), *ObjectTypeName, i));
}
ScriptBuilder.CloseBrace();
ScriptBuilder.AppendLine();
ScriptBuilder.AppendLine(TEXT("public static class CollisionChannelStatics"));
ScriptBuilder.OpenBrace();
ScriptBuilder.AppendLine(TEXT("public static EObjectTypeQuery ToObjectTypeQuery(this ECollisionChannel traceTypeQueryHelper)"));
ScriptBuilder.OpenBrace();
ScriptBuilder.AppendLine(TEXT("return (EObjectTypeQuery)traceTypeQueryHelper;"));
ScriptBuilder.CloseBrace();
ScriptBuilder.CloseBrace();
SaveRuntimeGlue(ScriptBuilder, TEXT("TraceChannel"));
}

View File

@ -0,0 +1,73 @@
#include "UnrealSharpRuntimeGlue.h"
#include "CSGlueGenerator.h"
#include "CSRuntimeGlueSettings.h"
#include "Logging/StructuredLog.h"
#define LOCTEXT_NAMESPACE "FUnrealSharpRuntimeGlueModule"
DEFINE_LOG_CATEGORY(LogUnrealSharpRuntimeGlue);
void FUnrealSharpRuntimeGlueModule::StartupModule()
{
FModuleManager::Get().OnModulesChanged().AddRaw(this, &FUnrealSharpRuntimeGlueModule::OnModulesChanged);
InitializeRuntimeGlueGenerators();
}
void FUnrealSharpRuntimeGlueModule::ShutdownModule()
{
}
void FUnrealSharpRuntimeGlueModule::ForceRefreshRuntimeGlue()
{
for (const TPair<TObjectKey<UClass>, UCSGlueGenerator*>& Pair : RuntimeGlueGenerators)
{
if (!IsValid(Pair.Value))
{
UObject* Object = Pair.Value;
UE_LOGFMT(LogUnrealSharpRuntimeGlue, Warning, "Runtime glue generator {0} is not valid. Skipping refresh", *Object->GetName());
continue;
}
Pair.Value->ForceRefresh();
}
}
void FUnrealSharpRuntimeGlueModule::InitializeRuntimeGlueGenerators()
{
const UCSRuntimeGlueSettings* Settings = GetDefault<UCSRuntimeGlueSettings>();
for (const TSoftClassPtr<UCSGlueGenerator>& Generator : Settings->Generators)
{
if (Generator.IsNull())
{
UE_LOGFMT(LogUnrealSharpRuntimeGlue, Log, "{0} is null. Can't create generator", *Generator.ToString());
continue;
}
UClass* GeneratorClass = Generator.Get();
if (!GeneratorClass || RuntimeGlueGenerators.Contains(GeneratorClass))
{
continue;
}
UCSGlueGenerator* GeneratorInstance = NewObject<UCSGlueGenerator>(GetTransientPackage(), GeneratorClass, NAME_None, RF_Standalone);
RuntimeGlueGenerators.Add(GeneratorClass, GeneratorInstance);
GeneratorInstance->Initialize();
}
}
void FUnrealSharpRuntimeGlueModule::OnModulesChanged(FName ModuleName, EModuleChangeReason Reason)
{
if (Reason != EModuleChangeReason::ModuleLoaded)
{
return;
}
InitializeRuntimeGlueGenerators();
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FUnrealSharpRuntimeGlueModule, UnrealSharpRuntimeGlue)