美文网首页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