Unreal Engine 4 之 Slua入门(2)

如和关闭SLua的调试?
–slua_profile.start(“127.0.0.1”,8081)

1、SLua中的继承和与蓝图交互
self就是对应的c++类的lua封装,你可以使用self来调用c++的函数,访问属性等,同时self也是lua table;
调用蓝图中的方法,self:MyFunc();
蓝图调用Lua:在lua中重新写一个和蓝图中同样的方法,返回参数确保一致即可,而且可以覆盖掉蓝图中的方法;
如果想在lua中只调用蓝图中的方法使用:self.Super:MyFunc();
如果没有在lua中重写蓝图方法,那么self.Super:MyFunc()和self:MyFunc()是等价的;

2、Slua中调用UE的方法
local WBL = import(“WidgetBlueprintLibrary”)
WBL.Handled()

3、Slua中的工具
local DragOPCls = slua.loadClass("/Game/MyDragOP.MyDragOP")
function panel:OnDragDetected(Geometry,PointerEvent,Operation)
return WBL.CreateDragDropOperation(DragOPCls)
end

c++代码路径处理
path = FString::Format(TEXT(“Blueprint’{0}_C’”), { path });
最终路径
“Blueprint’/Game/MyDragOP.MyDragOP_C’”
使用方法:LoadObject or StaticLoadClass

4、工程C++调试
第一种,直接运行
第二章,Debug->Attach Process

5、源码调试
打开Epic Games,虚幻引擎->库中选择调试库下载即可

6、Slua调试
slua 支持运行时分析lua使用内存,可以查看内存分配细节,方便检查内存泄漏。
Dump UObjects
在unreal控制台输入slua.DumpUObjects,会在控制台里输出所有被lua引用的UOjbect对象,通过观察这些对象,你可以快速知道还有那些UObject被lua使用而无法回收,你需要根据情况去lua代码里置空来避免lua引用,从而被unreal回收。
在lua代码里也可以直接,调用slua.dumpUObjects函数来得到这些UObject的table返回值。
DumpMemoryDetail
如果你想详细分析lua内存的使用情况,你可以开启Memory Profile,通过在控制台输入slua.StartMemoryTrack, 开启Memory Profile,默认是关闭的。
开启Memory Profile后,可以通过slua.DumpMemoryDetail控制台命令输出,从开启后到现在所有的未被内存使用信息,slua会报告内存分配的大小和具体位置,例如:
通过这个Dump List,你可以分析那些内存尚未释放,占用多少内存,从而帮助你解决内存泄漏的问题。

7、Slua Profiler

工程参数配置
在大家完成sluaunreal的配置可以正常使用后,如果需要开启 profiler,首先需要修改目标工程的xxx.Build.cs文件(参考democpp.Build.cs,如下),和sluaunreal的工程配置文件相比,需要在依赖库和搜索路径中加入slua_profile 模块

PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

PublicDependencyModuleNames.AddRange(new string[] { “Core”, “CoreUObject”, “Engine”, “InputCore”, “Http” });

PrivateDependencyModuleNames.AddRange(new string[] { “slua_unreal”, “slua_profile”, “Slate”, “SlateCore”, “UMG”, “Http” });

PrivateIncludePathModuleNames.AddRange(new string[] { “slua_unreal” });
PublicIncludePathModuleNames.AddRange(new string[] { “slua_unreal”,“slua_profile” });

在Lua中开启slua_profiler
在完成工程参数配置后,就是需要在代码中调用slua_profilerd的start()方法来开启profiler了

start(host, port)
host: 是大家需要传递的目标IP地址, 在 demopp 中,host默认是回环地址(127.0.0.1)。因此如果在真机上调试时,profiler是无法接收到socket发送的数据的,需要更改host。
port: 是目标IP地址监听的端口信息, 在 demopp 中,监听端口默认是8081。如果更改监听端口,需要将Plugins文件夹下的"slua_unreal/Source/slua_profile/Privite/slua_remote_profile.cpp"文件中的Server端监听端口更改至start()中填入端口号
调用start()方法代码示例
– 判断是否有成功引入slua_profiler模块
if slua_profile then
– 根据实际的情况填入对应的 host 和 port
slua_profile.start(“127.0.0.1”, 8081)
end

在以上所有配置都完成后,此时编译运行大家的UE,可以在UE顶部的工具栏中选择“窗口” -> “slua Profile” 来开启profiler。

===========================================================================
UE4的根目录是以Cotent为基础的,Content所有目录下的资源前缀加入/Game/
SLua中加载方式:
1、如果是Blueprint(资源点击后打开是编辑器)使用方法如下
slua.loadClass("/Game/MyDragOP.MyDragOP")
解析:
“Blueprint’/Game/MyDragOP.MyDragOP_C’”
_C代表是Blueprint Class
MyDragOP代表是文件名字

2、资源,那么需要使用全地址,“资源类型’/Game/资源相对根路径.资源名”
slua.loadObject(“Texture2D’/Game/boy.boy’”)
“Texture2D’/Game/boy.boy’”

C/C++中加载方式:
同步加载方式1:

UTexture2D* Tex = LoadObject<UTexture2D>(NULL, TEXT("Texture2D'/Game/Textures/UI/tex_test001.tex_test001'"));
UClass* Test = LoadClass<AActor>(NULL, TEXT("Blueprint'/Game/Blueprints/MyGameMode.MyGameMode_C'")); 

同步加载方式2:

UTexture2D* Tex = LoadObject<UTexture2D>(NULL, TEXT("/Game/Textures/UI/tex_test001.tex_test001"));
UClass* pClass = LoadClass<AActor>(NULL, TEXT("/Game/Blueprints/MyGameMode.MyGameMode_C"));

同步加载方式3:

FStreamableManager streamableManager;
UStaticMesh* pStaticMesh = streamableManager.LoadSynchronous<UStaticMesh>(FSoftObjectPath("/Game/Geometry/Meshes/1M_Cube.1M_Cube"));
UClass* pClass = streamableManager.LoadSynchronous<UClass>(FSoftObjectPath("/Game/ThirdPersonCPP/Blueprints/TestActor.TestActor_C"));

eg

AssetLoader = new FStreamableManager();
UObject* obj = AssetLoader->LoadSynchronous(FStringAssetReference(TEXT("/Game/AsyncLoad/NewDataAsset.NewDataAsset")));
ItemDatabase = Cast<UItemInfoDatabase>(obj);

异步加载:


void ATestLoadObjectCharacter::BeginPlay()
{
	Super::BeginPlay();
 
	FStreamableManager streamableManager;
	FString strMeshFileName = "/Game/Geometry/Meshes/1M_Cube.1M_Cube";
	FStreamableDelegate streamableDelegate;
	FSoftObjectPath strMeshObjectFileName = FSoftObjectPath(strMeshFileName);
	streamableDelegate.BindUObject(this, &ThisClass::LoadFinish, strMeshObjectFileName);
	streamableManager.RequestAsyncLoad(strMeshObjectFileName, streamableDelegate);
}
void ATestLoadObjectCharacter::LoadFinish(FSoftObjectPath meshFilePath)
{
	FSoftObjectPtr meshObjectPtr = FSoftObjectPtr(meshFilePath);
	UObject* pObject = meshObjectPtr.Get();
	if (nullptr == pObject)
		return;
 
	UStaticMesh* pStaticMesh = Cast<UStaticMesh>(pObject);
	if (pStaticMesh)
	{
		UE_LOG(LogTemp, Error, TEXT("UStaicMesh name is %s"), *pStaticMesh->GetName());
	}
 
}

void AMyProject7Character::BeginPlay()
{
	Super::BeginPlay();
	FStreamableManager streamableManager;
	FString strBPClassPath = "/Game/testActor.testActor_C";
	FStreamableDelegate streamableDelegate;
	FSoftClassPath SoftBPClassPathName = FSoftClassPath(strBPClassPath);
	streamableDelegate.BindUObject(this, &ThisClass::LoadFinish, SoftBPClassPathName);
	streamableManager.RequestAsyncLoad(SoftBPClassPathName, streamableDelegate);
}
void AMyProject7Character::LoadFinish(FSoftClassPath SoftBPClassPathName)
{
		
		TSoftClassPtr<AActor> ActorClassPtr = TSoftClassPtr<AActor>(SoftBPClassPathName);
		UClass* pClass = ActorClassPtr.Get();
		if (pClass)
		{
			UE_LOG(LogTemp, Error, TEXT("UStaicMesh name is %s"), *pClass->GetName());
		}
}

自动回收
用上面的方式加载资源以后,如果对象失去引用,就会被自动释放,如果是异步加载,对象只在回调函数中有效,回调函数执行完毕就会被标记为可回收。那么如何保存异步加载的资源呢?
在项目里看到并没有回调中保存加载的对象,而是保存了异步资源加载的Handle,通过Handle来获得的GetLoadedAssets来获得加载的对象。在保存到对象池之后再释放Handle。

手动回收
在加载资源的时候如果讲bManageActiveHandle设置为true,对象会一直常驻内存直到手动释放。

FStreamableManager& AssetLoader = UAssetManager::GetStreamableManager();
UParticleSystem* AimObj = AssetLoader.LoadSynchronous(FSoftObjectPath(AssetPath), true);
如果对象不需要,手动执行unload

FStreamableManager& AssetLoader = UAssetManager::GetStreamableManager();
AssetLoader.Unload(FSoftObjectPath(AssetPath));
在编辑器模式里,上述两种方式都无法生效,只有打包版本才可以。如果在编辑器模式下强制Destroy或者MarkPendingKill(),可以把对象从内存销毁,但是也无法再次Load,除非重启编辑器,(等待验证)

注意
FStreamableManager::Unload()会Release掉和当前资源相关的所有FStreamableHandle。比如在三处位置加载了同一个资源,即使bManageActiveHandle设置为true,那么只要调用Unload一次,就可以将这三个FStreamableHandle对象全部Release掉,即从内存中释放该对象;如果对这3个FStreamableHandle对象分别执行Release,那么只有当最后一个Handle被Release之后,该资源才会从内存中释放。
异步加载时,谁先请求则谁的回调函数先执行,不会存在回调函数执行顺序乱序的问题(除非修改TAsyncLoadPriority),因为引擎内部接收回调请求的容器使用的是TArray,且每次执行索引为0的回调,然后RemoveAt(0)。
异步加载时,如果资源还没加载完成就执行ReleaseHandle()(假设加载时bManageActiveHandle为true),比如在执行回调函数之前执行ReleaseHandle,那么当资源加载完成后(回调函数执行之后),会自动从内存中回收。不过该对象在回调函数中仍然有效,除非在回调函数内ForceGC。
UPROPERTY()修饰的成员变量,可以让其保持的资源对象常驻内存,如果不再需要驻留内存,将该成员变量值为NULL,等到下次GC时就会被自动回收
GEngine->ForceGarbageCollection();执行后,内存回收至少要等到下一帧才会执行。在当前帧内,即使一个对象执行ConditionalBeginDestroy()且执行了ForceGarbageCollection,当前帧内该对象仍然有效。
ConditionalBeginDestroy()是所有UObject都有的API,其对象销毁是异步执行且对象在当前帧内持续有效;AActor::Destroy()是AActor特有的API,其对象回收发生在当前帧结束时。

Reference:
https://www.w3xue.com/exp/article/201912/70569.html
https://github.com/Tencent/sluaunreal

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值