UE4SS
在运行时把对游戏引擎的访问以可编程、脚本化、以及 C++ 模组化的方式暴露出来。它依赖引擎的反射/元数据(UClass/UProperty/UFunction 等)来安全地读取/修改对象,而不是靠硬编码内存偏移,从而在引擎或游戏更新时更稳定。
查找对象
UClass
auto* cls = UObjectGlobals::StaticFindObject<UClass*>(nullptr, nullptr, L"/Script/Engine.CameraActor")各种UObject
// 单例
UObject* Engine = UObjectGlobals::FindFirstOf(L"Engine");
UObject* GameUserSettings = UObjectGlobals::FindFirstOf(L"GameUserSettings")
// 非单例
std::vector<UObject*> Actors;
UObjectGlobals::FindAllOf(L"Actor", Actors);
std::vector<UObject*> Widgets;
UObjectGlobals::FindAllOf(L"Widget", Widgets);Actor
可以使用上面的方法UObjectGlobals::FindAllOf
或者使用原生 UE 的 API 封装:
UGameplayStatics::GetAllActorsOfClass(const UObject* WorldContextObject, class UClass* ActorClass, TArray<AActor*>& OutActors)查找资产
获取AssetRegistry对象
UAssetRegistry* const Registry = Cast<UAssetRegistry>(UAssetRegistryHelpers::GetAssetRegistry().ObjectPointer);查找资产
TArray<FAssetData> result;
// 获取全部
registry->GetAllAssets(result, true);
// 按类型查找
Registry->GetAssetsByClass(FName(L"/Script/Engine.StaticMesh"), result);
// 按路径查找
FAssetData ad = registry->GetAssetByObjectPath(FName(L"/Game/Folder/AssetName.AssetName"));UE 5.1+ 的 GetAssetsByClass
截至 UE4SS 3.0.1 尚未实现 UE 5.1+ 的
GetAssetsByClass
该函数的原理是调用UE函数 /Script/AssetRegistry.AssetRegistry:GetAssetsByClass(源码定义在 /Engine/Source/Runtime/AssetRegistry/Private/AssetRegistry.h)
- UE 5.1 以前的定义如下:
bool GetAssetsByClass(FName ClassName, TArray<FAssetData>& OutAssetData, bool bSearchSubClasses = false)- UE 5.1 以后的定义如下:
bool GetAssetsByClass(FTopLevelAssetPath ClassPathName, TArray<FAssetData>& OutAssetData, bool bSearchSubClasses = false)可见 UE 5.1 将 FName 类型的参数换成了 FTopLevelAssetPath结构。
故需要手动调用如下:
TArray<FAssetData> result;
if (Version::IsAtLeast(5, 1)) {
struct GetAssetsByClass_Params
{
FTopLevelAssetPath ClassName;
TArray<FAssetData> OutAssetData;
bool bSearchSubClasses;
} params {
{ ClassNameLeft, ClassNameRight },
{},
false
};
// 检查GetAssetsByClass反射
if (!UAssetRegistry::Functions::GetAssetsByClass.IsValid()) {
return result;
}
UAssetRegistry::Functions::GetAssetsByClass(registry, params);``
result.CopyFast(params.OutAssetData);
}创建Actor
关键API:
AActor* UGameplayStatics::BeginDeferredActorSpawnFromClass(
const UObject* WorldContextObject,
class UClass* ActorClass,
const FTransform& SpawnTransform,
ESpawnActorCollisionHandlingMethod CollisionHandlingOverride,
AActor* Owner
)
AActor* UGameplayStatics::FinishSpawningActor(
AActor* Actor,
const FTransform& SpawnTransform
)UWorld封装参考:
AActor* UWorld::SpawnActor(UClass* Class, FTransform const* Transform) {
AActor* Actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(this, Class, *Transform);
if (Actor)
{
UGameplayStatics::FinishSpawningActor(Actor, *Transform);
}
return Actor;
}调用函数
UFunction法
获取UFunction
const auto ufunc = (OBJ)->GetFunctionByName(FName(L"Function Name"));
const auto ufunc = (OBJ)->GetFunctionByNameInChain(FName(L"Function Name"));GetFunctionByName:GetFunctionByNameInChain:
定义参数并调用
struct {
XXX 参数A;
XXX 参数B;
XXX ReturnValue; // 返回值固定写法,若无返回值可不写
} params { A, B, {} };
(OBJ)->ProcessEvent(ufunc, ¶ms); // 调用函数
params.ReturnValue // 获取返回值
宏法
参考RE-UE4SS/deps/first/Unreal/src/AActor.cpp
操作Property
// 获取Property:GetPropertyByName 或 GetPropertyByNameInChain
auto bUnbound_FP = PostProcessVolume->GetPropertyByName(FromCharTypePtr<TCHAR>(L"bUnbound"));
auto bUnbound_FP = PostProcessVolume->GetPropertyByNameInChain(FromCharTypePtr<TCHAR>(L"bUnbound"));
// 转换到具体类型
auto bUnbound_FBP = CastField<FBoolProperty>(bUnbound_FP);
// 操作Property
bUnbound_FBP->SetPropertyValue(PostProcessVolume, true);注入函数
暂未涉及