GS2-StateMachine SDK for Game Engine API 레퍼런스
모델
EzStatus
스테이트 머신의 상태
특정 사용자에 대한 스테이트 머신의 실행 인스턴스를 나타냅니다. 변수, 서브 스테이트 머신용 콜 스택, 전이 횟수, 난수 상태를 포함한 현재 실행 상태를 추적합니다. 스테이터스는 Running, Wait, Pass(성공), Error 상태를 전이합니다.
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| statusId | string | ※ | ~ 1024자 | 스테이트 머신 상태 GRN
※ 서버가 자동으로 설정 | ||||||||||||
| name | string | ✓ | UUID | ~ 36자 | 스테이터스 이름 스테이트 머신 상태의 고유한 이름을 보유합니다. 이름은 UUID(Universally Unique Identifier) 형식으로 자동 생성되며, 각 스테이트 머신의 상태를 식별하는 데 사용됩니다. | |||||||||||
| enableSpeculativeExecution | 문자열 열거형 enum { “enable”, “disable” } | “disable” | 투기적 실행을 활성화할지 여부 활성화하면 스테이트 머신 정의와 난수 상태가 이 Status 엔티티에 포함됩니다. 이를 통해 클라이언트가 서버 확인 전에 로컬에서 전이를 시뮬레이션할 수 있어 체감 지연을 줄일 수 있습니다.
| |||||||||||||
| stateMachineDefinition | string | {enableSpeculativeExecution} == “enable” | ~ 16777216자 | 스테이트 머신 정의 투기적 실행을 위해 이 스테이터스에 포함된 GSL 정의입니다. enableSpeculativeExecution이 활성화된 경우에만 존재합니다. 일반적인 API 응답에서는 필터링되며, 클라이언트 측 시뮬레이션에 필요한 경우에만 포함됩니다. ※ enableSpeculativeExecution이(가) “enable” 이면 활성화 | ||||||||||||
| randomStatus | EzRandomStatus | {enableSpeculativeExecution} == “enable” | 난수 상태 이 실행 인스턴스의 난수 생성 상태입니다. 투기적 실행 시 클라이언트와 서버에서 결정론적인 난수 동작을 보장하기 위해 사용됩니다. enableSpeculativeExecution이 활성화된 경우에만 존재합니다. ※ enableSpeculativeExecution이(가) “enable” 이면 활성화 | |||||||||||||
| stacks | List<EzStackEntry> | [] | 0 ~ 1024 items | 스택 서브 스테이트 머신 호출의 콜 스택입니다. 스테이트 머신이 서브 스테이트 머신을 호출하면 호출한 쪽의 스테이트 머신 이름과 반환 태스크가 푸시됩니다. 서브 스테이트 머신이 완료되면 엔트리가 팝되고 반환 태스크에서 실행이 재개됩니다. | ||||||||||||
| variables | List<EzVariable> | [] | 0 ~ 1000 items | 스테이트 머신별 상태 변수 콜 계층 내 각 스테이트 머신의 현재 변수 값입니다. 각 엔트리는 스테이트 머신 이름과, int, float, string, bool, array, map 타입을 지원하는 JSON 직렬화된 값을 보유합니다. 변수는 동일한 실행 인스턴스 내 상태 전이를 거쳐 유지됩니다. | ||||||||||||
| status | 문자열 열거형 enum { “Running”, “Wait”, “Pass”, “Error” } | “Running” | 스테이터스 이 스테이트 머신 인스턴스의 현재 실행 상태입니다. “Running"은 머신이 전이를 처리 중임을 의미합니다. “Wait"는 머신이 외부 이벤트(emit)를 대기 중임을 의미합니다. “Pass"는 정상적으로 완료되었음을 의미합니다. “Error"는 에러로 종료되었음을 의미합니다.
| |||||||||||||
| lastError | string | ~ 1024자 | 마지막 에러 마지막으로 발생한 에러의 메시지입니다. 스테이터스가 “Error"로 전이되었을 때 설정됩니다. 스테이트 머신이 이상 종료된 원인의 상세 내용을 포함합니다. | |||||||||||||
| transitionCount | int | 0 | 0 ~ 2147483645 | 전이 횟수 이 실행 인스턴스에서 수행된 상태 전이의 총 횟수입니다. 전이할 때마다 증가합니다. 이 값이 1000을 초과하면 무한 루프를 방지하기 위해 스테이트 머신은 에러로 종료됩니다. |
EzStackEntry
스택 엔트리
서브 스테이트 머신의 콜 스택 내 하나의 엔트리를 나타냅니다. 스테이트 머신이 서브 스테이트 머신을 호출하면 호출한 쪽의 이름과 반환 태스크가 스택에 푸시됩니다. 서브 스테이트 머신이 완료되면 팝된 엔트리의 반환 태스크에서 실행이 재개됩니다.
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| stateMachineName | string | ✓ | ~ 128자 | 스테이트 머신 이름 이 스택 엔트리를 푸시한 호출 측 스테이트 머신의 이름입니다. 서브 스테이트 머신에서 돌아올 때 어떤 스테이트 머신의 컨텍스트를 복원할지 식별하는 데 사용됩니다. | ||
| taskName | string | ✓ | ~ 128자 | 태스크 이름 서브 스테이트 머신이 완료되었을 때 돌아갈 태스크(상태)의 이름입니다. 호출 측 스테이트 머신의 이 태스크에서 실행이 재개됩니다. |
EzVariable
스테이트 머신별 상태 변수
호출 계층 내 특정 스테이트 머신의 현재 변수 상태를 보유합니다. 값은 int, float, string, bool, array, map 데이터 타입을 지원하는 JSON 직렬화 표현입니다.
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| stateMachineName | string | ✓ | ~ 128자 | 스테이트 머신 이름 이들 변수를 소유하는 스테이트 머신의 이름입니다. 중첩된 호출 계층에서는 각 스테이트 머신이 이 이름으로 식별되는 독립적인 변수 스코프를 가집니다. | ||
| value | string | ✓ | ~ 1048576자 | 값 이 스테이트 머신의 JSON 직렬화된 변수 값입니다. int, float, string, bool, array, map 데이터 타입을 지원합니다. 스테이트 머신이 전이나 액션을 처리할 때 갱신됩니다. |
EzChangeStateEvent
상태 변경 이벤트
스테이트 머신 내에서 발생한 상태 전이를 기록합니다. 전이 대상 태스크 이름, 무결성 검증용 해시, 전이가 발생한 타임스탬프를 포함합니다.
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| taskName | string | ✓ | ~ 128자 | 태스크 이름 스테이트 머신이 전이한 대상 태스크(상태)의 이름입니다. | ||
| hash | string | ✓ | ~ 64자 | 해시 상태 전이의 무결성을 검증하기 위한 해시 값입니다. 전이가 올바르게 수행되었고 상태가 일관되어 있음을 검증하는 데 사용됩니다. | ||
| timestamp | long | ✓ | 타임스탬프 |
EzEmitEvent
메시지 전송 이벤트
외부 액션을 트리거하기 위해 스테이트 머신이 전송하는 메시지를 나타냅니다. 이벤트 이름은 액션의 종류를 식별하고, 파라미터는 액션별 데이터를 제공합니다.
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| event | string | ✓ | ~ 128자 | 이벤트 이름 전송된 이벤트의 종류를 식별하는 이름입니다. 보상 지급이나 리소스 소비 등, 어떤 외부 액션을 호출할지 판단하는 데 사용됩니다. | ||
| parameters | string | ✓ | ~ 1024자 | 파라미터 전송된 이벤트와 함께 전달되는 파라미터입니다. 이 이벤트에 의해 트리거되는 외부 액션을 설정하는 데 사용되는, 액션별 데이터를 직렬화된 형식으로 포함합니다. | ||
| timestamp | long | ✓ | 타임스탬프 |
EzEvent
이벤트
스테이트 머신 실행 중에 발생한 이벤트를 나타냅니다. 상태 변경 이벤트(상태 전이를 기록)이거나 emit 이벤트(외부 액션을 트리거하기 위한 메시지 전송) 중 하나입니다.
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| eventType | 문자열 열거형 enum { “change_state”, “emit” } | ✓ | 이벤트 종류 이벤트의 종류입니다. “change_state"는 스테이트 머신 내의 상태 전이를 기록합니다. “emit"은 보상 지급이나 리소스 소비 등의 외부 액션을 트리거하기 위한 메시지 전송을 나타냅니다.
| |||||||||
| changeStateEvent | EzChangeStateEvent | {eventType} == “change_state” | ✓※ | 상태 변경 ※ eventType이(가) “change_state” 이면 필수 | ||||||||
| emitEvent | EzEmitEvent | {eventType} == “emit” | ✓※ | 메시지 전송 ※ eventType이(가) “emit” 이면 필수 |
EzRandomStatus
난수 상태
스테이트 머신 실행 인스턴스의 난수 생성 상태를 관리합니다. 시드 값과 카테고리별 사용 현황 추적을 포함합니다. 추측 실행 시 클라이언트와 서버 간에 결정론적인 난수 동작을 보장하기 위해 사용됩니다.
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| seed | long | ✓ | 0 ~ 4294967294 | 난수 시드 스테이트 머신 실행 내에서 결정론적인 난수 생성을 위한 시드 값입니다. | ||
| used | List<EzRandomUsed> | 0 ~ 1000 items | 사용된 난수 목록 카테고리별로 소비된 난수를 추적합니다. 각 카테고리는 난수 사용의 서로 다른 목적을 나타내며, 추측 재실행 시 일관성을 유지하기 위한 독립적인 추적을 가능하게 합니다. |
EzRandomUsed
사용한 난수
스테이트 머신 실행 내 특정 카테고리에서 소비된 난수의 수를 추적합니다. 각 카테고리는 서로 다른 목적을 위한 독립적인 난수 추적을 가능하게 합니다.
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| category | long | ✓ | 0 ~ 4294967294 | 카테고리 난수 사용 카테고리의 숫자 식별자입니다. 각 카테고리는 난수 소비를 독립적으로 추적하여, 스테이트 머신이 서로 다른 목적에 별도의 난수 시퀀스를 사용할 수 있도록 합니다. | ||
| used | long | ✓ | 0 ~ 4294967294 | 사용 횟수 이 카테고리에서 소비된 난수의 수입니다. 이 카테고리의 시퀀스에서 난수가 뽑힐 때마다 증가합니다. |
EzVerifyActionResult
검증 액션 실행 결과
EzConsumeActionResult
소비 액션 실행 결과
EzAcquireActionResult
획득 액션 실행 결과
EzTransactionResult
트랜잭션 실행 결과
서버 사이드에서 트랜잭션 자동 실행 기능을 이용하여 실행된 트랜잭션의 실행 결과
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| transactionId | string | ✓ | 36 ~ 36자 | 트랜잭션 ID | ||
| verifyResults | List<EzVerifyActionResult> | 0 ~ 10 items | 검증 액션의 실행 결과 목록 | |||
| consumeResults | List<EzConsumeActionResult> | [] | 0 ~ 10 items | 소비 액션의 실행 결과 목록 | ||
| acquireResults | List<EzAcquireActionResult> | [] | 0 ~ 100 items | 획득 액션 실행 결과 리스트 |
메서드
emit
이벤트를 전송하여 상태 전이를 트리거한다
스테이트 머신에 이름이 지정된 이벤트를 전송하여, 정의된 전이 규칙에 따라 현재 상태에서 다음 상태로 이동시킵니다.
게임 클라이언트가 스테이트 머신을 진행시키는 주된 방법입니다. 예를 들면:
- 플레이어가 퀘스트 다이얼로그에서 “수락"을 탭 → “accept” 이벤트 전송 → 상태가 “제시 중"에서 “진행 중"으로 변경
- 플레이어가 보스를 물리침 → “boss_defeated” 이벤트 전송 → 상태가 “보스 스테이지"에서 “완료"로 변경
- 플레이어가 스토리에서 선택지를 선택 → “choose_path_a” 이벤트 전송 → 선택한 분기 경로의 상태로 전이
추가 데이터를 JSON 인수(args)로 전달할 수 있습니다. 예를 들어 “submit_answer” 이벤트를 전송할 때 {“answer”: “B”}를 args에 포함할 수 있습니다.
스테이트 머신은 현재 상태에서 유효한 이벤트만 받아들입니다. 현재 상태에서 정의되지 않은 이벤트를 전송하면 오류가 반환되며 전이는 발생하지 않습니다.
Request
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128자 | 네임스페이스 이름 네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. | ||
| gameSession | GameSession | ✓ | GameSession | |||
| statusName | string | ✓ | ~ 36자 | 상태 이름 | ||
| eventName | string | ✓ | ~ 36자 | 이벤트 이름 | ||
| args | string | “{}” | ~ 4096자 | 스테이트 머신에 전달할 인자 |
Result
| 타입 | 설명 | |
|---|---|---|
| item | EzStatus | 스테이트 머신 상태 |
구현 예제
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var result = await domain.EmitAsync(
eventName: "event-0001",
args: "{\"value1\": \"value1\", \"value2\": 2.0, \"value3\": 3}"
);
var item = await result.ModelAsync(); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var future = domain.EmitFuture(
eventName: "event-0001",
args: "{\"value1\": \"value1\", \"value2\": 2.0, \"value3\": 3}"
);
yield return future;
if (future.Error != null)
{
onError.Invoke(future.Error, null);
yield break;
}
var future2 = future.Result.ModelFuture();
yield return future2;
if (future2.Error != null)
{
onError.Invoke(future2.Error, null);
yield break;
}
var result = future2.Result; const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Status(
"status-0001" // statusName
);
const auto Future = Domain->Emit(
"event-0001", // eventName
"{\"value1\": \"value1\", \"value2\": 2.0, \"value3\": 3}" // args
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
return false;
}
// 변경된 값 / 결과 값을 취득
const auto Future2 = Future->GetTask().Result()->Model();
Future2->StartSynchronousTask();
if (Future2->GetTask().IsError())
{
return Future2->GetTask().Error();
}
const auto Result = Future2->GetTask().Result();var domain = ez.state_machine.namespace_(
"namespace-0001"
).me(game_session).status(
"status-0001"
)
var async_result = await domain.emit(
"event-0001", # event_name
"{\"value1\": \"value1\", \"value2\": 2.0, \"value3\": 3}" # args
)
if async_result.error != null:
push_error(str(async_result.error))
return
var result = async_result.resultexit
완료된 스테이트 머신을 정리한다
실행이 종료된 스테이트 머신 인스턴스를 삭제합니다. 스테이트 머신의 상태가 “Pass”(정상 완료) 또는 “Error”(실패)인 경우에만 호출할 수 있습니다.
스테이트 머신이 종료 상태에 도달한 후에도, Exit로 명시적으로 삭제하기 전까지는 시스템에 남아 있습니다. 이를 통해 다음과 같은 작업이 가능합니다:
- 플레이어에게 완료 결과를 표시(예: “퀘스트 클리어!” 화면)
- 최종 상태와 변수를 읽어 보상을 결정
- 오류 상태를 처리하고 다음 동작을 결정
일반적인 흐름:
- 스테이트 머신이 종료 상태에 도달 → 상태가 “Pass"가 됨
- 게임이 최종 상태를 읽고 플레이어에게 보상을 부여
- 게임이 완료 화면을 표시
- 플레이어가 화면을 닫음 → 게임이 Exit를 호출하여 정리
Running 상태의 스테이트 머신에는 Exit를 호출할 수 없습니다. 실행 중인 스테이트 머신을 강제로 정지해야 하는 경우에는 서버 측 작업이 필요합니다.
Request
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128자 | 네임스페이스 이름 네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. | ||
| gameSession | GameSession | ✓ | GameSession | |||
| statusName | string | ✓ | ~ 36자 | 상태 이름 |
Result
| 타입 | 설명 | |
|---|---|---|
| item | EzStatus | 종료된 스테이트 머신 상태 |
구현 예제
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var result = await domain.ExitAsync(
); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var future = domain.ExitFuture(
);
yield return future;
if (future.Error != null)
{
onError.Invoke(future.Error, null);
yield break;
} const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Status(
"status-0001" // statusName
);
const auto Future = Domain->Exit(
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
return false;
}
const auto Result = Future->GetTask().Result();var domain = ez.state_machine.namespace_(
"namespace-0001"
).me(game_session).status(
"status-0001"
)
var async_result = await domain.exit(
)
if async_result.error != null:
push_error(str(async_result.error))
return
var result = async_result.resultgetStatus
특정 스테이트 머신 인스턴스의 현재 상태를 취득한다
특정 스테이트 머신 인스턴스의 상세 정보를 취득합니다. 현재 어떤 상태에 있는지, 저장된 변수 등이 포함됩니다.
워크플로의 현재 진행 상황을 플레이어에게 표시할 때 사용합니다. 예를 들면:
- 퀘스트 트래커에서 “현재 단계: 몬스터 3마리 처치(2/3)” 표시
- 튜토리얼 인디케이터로 플레이어가 어느 단계에 있는지 표시
- 프로세스 상태가 진행 중인지, 완료되었는지, 오류가 발생했는지 표시
응답에는 다음이 포함됩니다:
- 현재 상태 이름: 머신이 지금 어떤 상태에 있는지
- 변수: 스테이트 머신에 저장된 데이터(예: 진행 카운터, 선택 결과)
- 상태: 머신이 Running(동작 중), Pass(완료), Error(오류) 중 어느 것인지
- 스택 트레이스: 상태 전이 이력(디버깅에 유용)
Request
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128자 | 네임스페이스 이름 네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. | ||
| gameSession | GameSession | ✓ | GameSession | |||
| statusName | string | ✓ | ~ 36자 | 상태 이름 |
Result
| 타입 | 설명 | |
|---|---|---|
| item | EzStatus | 스테이트 머신 상태 |
구현 예제
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var item = await domain.ModelAsync(); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var future = domain.ModelFuture();
yield return future;
var item = future.Result; const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Status(
"status-0001" // statusName
);
const auto Future = Domain->Model();
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
return false;
}var domain = ez.state_machine.namespace_(
"namespace-0001"
).me(game_session).status(
"status-0001"
)
var async_result = await domain.model()
if async_result.error != null:
push_error(str(async_result.error))
return
var result = async_result.result값 변경 이벤트 핸들링
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
// 이벤트 핸들링 시작
var callbackId = domain.Subscribe(
value => {
// 값이 변화했을 때 호출됨
// value에는 변경 후의 값이 전달됨
}
);
// 이벤트 핸들링 정지
domain.Unsubscribe(callbackId); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
// 이벤트 핸들링 시작
var callbackId = domain.Subscribe(
value => {
// 값이 변화했을 때 호출됨
// value에는 변경 후의 값이 전달됨
}
);
// 이벤트 핸들링 정지
domain.Unsubscribe(callbackId); const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Status(
"status-0001" // statusName
);
// 이벤트 핸들링 시작
const auto CallbackId = Domain->Subscribe(
[](TSharedPtr<Gs2::StateMachine::Model::FStatus> value) {
// 값이 변화했을 때 호출됨
// value에는 변경 후의 값이 전달됨
}
);
// 이벤트 핸들링 정지
Domain->Unsubscribe(CallbackId);var domain = ez.state_machine.namespace_(
"namespace-0001"
).me(game_session).status(
"status-0001"
)
# 이벤트 핸들링 시작
var callback_id = domain.subscribe_model(func(value):
# 값이 변화했을 때 호출됨
# value에는 변경 후의 값이 전달됩니다
pass
)
# 이벤트 핸들링 정지
domain.unsubscribe_model(callback_id)이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.
로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.
따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.
listStatuses
플레이어의 스테이트 머신 인스턴스 목록을 취득한다
현재 플레이어에게 속한 모든 스테이트 머신 인스턴스를 취득합니다.
스테이트 머신은 서버에서 관리되는 워크플로로, 플레이어가 일련의 단계(상태)를 진행하는 과정을 추적합니다. 각 단계에서는 액션 실행, 플레이어 입력 대기, 조건에 따른 분기가 가능합니다.
스테이트 머신의 주요 사용 예:
- 퀘스트 진행: “퀘스트 수락” → “진행 중” → “보스전” → “완료” → “보상 수령”
- 튜토리얼 흐름: “환영” → “이동 튜토리얼” → “전투 튜토리얼” → “가챠 튜토리얼” → “완료”
- 기간 한정 이벤트: 제한 시간이 있는 여러 단계로 구성된 이벤트 프로세스
각 스테이트 머신 인스턴스는 다음 세 가지 상태 중 하나를 가집니다:
- Running: 스테이트 머신이 동작 중이며 다음 이벤트를 대기하고 있는 상태
- Pass: 스테이트 머신이 정상적으로 완료된 상태(종료 상태에 도달)
- Error: 스테이트 머신에서 오류가 발생한 상태
상태로 필터링할 수 있습니다. 예를 들어 퀘스트 화면에 활성(Running) 상태의 스테이트 머신만 표시하거나, 정리가 필요한 완료된 것을 찾을 때 사용할 수 있습니다.
Request
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128자 | 네임스페이스 이름 네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. | ||||||||||||
| gameSession | GameSession | ✓ | GameSession | |||||||||||||
| status | 문자열 열거형 enum { “Running”, “Wait”, “Pass”, “Error” } | 스테이터스 이 스테이트 머신 인스턴스의 현재 실행 상태입니다. “Running"은 머신이 전이를 처리 중임을 의미합니다. “Wait"는 머신이 외부 이벤트(emit)를 대기 중임을 의미합니다. “Pass"는 정상적으로 완료되었음을 의미합니다. “Error"는 에러로 종료되었음을 의미합니다.
| ||||||||||||||
| pageToken | string | ~ 1024자 | 데이터 취득을 시작할 위치를 지정하는 토큰 | |||||||||||||
| limit | int | 30 | 1 ~ 1000 | 조회한 데이터 건수 |
Result
| 타입 | 설명 | |
|---|---|---|
| items | List<EzStatus> | 스테이트 머신 상태 목록 |
| nextPageToken | string | 목록의 나머지를 취득하기 위한 페이지 토큰 |
구현 예제
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var items = await domain.StatusesAsync(
status: "Running"
).ToListAsync(); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var it = domain.Statuses(
status: "Running"
);
List<EzStatus> items = new List<EzStatus>();
while (it.HasNext())
{
yield return it.Next();
if (it.Error != null)
{
onError.Invoke(it.Error, null);
break;
}
if (it.Current != null)
{
items.Add(it.Current);
}
else
{
break;
}
} const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
);
const auto It = Domain->Statuses(
"Running" // status
);
TArray<Gs2::UE5::StateMachine::Model::FEzStatusPtr> Result;
for (auto Item : *It)
{
if (Item.IsError())
{
return false;
}
Result.Add(Item.Current());
}값 변경 이벤트 핸들링
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
// 이벤트 핸들링 시작
var callbackId = domain.SubscribeStatuses(
() => {
// 리스트의 요소가 변화했을 때 호출됨
}
);
// 이벤트 핸들링 정지
domain.UnsubscribeStatuses(callbackId); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
// 이벤트 핸들링 시작
var callbackId = domain.SubscribeStatuses(
() => {
// 리스트의 요소가 변화했을 때 호출됨
}
);
// 이벤트 핸들링 정지
domain.UnsubscribeStatuses(callbackId); const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
);
// 이벤트 핸들링 시작
const auto CallbackId = Domain->SubscribeStatuses(
[]() {
// 리스트의 요소가 변화했을 때 호출됨
}
);
// 이벤트 핸들링 정지
Domain->UnsubscribeStatuses(CallbackId);이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.
로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.
따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.
report
클라이언트 측 스테이트 머신 실행 결과를 서버로 전송하여 검증받는다
게임 클라이언트에서 로컬로 처리된 이벤트의 배치를 서버로 전송하여 검증을 받습니다.
이는 “추측 실행(speculative execution)“이라 불리는 최적화 기능입니다. 모든 이벤트마다 Emit을 호출하는(매번 네트워크 지연이 발생하는) 대신, 클라이언트가 로컬에서 스테이트 머신을 실행하고 여러 이벤트를 한꺼번에 처리한 뒤, 그 결과를 한 번의 호출로 서버에 전송합니다.
추측 실행의 작동 방식:
- 클라이언트가 스테이트 머신 정의의 로컬 사본을 보유합니다
- 이벤트가 연속으로 발생하는 경우(예: 게임플레이 중), 클라이언트는 서버의 응답을 기다리지 않고 로컬에서 처리합니다
- 이벤트를 배치 처리한 후, 클라이언트가 Report를 호출하여 모든 이벤트를 서버로 전송합니다
- 서버는 이벤트를 재생(replay)하고 최종 상태가 클라이언트가 보고한 내용과 일치하는지 검증합니다
- 상태가 일치하면 서버가 결과를 승인합니다. 일치하지 않는 경우(예: 클라이언트가 변조된 경우) StateMismatch 오류가 반환됩니다
다음과 같은 성능이 중요한 시나리오에서 유용합니다:
- 서버 응답을 기다리면 지연이 발생하는 빠른 템포의 게임플레이
- 플레이어가 일시적으로 접속이 끊길 수 있는 오프라인 지원 흐름
- 다수의 빠른 상태 전이를 배치 처리하는 경우
주의: 이 API를 사용하려면 네임스페이스에서 추측 실행이 활성화되어 있어야 합니다.
Request
| 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128자 | 네임스페이스 이름 네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. | ||
| gameSession | GameSession | ✓ | GameSession | |||
| statusName | string | ✓ | ~ 36자 | 상태 이름 | ||
| events | List<EzEvent> | 0 ~ 1000 items | 이벤트 목록 |
Result
| 타입 | 설명 | |
|---|---|---|
| item | EzStatus | 스테이트 머신 상태 |
Error
이 API에는 특별한 예외가 정의되어 있습니다.
GS2-SDK for Game Engine에서는 게임 내에서 핸들링이 필요할 것으로 예상되는 에러를, 일반적인 예외에서 파생된 특수화된 예외로 제공하여 다루기 쉽게 하고 있습니다.
일반적인 에러의 종류와 핸들링 방법은 여기 문서를 참고해 주세요.
| 타입 | 베이스 클래스 | 설명 |
|---|---|---|
| StateMismatchException | BadRequestException | 리포트 검증 결과 상태가 일치하지 않습니다 |
구현 예제
try {
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var result = await domain.ReportAsync(
events: new List<Gs2.Unity.Gs2StateMachine.Model.EzEvent> {
new Gs2.Unity.Gs2StateMachine.Model.EzEvent() {
EventType = "emit",
EmitEvent =
new Gs2.Unity.Gs2StateMachine.Model.EzEvent() {
Event = "message",
Parameters = "{\"payload\": \"Hello World\"}",
Timestamp = 1000,
},
},
}
);
var item = await result.ModelAsync();
} catch(Gs2.Gs2StateMachine.Exception.StateMismatchException e) {
// State of the verification result of the report is inconsistent.
} var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var future = domain.ReportFuture(
events: new List<Gs2.Unity.Gs2StateMachine.Model.EzEvent> {
new Gs2.Unity.Gs2StateMachine.Model.EzEvent() {
EventType = "emit",
EmitEvent =
new Gs2.Unity.Gs2StateMachine.Model.EzEvent() {
Event = "message",
Parameters = "{\"payload\": \"Hello World\"}",
Timestamp = 1000,
},
},
}
);
yield return future;
if (future.Error != null)
{
if (future.Error is Gs2.Gs2StateMachine.Exception.StateMismatchException)
{
// State of the verification result of the report is inconsistent.
}
onError.Invoke(future.Error, null);
yield break;
}
var future2 = future.Result.ModelFuture();
yield return future2;
if (future2.Error != null)
{
onError.Invoke(future2.Error, null);
yield break;
}
var result = future2.Result; const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Status(
"status-0001" // statusName
);
const auto Future = Domain->Report(
[]
{
auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::StateMachine::Model::FEzEvent>>>();
v->Add(
MakeShared<Gs2::UE5::StateMachine::Model::FEzEvent>()
->WithEventType(TOptional<FString>("emit"))
->WithEmitEvent(MakeShared<Gs2::UE5::StateMachine::Model::FEzEmitEvent>()
->WithEvent(TOptional<FString>("message"))
->WithParameters(TOptional<FString>("{\"payload\": \"Hello World\"}"))
->WithTimestamp(TOptional<int32>(1000))
);
);
return v;
}() // events
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
auto e = Future->GetTask().Error();
if (e->IsChildOf(Gs2::StateMachine::Error::FStateMismatchError::Class))
{
// State of the verification result of the report is inconsistent.
}
return false;
}
// 변경된 값 / 결과 값을 취득
const auto Future2 = Future->GetTask().Result()->Model();
Future2->StartSynchronousTask();
if (Future2->GetTask().IsError())
{
return Future2->GetTask().Error();
}
const auto Result = Future2->GetTask().Result();var domain = ez.state_machine.namespace_(
"namespace-0001"
).me(game_session).status(
"status-0001"
)
var async_result = await domain.report(
[
Gs2StateMachineEzEvent.new()
.with_event_type("emit")
.with_emit_event(
Gs2StateMachineEzEmitEvent.new()
.with_event("message")
.with_parameters("{\"payload\": \"Hello World\"}")
.with_timestamp(1000)
),
] # events
)
if async_result.error != null:
if async_result.error is Gs2StateMachineStateMismatchException:
# 리포트 검증 결과 상태가 일치하지 않습니다
pass
push_error(str(async_result.error))
return
var result = async_result.result