問題:editor 下如何調(diào)試 pak 的 mount 流程钻洒?
- mount pak
一般只要如下調(diào)用就可以:
FPakPlatformFile* PakPlatform = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(FPakPlatformFile::GetTypeName()));
if (PakPlatform)
{
PakPlatform->Mount(*pakPath, PakOrder)
}
- 但有兩種情況下,PakPlatform 會為 Null
1逸尖,當打包時(package)時沒有選 -pak 并且項目的 content 目錄下沒有 pak 文件
2属拾,editor 模式下 - 解決方法
第一種情況好解決,打包時加上 -pak 參數(shù)就行(我在這被坑了很久)冷溶;第二種情況就麻煩點渐白,需要手動將 PakPlatform 插入責任鏈條中,大概的代碼如下:
FPakPlatformFile* HotPatchServer::CheckAndInitPakPlatform()
{
FPakPlatformFile* HandlePakPlatform = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(FPakPlatformFile::GetTypeName()));
if (!HandlePakPlatform)
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform FPakPlatformFile == NULL"));
// 方便 Editor 調(diào)試 mount 流程
#if WITH_EDITOR
if (EnabledEditorHotPatch)
{
IPlatformFileModule* PlatformFileModule = FModuleManager::LoadModulePtr<IPlatformFileModule>(FPakPlatformFile::GetTypeName());
if (PlatformFileModule != NULL)
{
HandlePakPlatform = (FPakPlatformFile*)(PlatformFileModule->GetPlatformFile());
IPlatformFile& TopmostPlatformFile = FPlatformFileManager::Get().GetPlatformFile();
const TCHAR* Name = TEXT("");
for (IPlatformFile* ChainElement = &TopmostPlatformFile; ChainElement; ChainElement = ChainElement->GetLowerLevel())
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform 尋找合適插入位置 Name = %s"), ChainElement->GetName());
if (ChainElement->GetLowerLevel() == NULL)
{
HandlePakPlatform->Initialize(ChainElement, TEXT(""));
HandlePakPlatform->InitializeAfterSetActive();
Name = ChainElement->GetName();
break;
}
}
for (IPlatformFile* ChainElement = &TopmostPlatformFile; ChainElement; ChainElement = ChainElement->GetLowerLevel())
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform 尋找被插隊的節(jié)點 Name = %s"), ChainElement->GetName());
if (ChainElement->GetLowerLevel() != NULL && FCString::Stricmp(ChainElement->GetLowerLevel()->GetName(), Name) == 0 && FCString::Stricmp(FPakPlatformFile::GetTypeName(), Name) != 0)
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform 尋找到了需要插入的節(jié)點 Name = %s OldGetLowerLevel = %s NewLowerLevel = %s"), ChainElement->GetName(), ChainElement->GetName(), HandlePakPlatform->GetName());
ChainElement->SetLowerLevel(HandlePakPlatform);
break;
}
}
if (TopmostPlatformFile.GetLowerLevel() == NULL)
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform 沒尋找到被插隊的節(jié)點 HandlePakPlatform 被放在最上層逞频!"));
FPlatformFileManager::Get().SetPlatformFile(*HandlePakPlatform);
}
}
}
#endif
}
else
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform FPakPlatformFile is OK"));
}
return HandlePakPlatform;
}
問題:editor 掛載(mount)加密后的 pak 報錯?
-
pak 為何要加密纯衍?
一般正式上線時,為了資源不被輕松破解苗胀,一般都會選擇將 pak 加密襟诸。
-
如何加密?
如下圖所示:
-
那為啥在打出的包能正常解密基协,而在 editor 下卻會失敗呢歌亲?
一開始我也很疑惑,經(jīng)過多次查找下來澜驮,在 Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs 中發(fā)現(xiàn)了如下代碼:
具體模版內(nèi)容為:
以上可以總結(jié)為:在打包時(編譯項目時)陷揪,會根據(jù)項目的設(shè)置,自動生成對應(yīng)的解密代碼杂穷。
-
editor 下如何解密悍缠?
其實也比較簡單,就像上面的代碼一樣耐量,加一個解密的 callback 就可以了飞蚓,具體的代碼如下:
bool bEncryptPakIndex;
bool bEncryptPakIniFiles;
bool bEncryptUAssetFiles;
bool bEncryptAllAssetFiles;
FString GSetting = FString::Printf(TEXT("%sDefaultCrypto.ini"), *FPaths::SourceConfigDir());
GConfig->GetBool(TEXT("/Script/CryptoKeys.CryptoKeysSettings"), TEXT("bEncryptPakIndex"), bEncryptPakIndex, GSetting);
GConfig->GetBool(TEXT("/Script/CryptoKeys.CryptoKeysSettings"), TEXT("bEncryptPakIniFiles"), bEncryptPakIniFiles, GSetting);
GConfig->GetBool(TEXT("/Script/CryptoKeys.CryptoKeysSettings"), TEXT("bEncryptUAssetFiles"), bEncryptUAssetFiles, GSetting);
GConfig->GetBool(TEXT("/Script/CryptoKeys.CryptoKeysSettings"), TEXT("bEncryptAllAssetFiles"), bEncryptAllAssetFiles, GSetting);
if (bEncryptPakIndex || bEncryptPakIniFiles || bEncryptUAssetFiles || bEncryptAllAssetFiles) {
FString EncryptionKey;
GConfig->GetString(TEXT("/Script/CryptoKeys.CryptoKeysSettings"), TEXT("EncryptionKey"), EncryptionKey, GSetting);
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform EncryptionKey = %s"), &EncryptionKey);
FCoreDelegates::GetPakEncryptionKeyDelegate().BindLambda([EncryptionKey](uint8* key) {
TArray<uint8> KeyBase64Array;
FBase64::Decode(EncryptionKey, KeyBase64Array);
FMemory::Memcpy(key, KeyBase64Array.GetData(), FAES::FAESKey::KeySize);
});
}
結(jié)合上面的代碼:
FPakPlatformFile* HotPatchServer::CheckAndInitPakPlatform()
{
FPakPlatformFile* HandlePakPlatform = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(FPakPlatformFile::GetTypeName()));
if (!HandlePakPlatform)
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform FPakPlatformFile == NULL"));
// 方便 Editor 調(diào)試 mount 流程
#if WITH_EDITOR
if (EnabledEditorHotPatch)
{
bool bEncryptPakIndex;
bool bEncryptPakIniFiles;
bool bEncryptUAssetFiles;
bool bEncryptAllAssetFiles;
FString GSetting = FString::Printf(TEXT("%sDefaultCrypto.ini"), *FPaths::SourceConfigDir());
GConfig->GetBool(TEXT("/Script/CryptoKeys.CryptoKeysSettings"), TEXT("bEncryptPakIndex"), bEncryptPakIndex, GSetting);
GConfig->GetBool(TEXT("/Script/CryptoKeys.CryptoKeysSettings"), TEXT("bEncryptPakIniFiles"), bEncryptPakIniFiles, GSetting);
GConfig->GetBool(TEXT("/Script/CryptoKeys.CryptoKeysSettings"), TEXT("bEncryptUAssetFiles"), bEncryptUAssetFiles, GSetting);
GConfig->GetBool(TEXT("/Script/CryptoKeys.CryptoKeysSettings"), TEXT("bEncryptAllAssetFiles"), bEncryptAllAssetFiles, GSetting);
if (bEncryptPakIndex || bEncryptPakIniFiles || bEncryptUAssetFiles || bEncryptAllAssetFiles) {
FString EncryptionKey;
GConfig->GetString(TEXT("/Script/CryptoKeys.CryptoKeysSettings"), TEXT("EncryptionKey"), EncryptionKey, GSetting);
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform EncryptionKey = %s"), &EncryptionKey);
FCoreDelegates::GetPakEncryptionKeyDelegate().BindLambda([EncryptionKey](uint8* key) {
TArray<uint8> KeyBase64Array;
FBase64::Decode(EncryptionKey, KeyBase64Array);
FMemory::Memcpy(key, KeyBase64Array.GetData(), FAES::FAESKey::KeySize);
});
}
IPlatformFileModule* PlatformFileModule = FModuleManager::LoadModulePtr<IPlatformFileModule>(FPakPlatformFile::GetTypeName());
if (PlatformFileModule != NULL)
{
HandlePakPlatform = (FPakPlatformFile*)(PlatformFileModule->GetPlatformFile());
IPlatformFile& TopmostPlatformFile = FPlatformFileManager::Get().GetPlatformFile();
const TCHAR* Name = TEXT("");
for (IPlatformFile* ChainElement = &TopmostPlatformFile; ChainElement; ChainElement = ChainElement->GetLowerLevel())
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform 尋找合適插入位置 Name = %s"), ChainElement->GetName());
if (ChainElement->GetLowerLevel() == NULL)
{
HandlePakPlatform->Initialize(ChainElement, TEXT(""));
HandlePakPlatform->InitializeAfterSetActive();
Name = ChainElement->GetName();
break;
}
}
for (IPlatformFile* ChainElement = &TopmostPlatformFile; ChainElement; ChainElement = ChainElement->GetLowerLevel())
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform 尋找被插隊的節(jié)點 Name = %s"), ChainElement->GetName());
if (ChainElement->GetLowerLevel() != NULL && FCString::Stricmp(ChainElement->GetLowerLevel()->GetName(), Name) == 0 && FCString::Stricmp(FPakPlatformFile::GetTypeName(), Name) != 0)
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform 尋找到了需要插入的節(jié)點 Name = %s OldGetLowerLevel = %s NewLowerLevel = %s"), ChainElement->GetName(), ChainElement->GetName(), HandlePakPlatform->GetName());
ChainElement->SetLowerLevel(HandlePakPlatform);
break;
}
}
if (TopmostPlatformFile.GetLowerLevel() == NULL)
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform 沒尋找到被插隊的節(jié)點 HandlePakPlatform 被放在最上層!"));
FPlatformFileManager::Get().SetPlatformFile(*HandlePakPlatform);
}
}
}
#endif
}
else
{
UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform FPakPlatformFile is OK"));
}
return HandlePakPlatform;
}