5 min to read
팰월드 모드 제작법8
심화과정 101
심화과정 101
지금까지 어느정도의 UE4SS의 함수들을 이해하셨지만, 실제로 원하는 작업을 수행하기 위해서 어떤 함수를 실제 연결하거나 혹은 호출해야 하는지 파악하는데 어려움이 있을 것입니다. *****
심화과정 101에 오신것을 환영합니다.
우리는 새로운 월드에 진입하여 UE4SS 콘솔을 준비합니다. 여기서 첫 번째 작업은 많은 사람들이 관심을 가지는 것입니다. 채팅 메시지가 전송될때 호출되는 함수를 연결하고 해당 메시지를 콘솔에 출력하는 것입니다. 그러나 어떤 함수가 호출되는지 혹은 어디서 찾아야하는지에 대해 아무것도 알지 못합니다. 그래서 라이브 뷰를 자세히 살펴보도록 합시다.
**❕NOTE**
라이브뷰는 특정함수를 찾는데 가장 적합하지 않을 수도 있지만, 코드베이스의 구조 및 조직을 이해하는데 유용한 도구입니다.
우리는 라이브 뷰와 헤더 파일 간의 탐색법을 배워 언리얼 엔진4 서버 측 스크립팅 환경에 대한 더 나은 이해를 얻을 수 있습니다.
라이브 뷰(Live view)
라이브 뷰 검색창에서 채팅 메시지와 관련된 내용을 검색해보십시오. 여전히 관련성있고 간단한 검색어를 쓰는 것이 좋습니다. 여기서는 함수를 찾고 있으므로 클래스나 객체를 확인하는 것보다 함수만을 살펴봅시다. 조금 검색해본 후 함수를 시도해볼 수 있는 생각되거나 막힌 경우에는 아래 스포일러를 확인하러 돌아오십시오.
만약 검색어가 떠오르지 않는다면...
*****
"chat"으로 시작해서 내용을 찾아봅시다.
뭔가 찾은것 같아요!
*****
"chat"과 관련된 내용을 검색했다면 아마도 몇 가지 함수를 찾으셨을 것입니다. 그 중 하나가 `BroadcastChatMessage`인 경우가 있을 것입니다.
그렇게 찾으셨다면 멋진 일입니다! 그렇지 않은 경우에는 튜토리얼을 위해 조금 더 쉽게 만들어 드리겠습니다.
`BroadcastChatMessage` 함수에 집중하도록 하겠습니다.
실습 목적으로 찾은 함수를 후킹하고 실제 채팅할 때 해당 함수가 실행되는지 확인해보도록 합시다. 함수를 후킹하고 해당 함수가 실행될 때 무언가를 출력하는데 배운 내용을 활용하여 스크립트를 작성하는 기회로 삼아주세요.
- 그 함수를 후킹하십시오.
- 그 함수가 실행되면 뭔가를 출력합니다.
그러면 후킹할 함수의 이름/주소는 어디서 찾나요?
*****
후킹할 함수 이름은 라이브 뷰에서 볼수 있는 전체 함수 경로입니다.
ex) `/Script/Pal.PalGameStateInGame:BroadcastChatMessage`입니다.
작동확인코드
-- 만약 이와 유사한 접근을 했다면 잘 하셨습니다.
-- 기술적으로 이것을 SAP 후크로 래핑할 수 있지만, 이것이 /Script/이므로 그럴 필요가 없습니다.
RegisterHook("/Script/Pal.PalGameStateInGame:BroadcastChatMessage", function()
print("enter chat fired")
end)
이제 세계를 떠나서 모드 스크립트를 다시로드하고 다시 참여한 후 채팅에 무언가를 입력해보겠습니다. 모든 것이 잘 작동한다면, 후크가 실행되고 채팅에 무언가가 출력될 것입니다!
이는 실제로 올바른 함수를 후킹할 수 있었다는 것을 의미합니다. 만약 올바른 함수로 안내되지 않았다면, 정확히 원하는 작업을 수행하는 함수를 찾기 위해 몇 가지 다른 함수를 시도해야 했을 것입니다.
하지만 이제 이 함수에 대해 더 많이 알고 싶습니다. 이 함수는 무엇을 반환합니까? 어떤 매개변수에 후크를 걸 수 있습니까? 이 함수에서 메시지를 가져올 수 있습니까?
여기서 헤더 파일이 필요합니다. *****
헤더파일
잠깐 VSCode로 전환해 봅시다.
워크스페이스의 CXXHeaderDump
폴더를 마우스 오른쪽 버튼으로 클릭하고 Find in Folder
를 클릭하세요.
이렇게 하면 파일에 이미 ./CXXHeaderDump
가 기입된 상태로 검색 대화상자가 열립니다.
이를 통해 해당 폴더의 모든 파일에서 무언가를 검색할 수 있습니다.
첫 번째 상자에는 우리가 찾고 있는 것을 입력하고, 이 경우에는 BroadcastChatMessage
에 대한 자세한 정보를 찾고 싶으므로 그렇게 검색하겠습니다.
물론 이미 찾고자하는 함수를 알기 때문에 해당 결과를 얻게 되고, 이는 Pal.hpp
에 있습니다.
해당 검색 결과를 클릭하여 해당 부분으로 자동으로 열어볼 수 있습니다.
NOTE: 우리는 이렇게 시작할 수도 있었습니다. 우리가 채팅 관련 내용을 찾고 있다는 것을 이미 알고 있었으므로, 단순히 “chat” 헤더 파일을 검색하고 나타난 결과물을 통해 유망해 보이는 것을 찾을 때까지 살펴볼 수 있었습니다.
[!TIP] 👍헤더 파일 팁:
CXXHeaderDump
를 사용하는 경우 대부분의 Lua에 관련된 내용은Pal.hpp
에서 찾을 수 있습니다.
해당 부분을 열면 그 함수와 그 매개변수를 볼 수 있습니다:
void BroadcastChatMessage(const FPalChatMessage& ChatMessage);
그 매개변수를 바로 우리의 후크에 전달할 수 있고, 그로 인해 채팅 메시지를 얻을 수 있을 것입니다.
좀 더 자세히 파고들기 전에, 그것을 시도해보고 무엇이 발생하는지 살펴보겠습니다.
후크를 수정하여 ChatMessage
매개변수를 가져오도록 하고, 그것을 출력하여 무슨 일이 발생하는지 확인해보세요.
그런데 이것이 작동하지 않을 것임을 미리 알려드리겠습니다. 하지만 이것이 학습 과정입니다.
작동확인코드
*****
-- I expect you'll come up with something like this
RegisterHook("/Script/Pal.PalGameStateInGame:BroadcastChatMessage", function(self, ChatMessage)
print(ChatMessage:get())
end)
이해도 확인! 이 후크의 self 매개변수는 뭔가요?
*****
self 매개변수는 UObject인 `PalGameStateInGame`을 가리킵니다.
올바르게 수행했다면, 아마도 다음과 유사한 오류 메시지가 나타날 것입니다:
Parameter #1 must be of type 'string'. Was of type 'userdata'.
print() 함수는 문자열을 전달받기를 기대합니다.
그리고 우리는 함수 헤더에서 알 수 있듯이, ChatMessage
가 FPalChatMessage
유형임을 알고 있습니다.
그러니 당연히 오류가 발생할 것입니다.
Pal.hpp
파일에서 FPalChatMessage
가 정확히 무엇인지 확인하기 위해 해당 함수로 돌아가 봅시다.
그런 다음 VSCode에서 해당 유형을 클릭하여 정의를 확인합니다.
정의로 직접 이동하여 FPalChatMessage
의 정의를 확인할 수 있습니다. 꽤 깔끔하죠.
struct FPalChatMessage
{
EPalChatCategory Category;
FString Sender;
FGuid SenderPlayerUId;
FString Message;
FGuid ReceiverPlayerUId;
};
그것은 여러 가지 구성 요소가 있는 구조체입니다. 일단 우리가 콘솔에 메시지를 인쇄하고 싶으므로 실제 FString Message
구성 요소를 가져와 보겠습니다.
이 속성에 액세스하려면 받은 구조체를 그 구성 요소로 분해해야 합니다.
그러므로 이제 ChatMessage
의 부분을 알았으니 후크를 수정하여 다음을 시도해보세요:
ChatMessage
가져오기Message
속성에 액세스하기Message
속성을 콘솔에 출력하기
힌트: `Was of type userdata` 오류 메시지를 유의하세요.
*****
이 반환된 유형을 유의하고 기억하세요... UE는 단순한 문자열을 반환하지 않습니다.
UE4SS 문서를 참조하여 Message 유형에 유용한 메서드를 찾아보세요.
작동확인코드
*****
-- Something like this should do the trick
RegisterHook("/Script/Pal.PalGameStateInGame:BroadcastChatMessage", function(self, ChatMessage)
local chat_message = ChatMessage:get()
local message = chat_message.Message:ToString() -- Take note of the :ToString()! FString is not the same as a string!
print(message)
end)
잘 하셨습니다! 이제 채팅 메시지를 기록하거나 다른 용도로 사용할 수 있습니다. 다음 튜토리얼에서는 좀 더 실용적인 것으로 넘어갈 것입니다.