我想在打包好的exe中,热加载一个pak(里面包含了材质),然后使用新材质替换掉A物体的材质。
主要步骤如下:
1、从网络线程(非游戏线程)收到切换材质的消息,消息里指明pak包的绝对路径。
2、然后调用AsyncTask(ENamedThreads::GameThread, 处理函数lamda表达式)
3、然后在“处理函数lamda表达式”中,进行以下步骤:
a、将pak挂载到/Game/目录下。(挂载成功)
b、然后通过UMaterial m = (UMaterial)StaticLoadObject(UMaterial::StaticClass(), …)。 (这个步骤就会crash,报“Cannot Flush Async Loading while async loading is suspended”)
我的具体代码是:
// Fill out your copyright notice in the Description page of Project Settings.
#include “UdpControlActorImpl.h”
#include “EngineUtils.h”
#include “HAL/PlatformFilemanager.h”
#include “Runtime/Engine/Classes/Engine/StreamableManager.h”
#include “Runtime/Engine/Classes/Engine/AssetManager.h”
#include “Runtime/Engine/Classes/Engine/StaticMeshActor.h”
#include “Runtime/Engine/Classes/Engine/StaticMeshActor.h”
#include “Runtime/Engine/Classes/Materials/Material.h”
#include “Runtime/Core/Public/Templates/SharedPointer.h”
#include “IPlatformFilePak.h”
static void testLoadPak(AUdpControlActorImpl* p)
{
IPlatformFile* OldPlatform = &FPlatformFileManager::Get().GetPlatformFile();
TSharedPtr PakPlatform = MakeShareable(new FPakPlatformFile());
PakPlatform->Initialize(&FPlatformFileManager::Get().GetPlatformFile(), TEXT(“”));
FPlatformFileManager::Get().SetPlatformFile(*PakPlatform.Get());
FString PakFileFullPath = L"d:/temp/dlc_myMaterial.pak";
if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*PakFileFullPath)) {
UE_LOG(LogTemp, Warning, TEXT("%s is not exist."), *PakFileFullPath);
return;
}
TRefCountPtr<FPakFile> TmpPak = new FPakFile(PakPlatform.Get(), *PakFileFullPath, false);
FString PakMountPoint = TmpPak->GetMountPoint();
UE_LOG(LogTemp, Warning, TEXT("mountPoint in pak is %s"), *PakMountPoint);
int32 Pos = PakMountPoint.Find("Content/");
FString NewMountPoint = PakMountPoint.RightChop(Pos);
NewMountPoint = FPaths::ProjectDir() + NewMountPoint;
UE_LOG(LogTemp, Warning, TEXT("ProjectDir is %s"), *FPaths::ProjectDir());
UE_LOG(LogTemp, Warning, TEXT("NewMountPoint is %s"), *NewMountPoint);
TmpPak->SetMountPoint(*NewMountPoint);
UMaterial* GizmoMaterial = nullptr;
if (PakPlatform->Mount(*PakFileFullPath, 1, *NewMountPoint)) {
TArray<FString> FoundFilenames;
TmpPak->FindFilesAtPath(FoundFilenames, *TmpPak->GetMountPoint(), true, true, true);
if (FoundFilenames.Num() > 0) {
UE_LOG(LogTemp, Warning, TEXT("FoundFilenames.Num() is %d"), FoundFilenames.Num());
for (FString& Filename : FoundFilenames) {
UE_LOG(LogTemp, Warning, TEXT(" NewFileName111 is %s"), *Filename);
if (Filename.EndsWith(TEXT(".uasset")) && Filename.Contains(TEXT("testMyMaterial"))) {
NewFileName = TEXT("/Game/StarterContent/myMaterial/testMyMaterial.testMyMaterial");
GizmoMaterial = (UMaterial*)StaticLoadObject(UMaterial::StaticClass(), NULL, TEXT("/Game/StarterContent/myMaterial/testMyMaterial.testMyMaterial"));
}
}
}
for (TActorIterator<AStaticMeshActor> ActorItr(p->GetWorld()); ActorItr; ++ActorItr) {
AStaticMeshActor* Mesh = *ActorItr;
if (Mesh->ActorHasTag("test_chair")) {
UStaticMeshComponent* staticMeshComponent = Mesh->GetStaticMeshComponent();
if (GizmoMaterial) {
UMaterialInstanceDynamic* DynamicMaterialInst = UMaterialInstanceDynamic::Create(
GizmoMaterial, staticMeshComponent);
staticMeshComponent->SetMaterial(0, DynamicMaterialInst);
}
}
}
}
FPlatformFileManager::Get().SetPlatformFile(*OldPlatform);
}
static void test(AUdpControlActorImpl *p)
{
AsyncTask(ENamedThreads::GameThread, = {
testLoadPak(p);
});
}
// Sets default values
AUdpControlActorImpl::AUdpControlActorImpl()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don’t need it.
PrimaryActorTick.bCanEverTick = false;
}
void AUdpControlActorImpl::BeginDestroy()
{
if (m_thread != nullptr) {
m_thread->join();
delete m_thread;
m_thread = nullptr;
}
Super::BeginDestroy();
}
// Called when the game starts or when spawned
void AUdpControlActorImpl::BeginPlay()
{
Super::BeginPlay();
if (m_thread == nullptr) {
m_thread = new std::thread(test, this);
}
}
// Called every frame
void AUdpControlActorImpl::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}