<p align="center">
<img alt="pkmn/engine" width="192" height="192" src="https://pkmn.cc/engine.svg" />
<br />
<br />
<a href="https://github.com/pkmn/engine/actions/workflows/test.yml">
<img alt="Test Status" src="https://github.com/pkmn/engine/actions/workflows/test.yml/badge.svg" />
</a>
<a href="#status">
<img alt="WIP" src="https://img.shields.io/badge/status-WIP-red.svg" />
</a>
<a href="https://github.com/pkmn/engine/blob/master/LICENSE">
<img alt="License" src="https://img.shields.io/badge/License-MIT-blue.svg" />
</a>
</p>
[!WARNING]
이 프로젝트는 개발이 활발하게 진행 중이며, 현재 main 브랜치에는 많은 breaking changes가 포함되어 있어 작동하지 않거나 완전히 문서화되지 않은 부분이 있을 수 있습니다. 이 프로젝트에 의존하기 전에 출시될 초기 v0.1 릴리스를 기다려 주십시오.
<hr />
A minimal, complete, Pokémon battle simulation engine optimized for performance and designed for tooling, embedded systems, and artificial intelligence use cases. This engine aims to be a frame-accurate and bug-for-bug compatible implementation of both Pokémon battles as defined by the original game code and the Pokémon Showdown[^1] simulator which represents Pokémon battling as practically interpreted online.
The pkmn engine is more than 1000× faster than the patched Pokémon Showdown simulator code when playing out supported formats in compatibility mode and is extensively tested and documented. Note, however, that the engine is not a fully featured simulator but is instead a low-level library which can be used as a building block for more advanced use cases.
Installation
이 저장소는 엔진 코드(Zig 언어로 작성됨)와 참조 드라이버 코드(TypeScript 언어로 작성됨)를 모두 호스팅합니다.
libpkmn
엔진 코드의 바이너리는 GitHub의 [releases] 탭에서 다운로드하거나, 소스 코드를 직접 다운로드하여 최신 zig 컴파일러로 빌드할 수 있습니다. 빌드 옵션은 zig build --help를 참고하세요:
$ curl https://github.com/pkmn/engine/archive/refs/heads/main.zip -o engine.zip
$ unzip engine.zip
$ cd engine
...
Zig 웹사이트에는 각 플랫폼에 Zig를 설치하는 방법을 안내하는 설치 지침이 있습니다. 엔진 코드는 Zig v0.16.0 이상에서 작동해야 하지만, Zig의 마스터 브랜치를 추적하므로, 향후 언어 변경 사항으로 인해 깨지는 경우 이 내용이 바뀔 수 있습니다.
libpkmn은 -Dshowdown을 사용하여 Pokémon Showdown과 호환되는 libpkmn-showdown 라이브러리를 생성하도록 빌드할 수 있습니다. 또한, 프로토콜 메시지 로깅은 -Dlog를 통해 활성화할 수 있습니다. 바이너리 릴리스에서 사용 가능한 libpkmn과 libpkmn-showdown 객체는 기본적으로 모두 -Dlog 플래그로 컴파일됩니다.
@pkmn/engine
드라이버 코드는 npm에서 설치할 수 있습니다:
$ npm install @pkmn/engine
드라이버가 유용하려면 node_modules/@pkmn/engine/build/lib에서 컴파일된 Node/WASM 애드온을 찾을 수 있어야 합니다. 패키지를 설치하면 postinstall 라이프사이클 스크립트가 실행되며, 이 스크립트는 호환 가능한 zig 컴파일러를 확인하고 (최소 버전에 대한 내용은 앞서 참조), 찾을 수 없는 경우 node_module/@pkmn/engine/build/bin에 다운로드합니다. 또한 애드온을 네이티브로 성공적으로 빌드하는 데 필요한 Node 헤더도 확인하고 (필요한 경우) 다운로드합니다.
[!중요]
만약 npm을 --ignore-scripts로 설정했거나 (또는 npm v12+를 사용하며 @pkmn/engine을 npm approve-scripts @pkmn/engine으로 승인하지 않은 경우) 반드시 npx install-pkmn-engine을 직접 실행하거나 애드온을 수동으로 빌드하여 아티팩트를 예상 경로에 배치해야 합니다.
pkmn
pkmn을 포함하려면 zig fetch --save를 실행하여 프로젝트의 build.zig.zon에 종속성으로 추가합니다:
$ zig fetch --save https://github.com/pkmn/engine/archive/RELEASE.tar.gz
RELEASE를 사용하려는 릴리스의 태그(예: 0.1.0 또는 nightly)나 특정 커밋 해시로 대체합니다. build.zig.zon에 종속성을 추가한 후에는 build.zig에서 pkmn 모듈을 가져올 수 있습니다:
const std = @import("std");
pub fn build(b: *std.Build) void {
...
pkmn 패키지는 Pokémon Showdown 호환성 모드 또는 프로토콜 메시지 로깅 활성화 여부와 같은 다양한 옵션으로 구성할 수 있습니다. 또는 pkmn_options 루트 소스 파일 선언을 통해 옵션을 설정할 수도 있습니다. 빌드 또는 루트 옵션을 통해서도 조정할 수 있는 여러 문서화되지 않은 내부 옵션들이 있지만, 이 옵션들은 공식적으로 지원되지 않으며 정확성에 영향을 미치고 경고 없이 의미나 동작이 변경될 수 있습니다. 사용 시 주의하십시오.
pub const pkmn_options = .{ .showdown = true, .log = true };
사용법
각 포켓몬 세대마다 엔진은 두 가지 함수를 가진 배틀 구조를 제공합니다. 한 함수는 양 플레이어의 선택에 따라 배틀 상태를 update하는 함수이며, 다른 하나는 해당 결정 지점에서 어떤 choices가 유효한지 정의하는 함수입니다 (배틀 시작 시 양쪽 플레이어 모두 파티 멤버를 교체 투입하기 위해 첫 번째 선택으로 '패스'해야 합니다). 만약 -Dlog 프로토콜 로깅이 활성화되면, 각 업데이트는 로그를 생성하며 이는 버퍼로 디코딩될 수 있습니다 (LOGS_SIZE 상수는 올바른 크기의 버퍼를 쉽게 할당할 수 있도록 제공됩니다). 각 update는 배틀이 종료되었는지 또는 각 플레이어에게 사용 가능한 선택 유형을 나타내는 결과를 반환합니다.
각 결정 지점에서 풍부한 요청 객체를 제공하는 Pokémon Showdown의 SIM-PROTOCOL과는 달리, pkmn 엔진은 이전 update의 결과와 배틀 상태를 기반으로 가능한 선택들을 온디맨드(on demand)로 계산합니다 (CHOICES_SIZE는 choices에 전달되는 버퍼를 초기화하기에 좋은 크기입니다). choices가 반환한 옵션에 없는 선택으로 배틀을 업데이트하려고 시도하는 것은 정의되지 않은 동작이며 상태를 손상시키거나 엔진 충돌을 유발할 수 있습니다.
전투는 어느 시점부터든 진행될 수 있지만, 아직 시작되지 않은 전투를 새로 초기화하려면 턴 카운트와 활성 포켓몬은 0으로 설정되어야 합니다 (드라이버 코드가 이 부분을 처리해야 합니다). 대부분의 드라이버 코드에는 전투 초기화를 편리하게 할 수 있도록 도와주는 유틸리티가 제공되어야 합니다. 사용 중인 바인딩에 대한 관련 문서를 확인하고 예제를 참고하십시오. 엔진의 프로토콜 문서에서는 업데이트의 세부 사항과 발생할 수 있는 잠재적인 로그에 대해 더 자세히 설명합니다.
아래 코드 스니펫들은 pkmn 엔진을 어떻게 사용할 수 있는지 광범위하게 보여주기 위한 것입니다. - examples 디렉터리에는 주석이 달리고 실행 가능한 전체 코드가 포함되어 있습니다.
C
pkmn.h는 libpkmn의 C API를 내보냅니다. 심볼들은 이름 충돌을 방지하기 위해 모두 pkmn_으로 접두사 지정됩니다. 만약 -Dlog가 활성화되고 로깅에서 오류가 발생하면, 해당 오류는 pkmn_result에 인코딩되며 pkmn_error로 확인할 수 있습니다.
#include <pkmn.h>
pkmn_battle_options options;
...
(전체 코드)
C API는 불투명한(opaque) 전투 객체를 생성하거나 접근하기 위한 유틸리티를 내보내지 않습니다. 대신, 다른 언어에서 더 인체공학적인 바인딩을 위한 기반으로 사용하도록 의도되었습니다 (C에서 네임스페이스와 비트 필드가 구현 정의 레이아웃을 갖는 것이 libpkmn이 노출하기로 선택한 내용의 부족함에 기여하는 주요 요인입니다).
JavaScript / TypeScript
@pkmn/engine은 @pkmn/data 패키지에 의존하며, 이 패키지는 Dex 구현체도 함께 제공받아야 합니다. Battle.create 함수를 사용하여 처음부터 Battle을 초기화할 수 있으며, 이미 진행 중인 전투를 다시 인스턴스화하려면 Battle.restore를 사용할 수 있습니다. 로깅이 활성화된 경우, 출력은 Log.parse를 통해 Pokémon Showdown 프로토콜로 변환될 수 있습니다.
import {Dex} from '@pkmn/dex';
import {Generations} from '@pkmn/data';
import {Battle, Choice} from '@pkmn/engine';
...
(full code)
기본적으로 @pkmn/engine 패키지는 -Dshowdown 옵션으로 엔진을 컴파일하지만, install-pkmn-engine를 직접 실행하고 --options를 전달하여 이 기본값을 재정의함으로써 드라이버가 사용할 확장 기능의 다양한 구성을 빌드할 수 있습니다. 드라이버는 Pokémon Showdown 호환성이 있거나 없거나 하는 두 가지 구성 모두를 동시에 지원할 수 있습니다. 업데이트 시, post-install 스크립트는 발견된 모든 확장 기능을 원래 사용했던 것과 동일한 구성 매개변수로 재빌드를 시도하므로, 라이브러리를 최신 버전으로 업데이트해도 원활합니다.
네이티브 엔진 코드를 사용함에도 불구하고, @pkmn/engine 코드는 WebAssembly를 지원하는 브라우저에서도 작동하도록 설계되었습니다. examples 디렉토리에서 npm run start:web을 실행하면 브라우저에서 엔진이 실행되는 것을 시연하는 데 사용될 수 있는 서버가 시작됩니다.
Zig
pkmn Zig 패키지는 상태 인스턴스화(state instantiation)를 단순화하기 위한 헬퍼 메서드를 노출하며, 로깅이 활성화된 경우 모든 Writer를 사용하여 표준 출력이나 버퍼에 쉽게 출력할 수 있습니다.
const std = @import("std");
const pkmn = @import("pkmn");
...
(full code)
Zig 패키지는 또한 FixedRNG와 같이 다른 곳에 노출하기 어려운 일부 API를 지원합니다. 이는 배틀의 정확한 RNG 프레임(특정 결과/효과가 항상 발생하도록 보장하는 데 유용할 수 있음)을 완전히 지정할 수 있게 해주지만, 그렇게 하는 것은 Battle 객체의 크기를 변경시킵니다.
기타
다른 언어로 엔진을 사용하려는 개발자들은 기존 문서를 바탕으로 libpkmn에 대한 바인딩(bindings)을 작성하는 것이 비교적 간단할 것입니다. 하지만 과정을 더욱 단순화하기 위해 src/data에는 모든 포켓몬 데이터, 구조체 크기 및 오프셋, 그리고 참조 드라이버 코드에서 사용되는 프로토콜 정보의 JSON 덤프가 포함되어 있습니다. 다음은 pkmn organization 외부 개발자들이 작성한 알려진 libpkmn 바인딩 목록으로 도움이 될 수 있지만 (이 프로젝트들이 반드시 최신/완벽/정확하지 않을 수 있다는 점에 유의하십시오 - 이 목록에 포함되는 것이 지지함을 의미하는 것은 아닙니다):
pkmn-debug
@pkmn/engine 패키지에는 엔진에서 사용되는 이진 데이터 구조 및 프로토콜을 디코딩하고 디버깅에 사용할 수 있는 독립 웹페이지를 출력하는 pkmn-debug 도구가 포함되어 있습니다. 로컬에 @pkmn/engine 패키지가 설치된 폴더에서 이 도구를 사용하려면 npx pkmn-debug을 사용할 수 있지만, npx 없이 어디서든 이 도구를 사용할 수 있도록 패키지를 전역으로 설치하는 것이 더 좋을 수도 있습니다:
$ npm install --global @pkmn/engine
기본적으로 pkmn-debug은 표준 입력에서 이진 디버그 프로토콜을 읽고 표준 출력에 HTML을 출력할 것으로 예상합니다:
$ <cmd> | pkmn-debug > index.html
대안으로, pkmn-debug에 단일 파일 이름 인수가 전달되면 해당 파일에서 읽습니다:
$ pkmn-debug <file> > index.html