zoukankan      html  css  js  c++  java
  • Unreal的quit控制台命令如何注册到dumpconsolecommands

    一、问题

    在UE进程运行的时候,可以在控制台通过DumpConsoleCommands来列出UE中所有可执行的命令。从实现上看,UE中所有的控制台命令最终都会通过EngineSourceRuntimeCorePrivateHALConsoleManager.cpp: FConsoleManager::AddConsoleObject进行注册;而quit命令在UE中并没有通过这个接口注册(可以通过断点确认),但是在执行DumpConsoleCommands时,这个命令却赫然出现在输出列表中。UE是如何实现的呢?

    二、DumpConsoleCommands本身的注册

    这个命令本身的注册是中规中矩的,就是通过RegisterConsoleCommand==>>AddConsoleObject进行注册
    ConsoleManager.cpp
    IConsoleManager::Get().RegisterConsoleCommand( TEXT( "DumpConsoleCommands" ), TEXT( "Dumps all console vaiables and commands and all exec that can be discovered to the log/console" ), ECVF_Default );

    三、如何捕捉值在代码中实现的控制台命令

    1、ConsoleCommandLibrary类的注释

    这里的注释说明了实现方法,就是在执行命令时,首先执行一个特殊命令,并注册钩子,在具体命令调用FParse::Command的时候触发回调,将传入命令名字添加到列表中。
    EngineSourceRuntimeCorePrivateMiscParse.cpp
    /**
    * Needed for the console command "DumpConsoleCommands"
    * How it works:
    * - GConsoleCommandLibrary is set to point at a local instance of ConsoleCommandLibrary
    * - a dummy command search is triggered which gathers all commands in a hashed set
    * - sort all gathered commands in human friendly way
    * - log all commands
    * - GConsoleCommandLibrary is set 0
    */
    class ConsoleCommandLibrary
    {
    public:
    ConsoleCommandLibrary(const FString& InPattern);

    ~ConsoleCommandLibrary();

    void OnParseCommand(const TCHAR* Match)
    {
    // -1 to not take the "*" after the pattern into account
    if(FCString::Strnicmp(Match, *Pattern, Pattern.Len() - 1) == 0)
    {
    KnownNames.Add(Match);
    }
    }

    const FString& Pattern;
    TSet<FString> KnownNames;
    };

    2、DumpConsoleCommands命令触发的主体函数

    这个函数通过ConsoleCommandLibrary局部变量注册GConsoleCommandLibrary钩子函数,然后调用SubSystem.Exec,从而触发各个在代码中解析的FParse::Command调用。
    EngineSourceRuntimeCorePrivateMiscParse.cpp
    void ConsoleCommandLibrary_DumpLibrary(UWorld* InWorld, FExec& SubSystem, const FString& Pattern, FOutputDevice& Ar)
    {
    ConsoleCommandLibrary LocalConsoleCommandLibrary(Pattern);

    FOutputDeviceNull Null;

    bool bExecuted = SubSystem.Exec( InWorld, *Pattern, Null);
    ……
    }

    3、FParse::Command函数中的回调

    在每次执行FParse::Command函数时,判断如果有GConsoleCommandLibrary指针注册,则调用OnParseCommand回调,并且通常是马上执行 return false,从而避免触发真正的命令执行过程。
    bool FParse::Command( const TCHAR** Stream, const TCHAR* Match, bool bParseMightTriggerExecution )
    {
    #if !UE_BUILD_SHIPPING
    if(GConsoleCommandLibrary)
    {
    GConsoleCommandLibrary->OnParseCommand(Match);

    if(bParseMightTriggerExecution)
    {
    // Better we fail the test - we only wanted to find all commands.
    return false;
    }
    }
    ……
    }

    四、副作用

    这种方法虽然巧妙,但是也有副作用:它们虽然可以通过DumpConsoleCommands提示出来,但是不能智能提示。
    比方说,当你输入时r.D,控制台会贴心的提示所有可能的命令,其中就包括r.DumpingMovie,因为这个命令通过IConsoleManager::Get().RegisterConsoleVariableRef(TEXT("r.DumpingMovie")进行了主动注册;
    但是通过这种奇技淫巧注册的命令就不行智能提示,例如输入start的的时候就不会智能提示StartRemoteSession,因为这个命令没有主动注册,而只是把解析写在了代码中。

  • 相关阅读:
    小白专场-堆中的路径-python语言实现
    小白专场-堆中的路径-c语言实现
    集合及运算
    哈弗曼树与哈夫曼编码

    线性结构之习题选讲-ReversingLinkedList
    小白专场-是否同一颗二叉搜索树-python语言实现
    微信公众平台开发教程第1篇-新手解惑(转)
    GIT GUI的使用(转)
    Git操作指南(2) —— Git Gui for Windows的建库、克隆(clone)、上传(push)、下载(pull)、合并(转)
  • 原文地址:https://www.cnblogs.com/tsecer/p/14964807.html
Copyright © 2011-2022 走看看