Questsmith에서 스크립팅 사용 방법
시나리오 스크립트를 사용하여 에디터 UI 이상으로 입력, 컨텍스트 및 출력 동작을 제어하세요.
스크립팅은 제작자가 시나리오 에디터가 지원하는 범위를 넘어 플레이어 경험을 사용자 정의할 수 있게 해줍니다.
Questsmith에서 스크립트는 시나리오에 부착되어 해당 시나리오에서 시작된 모험들이 공유하며, 각 모험은 각자의 별도 게임 상태를 유지합니다.
시나리오 지원 및 가시성
- 스크립트는 단순 시작(Simple Start) 및 캐릭터 제작기(Character Creator) 시나리오에서 사용할 수 있습니다.
- 객관식 부모 시나리오는 스크립트를 가질 수 없지만, 그 옵션들은 가질 수 있습니다.
- 시나리오 제작자만이 스크립트를 보고 편집할 수 있습니다.
- 게시된 시나리오 스크립트는 가이드라인 준수를 위해 모더레이션 검토를 받을 수 있습니다.
스크립팅 UI 개요
지원되는 시나리오를 편집하는 동안 세부 정보(Details) 탭 하단에서 스크립팅을 엽니다.
- 라이브러리 (Library): 다른 스크립트에서 사용할 수 있는 공유 헬퍼와 상수입니다.
- 입력 (Input): onInput 라이프사이클 훅 중에 실행됩니다.
- 컨텍스트 (Context): onModelContext 라이프사이클 훅 중에 실행됩니다.
- 출력 (Output): onOutput 라이프사이클 훅 중에 실행됩니다.
라이브러리가 아닌 스크립트의 경우, 마지막 줄은 반드시 modifier(text)를 호출해야 합니다.
스크립트 테스트 패널
- 입력: 스크립트 동작을 시뮬레이션하기 위한 편집 가능한 테스트 페이로드입니다.
- 제출: 스크립트 + 라이브러리 + 입력을 서버로 보내 실행합니다.
- 출력: 반환된 텍스트, 정지 여부, 로그, 상태 및 스토리 카드 정보를 보여줍니다.
콘솔 로그 패널
- 해당 시나리오에서 시작된 당신의 플레이 테스트 모험들의 최근 로그를 표시합니다.
- 실시간으로 스트리밍되며 분할 탭(에디터 + 플레이 테스트)과 함께 사용하면 유용합니다.
- 로그는 15분 동안 보관됩니다.
라이프사이클 훅
스크립팅 API는 세 가지 훅을 노출하며, 각각은 격리된 샌드박스에서 실행됩니다.
- onInput
- onModelContext
- onOutput
런타임 제한: 훅당 16MB 메모리 및 2초 타임아웃이 적용됩니다.
사용 가능한 매개변수
스크립트 범위 내에서 이들을 직접 참조할 수 있습니다:
- text: 훅에 따라 플레이어 입력, 모델 컨텍스트 텍스트, 또는 출력 텍스트입니다.
- history: 텍스트/가공되지 않은 텍스트/유형 정보를 포함하는 최근 행동 배열입니다.
- storyCards: 모험 카드 배열입니다 (레거시 별칭인 worldInfo도 여전히 지원됨).
- state: 여러 턴에 걸쳐 유지되는 커스텀 스크립트 기억을 위한 영구 객체입니다.
- info: actionCount, 캐릭터 이름, 최대 글자 수, 기억 길이와 같은 헬퍼 메타데이터입니다.
상태(State) 객체 유의사항
- 상태를 직접 수정하세요 (별도의 헬퍼가 필요 없음).
- state.memory는 컨텍스트, 작가의 노트 및 프런트 메모리 오버라이드를 지원합니다.
- state.placeholders는 시나리오 플레이스홀더의 질문/답변 값을 저장하며 여러 턴에 걸쳐 지속됩니다.
- state.message는 클라이언트 지원에 따라 플레이어에게 표시될 수 있습니다.
사용 가능한 함수
- log
- addStoryCard
- removeStoryCard
- updateStoryCard
반환 규약
스크립트는 보통 다음과 같은 객체를 반환해야 합니다:
return { text: 'New text' }
return { stop: true }- text: 훅 텍스트 스트림(입력, 모델 컨텍스트 또는 출력)을 대체합니다.
- stop: 루프 진행을 중단합니다. 주의 깊고 의도적으로 사용하세요.
중요한 오류 동작
- onInput에서 빈 텍스트를 반환하면 플레이어에게 스크립트 오류가 발생합니다.
- onModelContext에서 빈 텍스트를 반환하면 스크립트가 실행되지 않은 것처럼 작동합니다.
- onOutput에서 빈 텍스트를 반환하면 플레이어에게 커스텀 스크립트 실패가 표시됩니다.
- onOutput에서 stop을 반환하는 것은 권장되지 않습니다.
최소 입력 스크립트 예시
const modifier = (text) => {
let modifiedText = text
if (text.includes('칼을 잡는다')) {
state.items = ['sword']
state.memory = { context: '당신은 칼을 가지고 있습니다.' }
state.message = '칼을 획득했습니다!'
log('플레이어에게 칼 추가됨')
modifiedText = text + '\n이제 칼도 가지고 있습니다!'
}
return { text: modifiedText }
}
modifier(text)실용적인 활용 사례
- 명령어 파서 (커스텀 플레이어 명령어).
- 상태(state)에서의 인벤토리나 지위 추적.
- 기억/작가의 노트/프런트 메모리의 동적 조정.
- 컨텍스트 후처리와 안전 가드레일.
- 사건에 기반한 자동 스토리 카드 삽입/제거.
베스트 프랙티스
- 작은 스크립트로 시작하고 각 훅을 독립적으로 테스트하세요.
- 스크립트를 결정론적으로 유지하고 무거운 계산은 피하세요.
- 재사용 가능한 로직과 상수를 위해 라이브러리를 사용하세요.
- 정의되지 않은 필드(기록, 플레이스홀더, 정보값)에 대비하세요.
- 가능하면 전체 텍스트 재작성보다 가산적인 수정을 선호하세요.
- 라이브 플레이 테스트 중에 콘솔 로그를 사용하고 이슈를 최소한으로 재현하세요.
문제 해결 팁: 스크립트가 예기치 않게 실패한다면, 최소한의 재현 시나리오를 게시하고 해당 링크를 버그 보고서에 포함하세요. 이는 디버깅 속도를 획기적으로 높여줍니다.
스크립트 이슈나 기능 요청의 경우, Discord의 bugs/feature-request 채널을 이용하고 가능한 경우 재현 단계를 포함해 주세요.