UDN
Search public documentation:

DebuggerInterfaceKR
English Translation
日本語訳
中国翻译

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UE3 홈 > 에디터와 툴 프로그래밍 > 언리얼스크립트 디버거 인터페이스
UE3 홈 > 언리얼스크립트 > 언리얼스크립트 디버거 인터페이스

언리얼스크립트 디버거 인터페이스


문서 변경내역: Main.JoeWilcox 제작.

개요


전형적인 디버깅 세션과 거기에 무엇이 포함되는지를 봅시다. 언리얼스크립트를 디버그 하기 전에 당신은 디버그 모드에서 스크립트를 컴파일 해야 합니다("-debug" 를 코맨드 라인에 추가함으로써, e.g. UDK make -debug). 이것은 추가적인 컨트롤과 맵핑 정보를 컴파일된 패키지에 추가합니다. 디버그 정보와 컴파일 된 스크립트를 갖게 되면, 두 방법 중 한가지를 통해 엔진에서 디버거를 활성화 시킬 수 있습니다. 첫 번째는, 첫번째 언리얼스크립트 바이트코드가 프로세스 되는 순간 UE3가 스크립트 디버거를 활성화시키도록 하는 "-autodebug" 코맨드 라인 스윗치를 사용하는 것입니다. 그렇지 않으면, 디버거를 활성화 시키고 즉각적으로 끊어지는 게임 콘솔로부터 "toggledebugger" 콘솔 코맨드가 사용될 수 있습니다.

디버거를 활성화할 때 어떠한 일이 벌어지는 지를 살펴 보겠습니다(방법 하나를 사용하여):

  1. 첫째로 UE3는 인터페이스 DLL을 로딩합니다. 디폴트로, 셋팅이 Debugger.ini 파일에서 얼마나 오버라이드 할 수 있을지에 상관없이 그것은 "DebuggerInterface.dll" 파일을 로딩할 것입니다. 이 DLL 은 디버그 코맨드를 엔진으로 보내고 결과를 다시 받는 도관의 역할을 합니다.
  2. 로딩이 되면, UE3 는 다시 엔진으로 커뮤니케이션 도관을 생성하는 exported 함수 SetCallback() 를 즉각적으로 호출합니다. 그리고 나서 그것은 3 개의 웟치 리스트를 클리어합니다 (로컬, 글로벌, 그리고 유저 웟치).
  3. 마지막으로, 디버거를 디스플레이 하거나 활성화하는 exported 함수 ShowDllForm 을 호출합니다.

오리지널 외부 디버거 인터페이스는 작은 Borland Delphi 형태 DLL 이었고 인터페이스는 역방향의 호환성을 위해서 동일하게 남아있습니다. 인터페이스 DLL 로부터 export 될 필요가 있는 함수들을 살펴보겠습니다.

인터페이스


디버거 인터페이스가 실행해야 할 19개의 함수가 있습니다. 그것은 다음과 같습니다:

void SetCallback(void* CallbackFunc)
 이것은 DLL에서의 운용에서 가장 중요한 함수입니다. 처음 활성화 되었을 때, 엔진은 이 함수를 통해서 콜백을 셋업하고자 합니다. 패스된 함수 포인터를 저장하고 커뮤니케이트 하기 위해 그것을 사용하여야 합니다. 어떠한 코맨드가 보내질 수 있는지에 대해선 추후에 언급할 것입니다.

void ShowDllForm()
 호출되었을 때, ShowDLLForm() 은 디버거의 윈도우를 활성화하고 그것을 보이게 만들 수 있어야 합니다.

void BuildHierarchy()
void ClearHierarchy()
엔진이 현재 로딩된 상태의 계층 구조를 보내려고 하는 디버거를 시그널하고자 할 때 이 두 함수는 호출됩니다. 그들 사이에서, UE3은 몇몇 개의 AddClassToHierarchy() 를 호출할 것이고, 로딩된 모든 계층의 트리를 패싱할 것입니다.

void AddClassToHierarchy(const char* ClassName)
이 함수는 계층을 디버거의 계층 구조에 추가할 때 사용됩니다. 오리지널 디버거는 계층구조 트리 뷰에서 로딩된 계층의 리스트를 유지했습니다. 이 정보는 다음의 포맷을 사용하는 스트링으로서 패스됩니다: .. 예를 들어 당신은 다음과 같은 것을 가질 수 있습니다: "core..object" (오브젝트가 부모를 가지고 있지 않기 때문) "engine.object.actor" "utgame.gameinfo.utgame" 디버거가 이 정보로 하는 일은 외부 어플리케이션에 달려 있습니다.

void ClearWatch(int WatchType)
void ClearAWatch(int WatchType)
UE3 는 3가지 다른 종류의 웟치를 서포트합니다: 로컬, 글로벌 그리고 유저 웟치. 이 함수는 UE3가 그 리스트 중의 하나를 클리어 하고자 할 때 호출됩니다. 그것은 다음의 웟치 타입을 서포트합니다:

  1. 로컬 웟치(Local Watches)
  2. 글로벌 웟치(Global Watches)
  3. 유저 웟치(User Watches)
외부 디버거는 웟치 리스트에서 데이터를 운용하고 디스플레이 하는 역할을 합니다. ClearWatch() 는오리지널 디버거 예시로부터의 유임자(holdover)입니다. 엔진은 여전히 그것을 호출하기 때문에 그것은 실행될 필요가 있습니다. 우리는 당신이 심플하게 ClearWatch() 로의 호출을 ClearAWatch() 핸들러로 재전송하는 것을 추천합니다.

int AddAWatch(int WatchType, int ParentIndex, const char* VarName, const char* VarValue)
엔진은 디버거 웟치 리스트를 업데이트하기 위해 이 함수를 사용합니다. 단일 변수는 종종 멀티플 AddAWatch() 호출로 귀결되곤 합니다. 예를 들어, 벡터를 위해 웟치를 추가하는 것은 (3 자녀를 갖는 구조) 4개의 AddAWatch() 호출로 귀결될 것입니다: 변수에 대한 첫 번째 호출과 X, Y 그리고 Z에 대한 3개의 호출. 이 함수에 대한 파라미터는 다음과 같습니다:

   • WatchType: 웟치 타입은 ClearWatch() 에서 사용되는 밸류 타입과 동일합니다.
   • ParentIndex: 이것은 현 오브젝트에서 부모의 유니크 인덱스입니다. 엔진이 추가할 멤버 변수를 찾는 오브젝트를 통해 recurse함에 따라, 각각은 유니크 인덱스를 갖게 될 것입니다.
   • VarName: 이것은 변수의 이름입니다.
   • VarValue: 이것은 디스플레이 할 밸류이거나 변수에 대한 추가적인 디스플레이 데이터가 될 것입니다.

AddAWatch() 에 대한 리턴 결과는 웟치 리스트에서 이 특정한 변수를 기술하는 유니크 ID 일 필요가 있습니다.

벡터 예를 좀더 세밀하게 보겠습니다. 다음 스크립트 코드를 보십시오:

function TestFunc()
{
    local vector TestVec;
    TestVec.X = 10;
    TestVec.Y=20;
    TestVec.Z=30;
    log(TestVec);
}

로그 식에서 중지점(breakpoint)을 셋팅하면, 디버거가 브레이크 할 때 UE3가 첫 번째로 하는 것은 ClearWatch(0) 를 사용하여 로컬 웟치를 클리어하는 것입니다. 그리고 나서 그것은 TestVec 에 대해 웟치를 추가하고자 합니다. 이것은 다음의 AddAWatch() 호출로 귀결됩니다:

AddAWatch(0, 0, "!TestVec",""); // 1로 리턴해야 함
AddAWatch(0,1,"X","10"); // 2로 리턴해야 함
AddAWatch(0,1,"Y","20"); // 3으로 리턴해야 함
AddAWatch(0,1,"Z","20"); // 4로 리턴해야 함

void LockList(int WatchList)
void UnlockList(int WatchList)
이 두개의 함수는 UE3이 주어진 웟치 리스트에 업데이트 하려고 할 때 호출됩니다. 디버거는 UnlockList() 함수가 호출될 때까지 가능한 한 스무스하게 업데이트를 진행하기 위해서 필요한 어떤 스텝도 택할 수 있어야 합니다.

void AddBreakpoint(const char* ClassName, int LineNo)
void RemoveBreakpoint(const char* ClassName, int LineNo)
UE3 가 트랙킹하는 중지점(breakpoint)을 디스플레이에 추가할 필요가 있을 때, 그것은 디버거로 레지스터(register)하기 위해 AddBreakPoint 를 호출합니다. ClassName 은 중지점이 존재하는 계층의 이름이고 LineNo 는 라인 넘버입니다. 외부 디버거는 이것을 트랙킹 하고 연결 라인에서의 중지점을 디스플레이 하는 역할을 합니다. 마찬가지로, RemoveBreakPoint() 는 현존하는 중지점을 제거하라고 디버거에게 말합니다.

void EditorLoadClass(const char* ClassName)
UE3 는 이 함수를 사용하여 ClassName 변수에 의해 구체화 된 계층을 위한 스크립트를 로딩하라고 디버거에 지시합니다. ClassName 은 . 으로 패스됩니다. 디버거는 스트링을 분할하고 적당한 파일을 로딩하는 역할을 할 것입니다.

void EditorGotoLine(int LineNo, int bHighlight)
UE3 는 이 함수를 사용하여 현 소스 파일에서 특정한 라인을 디스플레이 하라고 디버거에 지시합니다. EditorGotoLine() 은 항상 EditorLoadClass() 호출에 의해 선행될 것임을 명심하십니다.

void AddLineToLog(const char* Text)
UE3 는 무언가를 디버거 로그 파일에 아웃풋 할 필요가 있을 때 이 함수를 호출합니다. 텍스트는 추가할 스트링입니다.

void CallStackClear()
UE3 가 브레이크하고 디버거에서 호출 스택을 업데이트 할 필요가 있을 때, 그것이 첫째로 할 일은 CallStackClear() 를 실행하는 것입니다. 이것은 디버거로 하여금 UE3이 호출 스택을 다시 빌드하길 원한다는 것을 시그널합니다.

void CallStackAdd(const char* CallStackEntry)
브레이크 후에, UE3는 몇몇의 CallStackAdd() 호출을 하여 디버거에 호출 스택을 빌드하고자 합니다. 디버거는 들어오는 데이터를 위해 어딘가에는 그것을 디스플레이 해야 합니다. CallStackEntry 는 라인 넘버 뿐만이 아니라 계층 이름도 포함하는 스트링입니다.

void SetCurrentObjectName(const char* ObjectName)
UE3 는 이 함수를 사용하여 디버거에서 현 오브젝트의 이름을 셋팅합니다. 그것은 각각의 내부 업데이트 호출 동안에 호출됩니다. 당신은 당신이 보기에 적절한 때에 이 정보를 사용할 수 있습니다.

void DebugWindowState(int StateCode)
이 함수는 현재 사용되지 않고 있습니다.

콜백(Callback)


우리는 앞서 UE3이 디버거와 어떻게 커뮤니케이션 하는지를 살펴보았습니다. 이제 다른 디렉션을 보겠습니다. 디버거는 콜백 함수를 통해 UE3과 커뮤니케이션 할 필요가 있습니다. 인터페이스 DLL이 엔진에 매여 있을 때, 엔진은 그것의 콜백을 register 할 것입니다. 이 콜백을 통해, 당신은 몇몇의 코맨드를 보낼 수 있고 모두 스트링으로서 패스됩니다.

콜백에 대한 typedef 는 다음과 같습니다:

typedef void (*CallbackPointer)(const char*);

다음은 코맨드 리스트입니다:

addbreakpoint

<classname>  <linenumber>

removebreakpoint
<classname>  <linenumber>

이 코맨드는 UE3에게 중지점을 추가/제거하라고 말할 때 사용됩니다. 은 중지점이 존재하는 호출의 이름이고 는 라인 넘버입니다.

addwatch

<varname>

removewatch
<varname>

이 코맨드는 UE3에게 유저설정 웟치를 추가/제거 하라고 말합니다. 당신은 그것을 충분히 기술해야만 합니다 (예: pawn.playerreplicationinfo.playername).

clearwatch
이 코맨드는 파라미터를 갖지 않고 모든 유저 웟치를 클리어 할 것입니다.

changestack

<stackid>

이 코맨드는 엔진으로 하여금 콜스택에서 주어진 포지션으로 점프하게 만듭니다.

setdatawatch

<watchtext>

이 코맨드는 주어진 변수의 데이터 액세스에서의 중지점을 셋팅합니다.

breakonnone

<0=false|1=true>

breakonnone 코맨드를 사용하여 access none error가 일어날 때면 언제든 브레이크 하라고 디버거에게 지시합니다.

break
가능한 한 빨리 브레이크 하라고 UE3에게 말합니다.

stopdebugging
이 코맨드는 디버거를 셧다운 하고 디버깅 세션을 중지합니다.

go
stepinto
stepover
stepoutof
이 코맨드는 디버거의 실행을 컨트롤 합니다.

하지만 잠깐... 그러니까 만약 내가 "addwatch" 코맨드를 UE3 로 보내면 내가 AddAWatch() 인터페이스 호출을 받는다는 겁니까? 네, 맞습니다. UE3를 사건들이 일어나는 곳으로, 그리고 당신의 인터페이스 DLL을 일어나고 있는 것을 렌더하는 것으로 생각하십시오. 그래서 당신이 "addwatch" 코맨드를 보낼 때, UE3 는 첫째로 오브젝트로 향하는 노선이 유효한지를 확인하고, 그리고 나서 그 오브젝트에 웟치를 내부적으로 셋업하여 그것이 완료되면 주어진 오브젝트를 웟치하고 있다고 인터페이스에 말해줄 것입니다. 네, 이것은 이렇게나 심플합니다.

유용한 다른 정보


끝마치기 전에, 당신이 디버거를 브레이크 할 때 정확이 어떤 일이 발생했는지를 보겠습니다. 이것은 당신의 외부 어플리케이션에서 무엇을 찾아야 할지에 대한 아이디어를 제공할 것입니다. 당신이 "break" 코맨드를 콜백에 보내면, UE3 는 프로세스를 시작할 것입니다. 그것은 다음 스크립트 바이트 코드의 실행에서의 브레이크를 알리는 플래그를 셋팅합니다. 그게 일어날 때, 몇몇 단계를 수행합니다.

  1. UE3 는 EditorLoadClass() 와 EditorGotoLine() 으로의 호출을 통해 어떤 계층, 어떤 라인에 위치한지를 인터페이스에 알립니다.
  2. 그리고 나서 SetCurrentObjectName 로 ObjectName 을 셋팅합니다.
  3. 다음으로 그것은 처음엔 ClearAWatch() 을 그리고 나선 AddAWatch() 를 여러 번 호출함으로써 모든 웟치를 리프레쉬합니다.
  4. CallStackAdd() 에 대한 멀티플 호출이 뒤따르는 CallStackClear() 을 호출함으로써 호출 스택을 리프레쉬 합니다.

"브레이크 된" 상태에 있는 동안, 게임은 동면 상태일 것이지만(모든 타이밍을 포함하여) 그것은 렌더하는 것과 윈도우 메시지 수신을 계속 할 것입니다.