모드 스크립트: 디버깅

프로그램을 작성할 때(가장 간단한 것부터 가장 복잡한 것까지)면, 프로그램이 제대로 작동하지 않게 만드는 버그를 피할 수 없이 마주치게 됩니다. 샌드박스의 특성상, 정확히 무슨 일이 일어나고 있는지 파악하기가 다소 어려울 수 있습니다. 자, 여기 스크립트 문제를 진단하는 데 도움이 될 몇 가지 팁을 소개합니다.

“원시인식” 디버깅

스크립트가 실행되는 환경에 직접 접근할 수 없기 때문에, 프로그램에서 무슨 일이 일어나고 있는지 파악하려면 수많은 log() 호출에 의존해야 합니다. 예를 들어, 특정 토큰이 왜 제대로 움직이지 않는지 잘 모르겠고, 그 과정에서 오가는 값들에 대해 좀 더 파악하고 싶다면 다음과 같이 해볼 수 있습니다:

on("change:graphic:left", function(obj) {
  //이 함수에 전달되는 객체의 'left' 값은 무엇인가요?
  log(obj.get("left"));
  obj.set("left", obj.get("left") + 70);
  //지금은 어떻게 되었나요?
  log(obj.get("left"));
  //객체 전체를 디버깅하여 현재 속성 목록을 확인할 수도 있습니다.
  log(obj);
});

log() 명령어의 출력 결과는 캠페인별 ‘Mod 스크립트 설정’ 페이지에 있는 Mod 출력 콘솔에서 확인할 수 있습니다.

Mod Script 샌드박스 v1.5 전용입니다. 가능한 경우, 오류 메시지에는 관련 Roll20 객체(유형 및 ID)를 확인할 수 있도록 컨텍스트 객체가 포함됩니다:

오류: toBelow() 함수는 Roll20 그래픽, 텍스트 또는 경로 객체를 인수로 받아 호출되어야 합니다. [Roll20 캐릭터 -NM0tVij02hIfnoTdihc]로 호출되었습니다.

오류 잠금

샌드박스는 스크립트에서 발생하는 사소한 오류가 있을 경우, 필요에 따라 스크립트를 다시 시작함으로써 자동으로 복구합니다. 그러나 복구할 수 없는 심각한 오류가 감지될 경우, 스크립트를 반복해서 재시작했다가 계속해서 오류가 발생하는 상황을 방지하기 위해 캠페인에 “오류 잠금”을 적용하여, 오류가 해결될 때까지 모드 스크립트가 실행되지 않도록 합니다. 스크립트가 오류로 인해 잠겨 있는 경우, ‘모드 스크립트 설정’ 페이지에 다음과 같은 메시지가 표시됩니다:

Mod Scripts 편집기의 오류 잠금

걱정하지 마세요! 스크립트를 수정하여 문제를 해결해 보신 다음, ‘스크립트 저장’ 버튼을 클릭하세요. 그렇게 하면 오류 잠금이 해제되고, 샌드박스가 스크립트를 다시 실행하려고 시도합니다. 다른 오류가 발생하면 오류 잠금이 다시 적용됩니다. 오류를 해결할 때까지 이 과정을 필요한 만큼 반복할 수 있습니다. 시도 횟수가 너무 많다는 이유로 오류 잠금을 해제하지 못하게 되는 일은 절대 없습니다.

스크립트별 호출 스택

호출 스택에는 스크립트 이름과 줄 번호가 표시됩니다.

오류에는 연결된 샌드박스 파일이 아닌 스크립트와 줄 번호를 명시하는 재작성된 호출 스택이 포함됩니다. 수동 스크립트에는 ‘SCRIPT’라는 레이블이 붙으며, 그 다음으로 탭에 지정한 이름, 탭 번호, 오류가 발생한 줄 번호, 열 오프셋 순으로 표시됩니다:

부분 예시
라벨 대본
이름 '나쁜 배우' 대본
탭 85
직선 3
칼럼 13

예시: 스크립트: Bad Actor 스크립트 [탭 85]:3

직접 작성한 스크립트의 호출 스택

원클릭 라이브러리 스크립트도 마찬가지이지만, 레이블은 1-CLICK입니다:

원클릭 라이브러리 스크립트의 호출 스택

전체 호출 스택이 변환되므로, 여러 스크립트가 다른 스크립트를 호출하는 경우 그 모든 과정이 어디에서 일어나고 있는지 파악할 수 있습니다.

무한 루프 가능성이 감지되었습니다. 추가 정보

샌드박스가 하트비트 전송을 중단하면, 무한 루프에 빠질 가능성이 있으며, 이 경우 시스템이 종료됩니다. 해당 이벤트와, 실행 중이던 콜백이 어디에 등록되었는지 확인할 수 있습니다. 이를 통해 문제가 발생하는 지점을 파악하는 데 큰 도움이 되며, 해결책을 찾는 속도도 훨씬 빨라질 것입니다.

  • 이벤트: change:graphic
  • 콜백: Bad Actor 스크립트의 37행

이벤트 및 콜백으로 인한 무한 루프 발생 가능성

흔히 발생하는 오류

다음은 좀 더 흔히 발생하는 오류들입니다:

myvar가 정의되지 않았습니다

on("ready", function() {
  var myVar;
  log(myvar);
});

오류 메시지에는 “정의되지 않음”이라고 표시되지만, 실제로는 변수가 선언되지 않은 것입니다. 이 문제의 가장 흔한 원인 중 하나는 변수 이름의 오타, 예를 들어 대문자를 빠뜨리는 경우입니다.

myProperty 속성을 읽을 수 없거나 myMethod 메서드를 호출할 수 없습니다.

on("ready", function() {
  var myVar;
  log(myVar.myProperty);
  log(myVar.myMethod());
});

myVar가 정의되어 있지 않으므로, 스크립트는 사용자가 myVar의 속성에 접근하려는 상황을 어떻게 처리해야 할지 알 수 없습니다. 이는 다음 중 하나 때문일 가능성이 높습니다:

  • getObj 또는 findObjs를 사용하여 객체를 찾으려고 했으나, 결과가 undefined로 나타났습니다. 속성에 접근하기 전에 변수가 정의되었는지 확인하기 위한 오류 검사를 수행하십시오.
  • 변수가 조건부(일련의 if 문이나 이와 유사한 방식)로 정의되고 있는데, 어떤 조건에도 일치하는 경우가 없었기 때문에 변수는 선언된 상태만 유지되었을 뿐, 실제로는 정의되지 않았습니다. 모든 가능성에 대한 조건을 설정하거나, 기본값을 지정하거나, 속성에 접근하기 전에 변수가 정의되었는지 확인하기 위한 오류 검사를 수행하십시오.

Roll20 객체에도 get 및 set 메서드가 필요합니다. obj.left는 테이블탑의 위치를 나타내지 않습니다. obj.get("left")를 사용하십시오.

예상치 못한 토큰

캐릭터가 하나 부족하거나 하나가 너무 많습니다. 이는 객체의 속성 목록이나 배열의 요소 사이에 쉼표를 빠뜨리거나, 복잡하게 중첩된 메서드 호출의 끝에 닫는 괄호가 하나 더 많거나 부족할 때 발생할 수 있습니다.

_displayname은 undefined를 반환하는 반면, get("_displayname")은 이름을 반환합니다

Roll20 객체의 대부분의 속성은 get() 및 set() 메서드를 통해 접근해야 합니다. get()을 사용할 때, 읽기 전용 속성의 경우 앞쪽에 있는 밑줄을 생략할 수 있습니다. 즉, obj.get("displayname") 은 obj.get("_displayname")과 동일합니다. obj._displayname은 아닙니다.

그래도 문제가 지속된다면, 저희 모드 스크립트 포럼에 게시물을 올려 주시기 바랍니다. 콘솔 오류 메시지와 예상했던 결과를 간략히 설명해 주세요.

도움이 되었습니까?
124명 중 20명이 도움이 되었다고 했습니다.