unreal editor 下如何 mount 加密過(guò)的 pak?

問(wèn)題:editor 下如何調(diào)試 pak 的 mount 流程?

  • mount pak
    一般只要如下調(diào)用就可以:
FPakPlatformFile*  PakPlatform = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(FPakPlatformFile::GetTypeName()));
if (PakPlatform)
{
    PakPlatform->Mount(*pakPath, PakOrder)
}
  • 但有兩種情況下,PakPlatform 會(huì)為 Null
    1,當(dāng)打包時(shí)(package)時(shí)沒(méi)有選 -pak 并且項(xiàng)目的 content 目錄下沒(méi)有 pak 文件
    2,editor 模式下
  • 解決方法
    第一種情況好解決,打包時(shí)加上 -pak 參數(shù)就行(我在這被坑了很久);第二種情況就麻煩點(diǎn),需要手動(dòng)將 PakPlatform 插入責(zé)任鏈條中,大概的代碼如下:
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 尋找被插隊(duì)的節(jié)點(diǎn) 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é)點(diǎn) 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 沒(méi)尋找到被插隊(duì)的節(jié)點(diǎn) HandlePakPlatform 被放在最上層!"));
                    FPlatformFileManager::Get().SetPlatformFile(*HandlePakPlatform);
                }
            }
        }
#endif
    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform FPakPlatformFile is OK"));
    }
    return HandlePakPlatform;
}

問(wèn)題:editor 掛載(mount)加密后的 pak 報(bào)錯(cuò)?

  • pak 為何要加密?

一般正式上線時(shí),為了資源不被輕松破解,一般都會(huì)選擇將 pak 加密。

  • 如何加密?

如下圖所示:


加密設(shè)置
  • 那為啥在打出的包能正常解密,而在 editor 下卻會(huì)失敗呢?

一開始我也很疑惑,經(jīng)過(guò)多次查找下來(lái),在 Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs 中發(fā)現(xiàn)了如下代碼:


定義

具體模版內(nèi)容為:


模版內(nèi)容

以上可以總結(jié)為:在打包時(shí)(編譯項(xiàng)目時(shí)),會(huì)根據(jù)項(xiàng)目的設(shè)置,自動(dòng)生成對(duì)應(yīng)的解密代碼。

  • editor 下如何解密?

其實(shí)也比較簡(jiǎn)單,就像上面的代碼一樣,加一個(gè)解密的 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 尋找被插隊(duì)的節(jié)點(diǎn) 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é)點(diǎn) 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 沒(méi)尋找到被插隊(duì)的節(jié)點(diǎn) HandlePakPlatform 被放在最上層!"));
                    FPlatformFileManager::Get().SetPlatformFile(*HandlePakPlatform);
                }
            }
        }
#endif
    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform FPakPlatformFile is OK"));
    }
    return HandlePakPlatform;
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容