美文网首页Unreal 技术笔记
unreal editor 下如何 mount 加密过的 pak

unreal editor 下如何 mount 加密过的 pak

作者: 子夜书案 | 来源:发表于2023-08-12 21:47 被阅读0次

问题:editor 下如何调试 pak 的 mount 流程?

  • mount pak
    一般只要如下调用就可以:
FPakPlatformFile*  PakPlatform = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(FPakPlatformFile::GetTypeName()));
if (PakPlatform)
{
    PakPlatform->Mount(*pakPath, PakOrder)
}
  • 但有两种情况下,PakPlatform 会为 Null
    1,当打包时(package)时没有选 -pak 并且项目的 content 目录下没有 pak 文件
    2,editor 模式下
  • 解决方法
    第一种情况好解决,打包时加上 -pak 参数就行(我在这被坑了很久);第二种情况就麻烦点,需要手动将 PakPlatform 插入责任链条中,大概的代码如下:
FPakPlatformFile* HotPatchServer::CheckAndInitPakPlatform()
{
    FPakPlatformFile*  HandlePakPlatform = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(FPakPlatformFile::GetTypeName()));
    if (!HandlePakPlatform)
    {
        UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform FPakPlatformFile == NULL")); 
// 方便 Editor 调试 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 寻找被插队的节点 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 寻找到了需要插入的节点 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 没寻找到被插队的节点 HandlePakPlatform 被放在最上层!"));
                    FPlatformFileManager::Get().SetPlatformFile(*HandlePakPlatform);
                }
            }
        }
#endif
    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform FPakPlatformFile is OK"));
    }
    return HandlePakPlatform;
}

问题:editor 挂载(mount)加密后的 pak 报错?

  • pak 为何要加密?

一般正式上线时,为了资源不被轻松破解,一般都会选择将 pak 加密。

  • 如何加密?

如下图所示:


加密设置
  • 那为啥在打出的包能正常解密,而在 editor 下却会失败呢?

一开始我也很疑惑,经过多次查找下来,在 Engine/Source/Programs/UnrealBuildTool/Configuration/TargetRules.cs 中发现了如下代码:


定义

具体模版内容为:


模版内容

以上可以总结为:在打包时(编译项目时),会根据项目的设置,自动生成对应的解密代码。

  • 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);
     });
}

结合上面的代码:

FPakPlatformFile* HotPatchServer::CheckAndInitPakPlatform()
{
    FPakPlatformFile*  HandlePakPlatform = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(FPakPlatformFile::GetTypeName()));
    if (!HandlePakPlatform)
    {
        UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform FPakPlatformFile == NULL")); 
// 方便 Editor 调试 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 寻找被插队的节点 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 寻找到了需要插入的节点 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 没寻找到被插队的节点 HandlePakPlatform 被放在最上层!"));
                    FPlatformFileManager::Get().SetPlatformFile(*HandlePakPlatform);
                }
            }
        }
#endif
    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("CheckAndInitPakPlatform FPakPlatformFile is OK"));
    }
    return HandlePakPlatform;
}

相关文章

网友评论

    本文标题:unreal editor 下如何 mount 加密过的 pak

    本文链接:https://www.haomeiwen.com/subject/orzxmdtx.html