> For the complete documentation index, see [llms.txt](/llms.txt)

# GS2-Matchmaking SDK for Game Engine API 레퍼런스

게임 엔진용 GS2-Matchmaking SDK의 모델 사양과 API 레퍼런스



## 모델

### EzGathering

개더링<br>

매치메이킹에 의해 모인 게임 플레이어 그룹을 나타내는 엔티티입니다.<br>
매치메이킹용 파라미터를 여러 개 가지고 있으며, 파라미터를 종합적으로 판단하여 플레이어를 그룹화합니다.<br>
플레이어는 자신의 역할·속성값·거부 리스트(함께 플레이하고 싶지 않은 사용자)를 지정하여 개더링에 참가합니다.<br>
참가 시에는 속성값 범위 조건, 역할의 정원, 화이트리스트 제한(allowUserIds)이 검증됩니다.<br>
모든 역할 슬롯이 정원에 도달하면 개더링은 완성 상태가 되어 매치메이킹이 완료됩니다.<br>
개더링 이름은 UUID 형식으로 자동 생성되며, 유효기간을 설정하여 자동 정리(클린업)하는 것도 가능합니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| gatheringId | string |  | ※ |  |  ~ 1024자 | 개더링GRN<br>※ 서버가 자동으로 설정 |
| name | string |  | ✓ | UUID |  ~ 128자 | 개더링 이름<br>개더링의 고유한 이름을 보유합니다.<br>이름은 UUID(Universally Unique Identifier) 형식으로 자동 생성되며, 개더링을 식별하기 위해 사용됩니다. |
| attributeRanges | [List&lt;EzAttributeRange&gt;](#ezattributerange) |  |  | [] | 0 ~ 5 items | 모집 조건<br>이 개더링에 참가하기 위해 플레이어가 충족해야 하는 속성 범위 조건의 목록입니다.<br>각 항목은 속성 이름과 허용되는 최소값·최대값 범위를 지정합니다.<br>플레이어 자신의 속성값이 이 범위 내에 있지 않으면 참가할 수 없습니다. 최대 5건. |
| capacityOfRoles | [List&lt;EzCapacityOfRole&gt;](#ezcapacityofrole) |  |  | [] | 1 ~ 5 items | 모집 슬롯 목록<br>이 개더링의 모집 슬롯을 정의합니다.<br>각 항목은 역할 이름, 그 별칭, 그리고 해당 역할에 참가 가능한 최대 인원수를 지정합니다.<br>모든 역할 슬롯이 정원에 도달하면 매치메이킹이 완료됩니다. 최소 1건, 최대 5건. |
| allowUserIds | List&lt;string&gt; |  |  | [] | 0 ~ 100 items | 참가 허용 사용자 ID 목록<br>이 게더링에 참가하는 것이 허용된 사용자 ID의 화이트리스트입니다.<br>지정한 경우, 목록에 포함된 사용자만 이 게더링의 매치메이킹에 참가할 수 있습니다.<br>친구 전용 매치메이킹이나 초대제 매치메이킹 시나리오에 유용합니다. 최대 100건. |
| metadata | string |  |  |  |  ~ 1024자 | 메타데이터<br>메타데이터에는 임의의 값을 설정할 수 있습니다.<br>이 값들은 GS2의 동작에는 영향을 주지 않으므로, 게임 내에서 사용하는 정보를 저장하는 용도로 사용할 수 있습니다. |
| expiresAt | long |  |  |  |  | 게더링 유효 기간<br>이 게더링이 자동으로 만료되어 삭제되는 시각입니다.<br>이 시각까지 매치메이킹이 완료되지 않으면 게더링은 정리됩니다.<br>지정하지 않은 경우, 매치메이킹이 완료되거나 수동으로 삭제될 때까지 게더링이 유지됩니다. |
| createdAt | long |  | ※ | 현재 시각 |  | 생성일시<br>UNIX 시간・밀리초<br>※ 서버가 자동으로 설정 |
| updatedAt | long |  | ※ | 현재 시각 |  | 최종 갱신일시<br>UNIX 시간・밀리초<br>※ 서버가 자동으로 설정 |

**관련 메서드:**
cancelMatchmaking - 매치메이킹을 취소하고 기어링에서 이탈합니다
createGathering - 매치메이킹용 방(개더링) 신규 생성
doMatchmaking - 참가 가능한 개더링을 검색하여 참가
earlyCompleteMatchmaking - 정원이 채워지지 않은 상태에서 매치메이킹을 조기 종료합니다
getGathering - 기어링의 현재 상태를 취득합니다
ping - 매치메이킹 대기 중 킵얼라이브를 전송합니다
updateGathering - 개더링의 모집 조건 변경


---

### EzRating

레이팅<br>

게임 플레이어별 현재 레이팅 값을 보유하는 엔티티입니다.<br>
플레이어가 처음 레이팅이 적용된 매치메이킹에 참가했을 때 자동으로 생성됩니다.<br>
레이팅은 Glicko-2 알고리즘을 사용하여 계산되며, 초기 레이트 값과 레이팅의 불확실성을 나타내는 Rating Deviation(rd)을 가집니다.<br>
대전 횟수가 늘어남에 따라 레이트 값은 플레이어의 실제 실력에 수렴해 갑니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| ratingId | string |  | ※ |  |  ~ 1024자 | 레이팅GRN<br>※ 서버가 자동으로 설정 |
| name | string |  | ✓ |  |  ~ 128자 | 레이팅 이름<br>레이팅 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| userId | string |  | ✓ |  |  ~ 128자 | 사용자ID |
| rateValue | float |  |  | 1500.0 | 0 ~ 65535.0 | 레이트 값<br>Glicko-2 알고리즘으로 계산된 플레이어의 현재 레이팅 점수입니다.<br>RatingModel에서 정의된 초기값(일반적으로 1500.0)이 기본값입니다.<br>대전 결과와 상대의 상대적인 실력에 따라 값이 증감합니다. |
| createdAt | long |  | ※ | 현재 시각 |  | 생성일시<br>UNIX 시간・밀리초<br>※ 서버가 자동으로 설정 |
| updatedAt | long |  | ※ | 현재 시각 |  | 최종 갱신일시<br>UNIX 시간・밀리초<br>※ 서버가 자동으로 설정 |

**관련 메서드:**
getRating - 특정 카테고리의 플레이어 레이팅 점수를 취득합니다
listRatings - 모든 레이팅 카테고리에 대한 플레이어의 레이팅 점수를 취득합니다


---

### EzJoinedSeasonGathering

참가 중인 시즌 게더링<br>

특정 시즌과 티어에서 플레이어가 어느 시즌 게더링에 참가하고 있는지를 추적하는 레코드입니다.<br>
플레이어가 시즌 게더링에 참가할 때 자동으로 생성되며, 플레이어의 현재 게더링을 빠르게 조회하기 위한 인덱스 역할을 합니다.<br>
각 플레이어는 시즌과 티어의 조합마다 최대 1개의 시즌 게더링에 소속될 수 있습니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| seasonName | string |  | ✓ |  |  ~ 128자 | 시즌 모델 이름<br>시즌 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| season | long |  | ✓ |  | 0 ~ 9223372036854775805 | 시즌 |
| tier | long |  | ✓ |  | 0 ~ 9223372036854775805 | 티어<br>비슷한 랭크의 플레이어를 그룹화하기 위한 티어 레벨입니다.<br>SeasonModel에서 지정된 GS2-Experience 모델에서의 플레이어 랭크에 따라 결정됩니다.<br>플레이어는 동일한 티어의 플레이어와만 매칭되어 공평한 대전이 보장됩니다. |
| seasonGatheringName | string |  | ✓ |  |  ~ 128자 | 시즌 게더링명<br>이 플레이어가 참가하고 있는 시즌 게더링의 이름입니다.<br>동일 시즌·티어 내의 특정 시즌 게더링 엔티티를 참조하기 위해 사용됩니다. |

**관련 메서드:**
getJoinedSeasonGathering - 특정 시즌에서 플레이어가 참가한 시즌 개더링 조회
listJoinedSeasonGatherings - 플레이어가 참가한 시즌 개더링 목록 조회


---

### EzSeasonGathering

시즌 게더링<br>

시즌 기간 동안 플레이어를 모으는 영속적인 게더링입니다.<br>
매치메이킹 완료 후 해산하는 일반 게더링과 달리, 시즌 게더링은 시즌 동안 계속 존속하며 참가자를 축적합니다.<br>
플레이어는 티어(GS2-Experience의 랭크에 기반)와 시즌 번호로 그룹화되며, 각 시즌 게더링에는 SeasonModel에서 정의된 최대 참가 인원 제한이 있습니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| seasonGatheringId | string |  | ※ |  |  ~ 1024자 | 시즌 개더링GRN<br>※ 서버가 자동으로 설정 |
| seasonName | string |  | ✓ |  |  ~ 128자 | 시즌 모델 이름<br>시즌 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| season | long |  | ✓ |  | 0 ~ 9223372036854775805 | 시즌 |
| tier | long |  | ✓ |  | 0 ~ 9223372036854775805 | 티어<br>비슷한 랭크의 플레이어를 그룹화하기 위한 티어 레벨입니다.<br>SeasonModel에서 지정된 GS2-Experience 모델에서의 플레이어 랭크에 따라 결정됩니다.<br>플레이어는 동일한 티어의 플레이어와만 매칭되어 공평한 대전이 보장됩니다. |
| name | string |  | ✓ | UUID |  ~ 128자 | 시즌 게더링명<br>시즌 게더링 고유의 이름입니다. 영숫자 및 -(하이픈), _(언더스코어), .(마침표)로 지정합니다. |
| participants | List&lt;string&gt; |  |  | [] | 0 ~ 1000 items | 참가자 사용자 ID 목록<br>이 시즌 게더링에 참가한 플레이어의 사용자 ID 목록입니다.<br>플레이어가 참가하면 이 목록에 추가되며, 최대 참가 인원에 도달할 때까지 시즌 동안 계속 증가합니다. |

**관련 메서드:**
doSeasonMatchmaking - 참가 가능한 시즌 매치를 검색하여 참가합니다
getSeasonGathering - 시즌 기어링의 현재 상태를 취득합니다


---

### EzBallot

투표용지<br>

레이팅이 적용된 매치메이킹 게임 종료 후, 각 플레이어가 대전 결과를 보고하기 위해 발급되는 투표용지입니다.<br>
레이팅 모델 이름, 개더링 이름, 참가 인원수 등 대전의 컨텍스트 정보를 포함합니다.<br>
각 플레이어는 서버에서 서명된 투표용지를 받아 게임 결과를 기입하여 Vote API에 제출합니다.<br>
투표 시스템은 레이팅 계산을 확정하기 위해 제출된 투표용지의 50%를 초과하는 합의를 필요로 합니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| userId | string |  | ✓ |  |  ~ 128자 | 사용자ID |
| ratingName | string |  | ✓ |  |  ~ 128자 | 레이팅 이름<br>이 대전 후의 레이팅 계산에 사용할 RatingModel의 이름입니다.<br>이 대전의 결과 처리에 적용되는 레이팅 시스템의 파라미터(초기값, 변동성)를 지정합니다. |
| gatheringName | string |  | ✓ |  |  ~ 128자 | 개더링 이름<br>대전 결과 보고 대상이 되는 개더링의 이름입니다.<br>특정 매치메이킹 세션을 식별하고, 동일한 대전의 모든 참가자로부터의 투표를 연결하기 위해 사용됩니다. |
| numberOfPlayer | int |  | ✓ |  | 2 ~ 10 | 참가 인원수<br>이 대전에 참가한 플레이어의 총 인원수입니다.<br>예상되는 투표 수 결정 및 합의 검증(플레이어의 50%를 초과하는 인원이 일치하는 결과를 제출해야 함)에 사용됩니다.<br>2에서 10 사이의 범위로 지정합니다. |

**관련 메서드:**
createVote - 대전 결과 보고용 서명된 투표용지를 생성합니다
vote - 대전 결과 투표를 제출합니다
voteMultiple - 모든 투표용지를 모아 한 번에 제출하여 대전 결과를 즉시 확정합니다


---

### EzRatingModel

레이팅 모델<br>

GS2에서는 레이팅 알고리즘으로 Glicko-2를 채택하고 있습니다.<br>
Glicko-2에는 여러 파라미터가 있지만, GS2-Matchmaking에서는 이를 종합적으로 나타내는 변동성이라는 하나의 파라미터로 통합하고 있습니다.<br>
변동성은 변화의 크기를 나타내는 파라미터로, 값이 클수록 레이팅 값의 변동 폭이 커집니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| name | string |  | ✓ |  |  ~ 128자 | 레이팅 모델 이름<br>레이팅 모델 고유의 이름. 영숫자 및 -(하이픈), _(밑줄), .(마침표)로 지정합니다. |
| metadata | string |  |  |  |  ~ 128자 | 메타데이터<br>메타데이터에는 임의의 값을 설정할 수 있습니다.<br>이 값들은 GS2의 동작에는 영향을 주지 않으므로, 게임 내에서 사용하는 정보를 저장하는 용도로 사용할 수 있습니다. |
| volatility | int |  |  | 100 | 1 ~ 20000 | 레이팅의 변동성<br>각 대전 후 레이트 값이 얼마나 변동하는지를 제어하는 Glicko-2의 파라미터입니다.<br>값이 클수록 레이팅의 변동 폭이 커져 더 빠르게 레이팅이 조정됩니다.<br>값이 작을수록 레이팅이 안정되어 완만하게 변화합니다. 기본값은 100입니다. |

**관련 메서드:**
getRatingModel - 특정 레이팅 설정의 상세 정보를 취득합니다
listRatingModels - 레이팅 설정 목록을 취득합니다


---

### EzSeasonModel

시즌 모델<br>

시즌 매치메이킹에서, 일정 기간 동안 유효한 영속 개더링의 기간·최대 참가 인원수·티어 연동 설정을 정의하는 마스터 데이터입니다.<br>
GS2-Schedule을 통해 기간을 관리하며, 필요에 따라 GS2-Experience와 연동하여 동일한 티어 내에서 영속 개더링을 형성합니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| name | string |  | ✓ |  |  ~ 128자 | 시즌 모델 이름<br>시즌 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| metadata | string |  |  |  |  ~ 128자 | 메타데이터<br>메타데이터에는 임의의 값을 설정할 수 있습니다.<br>이 값들은 GS2의 동작에는 영향을 주지 않으므로, 게임 내에서 사용하는 정보를 저장하는 용도로 사용할 수 있습니다. |
| maximumParticipants | int |  | ✓ |  | 2 ~ 1000 | 최대 참가 인원수<br>하나의 시즌 개더링에 참가할 수 있는 플레이어의 최대 인원수입니다.<br>이 상한에 도달하면 시즌 개더링은 만원 상태가 되어 더 이상 플레이어가 참가할 수 없게 됩니다.<br>2에서 1000 사이의 범위로 지정합니다. |
| experienceModelId | string |  |  |  |  ~ 1024자 | 티어 관리용 경험치 모델 GRN<br>플레이어의 티어를 결정하기 위해 사용하는 GS2-Experience 경험치 모델의 GRN입니다.<br>이 경험치 모델에서의 플레이어 랭크가 매치메이킹의 티어로 사용되어, 비슷한 레벨의 플레이어끼리 그룹화됩니다.<br>지정하지 않으면 티어에 의한 그룹화가 비활성화되어, 레벨에 관계없이 모든 플레이어가 매칭됩니다. |
| challengePeriodEventId | string |  | ✓ |  |  ~ 1024자 | 챌린지 기간 이벤트 GRN<br>이 시즌의 유효 기간을 정의하는 GS2-Schedule 이벤트의 GRN입니다.<br>이 이벤트가 활성화되어 있는 동안에만 시즌 개더링의 생성·참가가 가능합니다.<br>이벤트 기간이 종료되면 시즌이 종료되어 새로운 매치메이킹이 불가능해집니다. |

**관련 메서드:**
getSeasonModel - 특정 시즌 매치메이킹 설정의 상세 정보를 취득합니다
listSeasonModels - 시즌 매치메이킹 설정 목록을 취득합니다


---

### EzPlayer

참가자 플레이어 정보<br>

매치메이킹에 참가하는 플레이어를 나타내며, ID, 속성, 역할, 거부 목록을 포함합니다.<br>
게더링에 참가할 때, 플레이어의 속성값, 희망하는 역할, 함께 플레이하고 싶지 않은 사용자 목록을 가진 Player 오브젝트가 생성됩니다.<br>
플레이어의 속성은 게더링의 속성 범위 조건과 대조되며, 거부 목록은 원치 않는 페어링을 방지하기 위해 크로스체크됩니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| userId | string |  | ✓ |  |  ~ 128자 | 사용자ID |
| attributes | [List&lt;EzAttribute&gt;](#ezattribute) |  |  | [] | 0 ~ 5 items | 속성값 목록<br>매치메이킹 조건 평가에 사용되는 플레이어의 이름이 지정된 수치 속성입니다.<br>각 속성은 게더링의 AttributeRange 조건과 대조되어 참가 자격이 판정됩니다.<br>게더링 생성 시 범위 조건을 설정하는 경우, 플레이어 자신의 속성값도 그 범위 내에 있어야 합니다. 최대 5건. |
| roleName | string |  |  | "default" |  ~ 128자 | 역할명<br>이 플레이어가 게더링에서 채우고자 하는 역할입니다.<br>역할 구분이 없는 일반적인 매치메이킹의 경우 기본값 "default"를 사용합니다.<br>역할 기반 매치메이킹의 경우, 플레이어의 구체적인 역할(예: "팔라딘", "나이트")을 지정하며, 게더링의 정원 정의에 있는 역할명 및 별칭과 매칭됩니다. |
| denyUserIds | List&lt;string&gt; |  |  | [] | 0 ~ 100 items | 매칭 거부 사용자 ID 목록<br>이 플레이어가 매칭을 거부하는 사용자 ID의 블랙리스트입니다.<br>매치메이킹 시, 게더링에 이미 참가한 플레이어가 이 목록에 포함되어 있으면 해당 게더링에 참가할 수 없습니다.<br>반대로, 기존 참가자의 거부 목록에 이 플레이어가 포함되어 있는 경우에도 참가가 차단됩니다. 최대 100건. |

**관련 메서드:**
createGathering - 매치메이킹용 방(개더링) 신규 생성
doMatchmaking - 참가 가능한 개더링을 검색하여 참가


**관련 모델:**
EzCapacityOfRole - 모집 슬롯



---

### EzAttributeRange

모집 조건<br>

게더링에 참가하기 위한 속성의 허용 범위를 정의하는 조건입니다.<br>
플레이어가 참가를 시도할 때, 대응하는 이름의 속성값이 지정된 최소값·최대값 범위 내에 있어야 합니다.<br>
스킬 기반 또는 레벨 기반의 매치메이킹 필터를 작성하는 데 사용됩니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| name | string |  | ✓ |  |  ~ 128자 | 속성명<br>이 범위 조건을 적용할 속성의 이름입니다.<br>조건이 평가되려면 플레이어의 속성 목록에 있는 속성명과 일치해야 합니다. |
| min | int |  |  | 0 | 0 ~ 2147483646 | 속성값의 최소값<br>게더링에 참가하기 위해 필요한 속성값의 하한(해당 값 포함)입니다.<br>속성값이 이 임계값보다 낮은 플레이어는 참가할 수 없습니다. |
| max | int |  |  | 0 | 0 ~ 2147483646 | 속성값의 최대값<br>게더링에 참가 가능한 속성값의 상한(해당 값 포함)입니다.<br>속성값이 이 임계값을 초과하는 플레이어는 참가할 수 없습니다. |

**관련 메서드:**
createGathering - 매치메이킹용 방(개더링) 신규 생성
updateGathering - 개더링의 모집 조건 변경


**관련 모델:**
EzGathering - 개더링



---

### EzCapacityOfRole

모집 슬롯<br>

개더링 내 특정 역할에 대한 모집 슬롯을 정의합니다.<br>
각 역할은 이름, 선택적 별칭, 최대 정원, 현재 참가 중인 플레이어 목록을 가집니다.<br>
역할 별칭을 사용하면 유연한 매칭이 가능합니다. 예를 들어 "탱크" 역할에 "팔라딘"과 "나이트"라는 별칭을 설정하면, 둘 중 어느 하위 역할을 지정한 플레이어도 탱크 슬롯을 채울 수 있습니다.<br>
모든 역할의 참가자가 정원에 도달하면, 개더링의 매치메이킹이 완료됩니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| roleName | string |  |  | "default" |  ~ 128자 | 역할 이름<br>이 모집 슬롯의 역할 이름.<br>역할 구분이 없는 일반적인 매치메이킹의 경우, 기본값 "default"를 사용합니다.<br>역할 기반 매치메이킹(예: "탱크", "힐러", "어태커")의 경우, 여기에 역할 카테고리 이름을 지정합니다. |
| roleAliases | List&lt;string&gt; |  |  | [] | 0 ~ 9 items | 역할 이름 별칭 목록<br>이 모집 슬롯에서 허용되는 대체 역할 이름.<br>이러한 별칭 중 하나를 역할 이름으로 지정한 플레이어는 이 슬롯에 매칭됩니다.<br>하위 역할 매칭을 가능하게 합니다. 예: "탱크" 역할에 대한 "팔라딘"과 "나이트" 별칭. 최대 9건. |
| capacity | int |  | ✓ |  | 1 ~ 256 | 모집 인원수<br>이 역할 슬롯을 채울 수 있는 플레이어의 최대 수.<br>참가자 수가 이 정원에 도달하면, 역할은 가득 차게 되어 더 이상 이 역할의 플레이어는 참가할 수 없습니다.<br>1에서 256 범위로 지정합니다. |
| participants | [List&lt;EzPlayer&gt;](#ezplayer) |  |  | [] | 0 ~ 1000 items | 참가자 플레이어 정보 목록<br>현재 이 역할 슬롯을 차지하고 있는 플레이어의 목록.<br>플레이어는 개더링에 참가하면 추가되고, 이탈하면 삭제됩니다.<br>각 플레이어 항목에는 사용자 ID, 속성, 역할 이름, 거부 목록이 포함됩니다. 사용자 ID를 기준으로 고유성이 보장됩니다. |

**관련 메서드:**
createGathering - 매치메이킹용 방(개더링) 신규 생성


**관련 모델:**
EzGathering - 개더링



---

### EzAttribute

속성값<br>

매치메이킹을 위해 플레이어에게 연결된 이름이 지정된 수치 속성입니다.<br>
어떤 플레이어가 참가할 수 있는지 필터링하기 위해 개더링의 AttributeRange 조건과 함께 사용됩니다.<br>
예를 들어 값이 50인 "레벨" 속성을 가진 플레이어는 레벨 40~60을 요구하는 개더링에 매칭됩니다.<br>
각 플레이어는 최대 5개의 속성을 가질 수 있습니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| name | string |  | ✓ |  |  ~ 128자 | 속성 이름<br>속성 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| value | int |  |  | 0 | 0 ~ 2147483646 | 속성값<br>이 플레이어의 속성 수치입니다.<br>매치메이킹 시 개더링의 AttributeRange 조건에서 지정된 최소값·최대값 범위와 대조됩니다. |


**관련 모델:**
EzPlayer - 참가자 플레이어 정보



---

### EzGameResult

대전 결과<br>

Vote 시스템을 통한 레이팅 계산에 사용되는, 대전에서 한 플레이어의 결과를 나타냅니다.<br>
각 GameResult 항목은 사용자 ID와 해당 대전에서의 순위(최종 순위)를 짝지어 나타냅니다.<br>
순위 값이 작을수록 높은 성적을 나타냅니다(1위 = rank 1). 순위가 같은 플레이어는 무승부로 처리됩니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| rank | int |  | ✓ |  | 0 ~ 2147483646 | 순위<br>대전에서 플레이어의 최종 순위입니다. 1이 최상위(승자)입니다.<br>Glicko-2 알고리즘에 의한 레이팅 변동 계산에 사용됩니다. 상위 플레이어는 레이팅이 상승하고, 하위 플레이어는 레이팅이 하락합니다.<br>순위가 같은 플레이어는 무승부로 처리됩니다. |
| userId | string |  | ✓ |  |  ~ 128자 | 사용자ID |

**관련 메서드:**
vote - 대전 결과 투표를 제출합니다
voteMultiple - 모든 투표용지를 모아 한 번에 제출하여 대전 결과를 즉시 확정합니다


---

### EzSignedBallot

서명된 투표용지<br>

진위를 검증하기 위한 디지털 서명이 부여된 투표용지입니다.<br>
매치메이킹 완료 후 서버가 플레이어에게 서명된 투표용지를 발급하여, 정당한 참가자만이 대전 결과를 제출할 수 있도록 보장합니다.<br>
투표용지가 Vote API에 제출될 때 서명이 검증되어, 대전 컨텍스트(레이팅 이름, 개더링 이름, 참가 인원수)의 변조를 방지합니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| body | string |  | ✓ |  |  ~ 1024자 | 투표용지 본문<br>디지털 서명의 대상이 되는 직렬화된 투표용지 데이터입니다.<br>서명과 대조하여 검증 가능한 형식으로, 투표 컨텍스트(사용자 ID, 레이팅 이름, 개더링 이름, 참가 인원수)를 포함합니다. |
| signature | string |  | ✓ |  |  ~ 256자 | 서명<br>투표용지 본문의 진위성과 무결성을 검증하기 위한 디지털 서명입니다.<br>GS2-Key의 암호화 키를 사용하여 서버에서 생성되며, 투표용지 제출 시 위조나 변조를 방지하기 위해 검증됩니다. |

**관련 메서드:**
voteMultiple - 모든 투표용지를 모아 한 번에 제출하여 대전 결과를 즉시 확정합니다


---

### EzTimeSpan

시간 간격(기간)<br>

일·시간·분으로 구성된 시간의 길이를 나타냅니다.<br>
현재 시각으로부터의 게더링 유효 기간 등, 상대적인 시간 오프셋을 지정하는 데 사용됩니다.<br>
전체 기간은 세 구성 요소를 합산하여 계산됩니다.

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| days | int |  |  | 0 | 0 ~ 365 | 일수<br>기간에서의 일수입니다. 최대 365일. 기본값은 0입니다. |
| hours | int |  |  | 0 | 0 ~ 24 | 시간<br>기간에서의 시간 수입니다. 최대 24시간. 기본값은 0입니다. |
| minutes | int |  |  | 0 | 0 ~ 60 | 분<br>기간에서의 분 수입니다. 최대 60분. 기본값은 0입니다. |

**관련 메서드:**
createGathering - 매치메이킹용 방(개더링) 신규 생성


---

## 메서드

### cancelMatchmaking

매치메이킹을 취소하고 기어링에서 이탈합니다<br>

플레이어를 현재 참가 중인 기어링에서 이탈시키고 매치메이킹을 중단합니다.<br>
매치메이킹 대기 화면에서 "취소" 버튼을 탭했을 때 사용합니다.<br>

주의: 취소하려는 순간 매치메이킹이 완료된 경우, 기어링이 더 이상 존재하지 않기 때문에 NotFoundException(404 오류)이 반환됩니다.<br>
게임 측에서는 이 경우를 처리해야 합니다. 매치가 성립되었다는 의미이므로 플레이어를 그대로 게임에 진행시키면 됩니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gatheringName | string |  | ✓| UUID |  ~ 128자 | 개더링 이름<br>개더링의 고유한 이름을 보유합니다.<br>이름은 UUID(Universally Unique Identifier) 형식으로 자동 생성되며, 개더링을 식별하기 위해 사용됩니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzGathering](#ezgathering) | 취소한 개더링|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    var result = await domain.CancelMatchmakingAsync(
    );

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    var future = domain.CancelMatchmakingFuture(
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Gathering(
        "gathering-0001" // gatheringName
    );
    const auto Future = Domain->CancelMatchmaking(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
    const auto Result = Future->GetTask().Result();

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).me(game_session).gathering(
        "gathering-0001"
    )

var async_result = await domain.cancel_matchmaking(
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---

### createGathering

매치메이킹용 방(개더링) 신규 생성<br>

매치메이킹용 방을 생성하고 다른 플레이어의 참가를 기다립니다.<br>
개더링 생성 시 모집 조건을 설정합니다. 예를 들어 "어태커 1명과 힐러 1명 모집, 플레이어 레벨은 10~20"과 같은 조건을 지정할 수 있습니다.<br>

주요 설정 항목:<br>
- capacityOfRoles: 역할별 모집 인원을 정의합니다(예: DPS 2명 + 탱커 1명 + 힐러 1명).<br>
- attributeRanges: 레벨이나 랭크 등 플레이어 속성에 기반한 참가 조건을 설정합니다.<br>
- allowUserIds: 특정 플레이어만 참가할 수 있도록 제한합니다(친구 전용 또는 초대제 매치메이킹에 유용합니다).<br>
- expiresAt: 개더링의 유효 기간을 설정합니다. 설정을 권장합니다. 유효 기간이 없으면 플레이어가 게임에서 이탈한 후에도 오래된 개더링이 계속 남아 있게 됩니다. 유효 기간을 사용하는 경우, 기간이 만료되면 플레이어에게 개더링을 다시 생성하도록 안내하는 구조로 만들어 주세요.<br>

Player 파라미터에서 자기 자신의 사용자 ID는 생략할 수 있습니다.<br>

개더링 생성 후, 다른 플레이어는 DoMatchmaking을 호출하여 이 개더링을 찾아 참가할 수 있습니다.<br>
모든 역할 슬롯이 채워지면 매치메이킹이 완료되고 모든 참가자에게 알림이 전송됩니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| player | [EzPlayer](#ezplayer) |  | ✓|  |  | 자신의 플레이어 정보 |
| attributeRanges | [List&lt;EzAttributeRange&gt;](#ezattributerange) |  | | [] | 0 ~ 5 items | 모집 조건<br>이 개더링에 참가하기 위해 플레이어가 충족해야 하는 속성 범위 조건의 목록입니다.<br>각 항목은 속성 이름과 허용되는 최소값·최대값 범위를 지정합니다.<br>플레이어 자신의 속성값이 이 범위 내에 있지 않으면 참가할 수 없습니다. 최대 5건. |
| capacityOfRoles | [List&lt;EzCapacityOfRole&gt;](#ezcapacityofrole) |  | | [] | 1 ~ 5 items | 모집 슬롯 목록<br>이 개더링의 모집 슬롯을 정의합니다.<br>각 항목은 역할 이름, 그 별칭, 그리고 해당 역할에 참가 가능한 최대 인원수를 지정합니다.<br>모든 역할 슬롯이 정원에 도달하면 매치메이킹이 완료됩니다. 최소 1건, 최대 5건. |
| allowUserIds | List&lt;string&gt; |  | | [] | 0 ~ 100 items | 참가 허용 사용자 ID 목록<br>이 게더링에 참가하는 것이 허용된 사용자 ID의 화이트리스트입니다.<br>지정한 경우, 목록에 포함된 사용자만 이 게더링의 매치메이킹에 참가할 수 있습니다.<br>친구 전용 매치메이킹이나 초대제 매치메이킹 시나리오에 유용합니다. 최대 100건. |
| expiresAt | long |  | |  |  | 게더링 유효 기간<br>이 게더링이 자동으로 만료되어 삭제되는 시각입니다.<br>이 시각까지 매치메이킹이 완료되지 않으면 게더링은 정리됩니다.<br>지정하지 않은 경우, 매치메이킹이 완료되거나 수동으로 삭제될 때까지 게더링이 유지됩니다. |
| expiresAtTimeSpan | [EzTimeSpan](#eztimespan) |  | |  |  | 유효기간까지 남은 시간 |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzGathering](#ezgathering) | 작성한 개더링|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var result = await domain.CreateGatheringAsync(
        player: new Gs2.Unity.Gs2Matchmaking.Model.EzPlayer {
            Attributes = new List<Gs2.Unity.Gs2Matchmaking.Model.EzAttribute> {
                new Gs2.Unity.Gs2Matchmaking.Model.EzAttribute {
                    Name = "stage",
                    Value = 1,
                },
                new Gs2.Unity.Gs2Matchmaking.Model.EzAttribute {
                    Name = "level",
                    Value = 10,
                },
            },
        },
        attributeRanges: new List<Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange {
                Name = "stage",
                Min = 1,
                Max = 1,
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange {
                Name = "level",
                Min = 0,
                Max = 10,
            },
        },
        capacityOfRoles: new List<Gs2.Unity.Gs2Matchmaking.Model.EzCapacityOfRole> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzCapacityOfRole {
                RoleName = "default",
                Capacity = 4,
            },
        },
        allowUserIds: null,
        expiresAt: null,
        expiresAtTimeSpan: null
    );
    var item = await result.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var future = domain.CreateGatheringFuture(
        player: new Gs2.Unity.Gs2Matchmaking.Model.EzPlayer {
            Attributes = new List<Gs2.Unity.Gs2Matchmaking.Model.EzAttribute> {
                new Gs2.Unity.Gs2Matchmaking.Model.EzAttribute {
                    Name = "stage",
                    Value = 1,
                },
                new Gs2.Unity.Gs2Matchmaking.Model.EzAttribute {
                    Name = "level",
                    Value = 10,
                },
            },
        },
        attributeRanges: new List<Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange {
                Name = "stage",
                Min = 1,
                Max = 1,
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange {
                Name = "level",
                Min = 0,
                Max = 10,
            },
        },
        capacityOfRoles: new List<Gs2.Unity.Gs2Matchmaking.Model.EzCapacityOfRole> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzCapacityOfRole {
                RoleName = "default",
                Capacity = 4,
            },
        },
        allowUserIds: null,
        expiresAt: null,
        expiresAtTimeSpan: null
    );
    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;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    const auto Future = Domain->CreateGathering(
        MakeShared<Gs2::UE5::Matchmaking::Model::FEzPlayer>()
            ->WithAttributes([]
            {
                auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::Matchmaking::Model::FEzAttribute>>>();
                v->Add(
                    MakeShared<Gs2::UE5::Matchmaking::Model::FEzAttribute>()
                    ->WithName(TOptional<FString>("stage"))
                    ->WithValue(TOptional<int32>(1)));
                v->Add(
                    MakeShared<Gs2::UE5::Matchmaking::Model::FEzAttribute>()
                    ->WithName(TOptional<FString>("level"))
                    ->WithValue(TOptional<int32>(10)));
                return v;
            }())
        ), // player
        []
        {
            auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::Matchmaking::Model::FEzAttributeRange>>>();
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzAttributeRange>()
                ->WithName(TOptional<FString>("stage"))
                ->WithMin(TOptional<int32>(1))
                ->WithMax(TOptional<int32>(1)));
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzAttributeRange>()
                ->WithName(TOptional<FString>("level"))
                ->WithMin(TOptional<int32>(0))
                ->WithMax(TOptional<int32>(10)));
            return v;
        }(), // attributeRanges
        []
        {
            auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::Matchmaking::Model::FEzCapacityOfRole>>>();
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzCapacityOfRole>()
                ->WithRoleName(TOptional<FString>("default"))
                ->WithCapacity(TOptional<int32>(4)));
            return v;
        }() // capacityOfRoles
        // allowUserIds
        // expiresAt
        // expiresAtTimeSpan
    );
    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();

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).me(game_session)

var async_result = await domain.create_gathering(
    (Gs2MatchmakingPlayer.new()
        .with_attributes([
            (Gs2MatchmakingEzAttribute.new()
                .with_name("stage")
                .with_value(1)),
            (Gs2MatchmakingEzAttribute.new()
                .with_name("level")
                .with_value(10)),
        ])), # player
    [
        (Gs2MatchmakingEzAttributeRange.new()
            .with_name("stage")
            .with_min(1)
            .with_max(1)),
        (Gs2MatchmakingEzAttributeRange.new()
            .with_name("level")
            .with_min(0)
            .with_max(10)),
    ], # attribute_ranges
    [
        (Gs2MatchmakingEzCapacityOfRole.new()
            .with_role_name("default")
            .with_capacity(4)),
    ], # capacity_of_roles
    null, # allow_user_ids
    null, # expires_at
    null # expires_at_time_span
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---

### doMatchmaking

참가 가능한 개더링을 검색하여 참가<br>

기존 개더링 중에서 플레이어의 속성에 맞고 빈 자리가 있는 것을 검색하여 자동으로 참가합니다.<br>
직접 매치를 만들기보다 기존 매치에 참가하고 싶은 플레이어가 사용하는 메인 API입니다.<br>

한 번의 호출에서는 일정 시간 동안만 검색을 수행합니다. 아직 적절한 개더링을 찾지 못한 경우 `matchmakingContextToken`이 반환됩니다.<br>
다음 호출에서 이 토큰을 전달하면 이전 검색의 이어서부터 검색을 재개할 수 있습니다. 매치가 발견될 때까지 반복해서 호출해 주세요.<br>

모든 개더링을 검색했지만 참가 가능한 것이 없었던 경우, 개더링과 토큰 모두 `null`이 됩니다.<br>
이 경우에는 CreateGathering으로 새로운 개더링을 생성해 주세요.<br>

일반적인 매치메이킹 흐름:<br>
1. DoMatchmaking을 반복 호출하며 매번 토큰을 전달<br>
2. 개더링이 반환됨 → 매치메이킹 성공, 게임으로 진행<br>
3. 개더링과 토큰 모두 null → 매치를 찾지 못했으므로 새로운 개더링을 생성

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| player | [EzPlayer](#ezplayer) |  | ✓|  |  | 자신의 플레이어 정보 |
| matchmakingContextToken | string |  | |  |  ~ 5120자 | 검색 재개에 사용하는 매치메이킹 상태를 보유하는 토큰 |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzGathering](#ezgathering) | 참가한 개더링|
| matchmakingContextToken | string | 매치메이킹 상태를 보유하는 토큰|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var items = await domain.DoMatchmakingAsync(
        player: new Gs2.Unity.Gs2Matchmaking.Model.EzPlayer() {
            UserId = "user-0001",
            Attributes = new List<Gs2.Unity.Gs2MatchmakingEzAttribute> {
                new Gs2.Unity.Gs2MatchmakingEzAttribute() {
                    Name = "attr1",
                    Value = 1,
                },
                new Gs2.Unity.Gs2MatchmakingEzAttribute() {
                    Name = "attr2",
                    Value = 1,
                },
            }
        }
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var it = domain.DoMatchmaking(
        player: new Gs2.Unity.Gs2Matchmaking.Model.EzPlayer() {
            UserId = "user-0001",
            Attributes = new List<Gs2.Unity.Gs2MatchmakingEzAttribute> {
                new Gs2.Unity.Gs2MatchmakingEzAttribute() {
                    Name = "attr1",
                    Value = 1,
                },
                new Gs2.Unity.Gs2MatchmakingEzAttribute() {
                    Name = "attr2",
                    Value = 1,
                },
            }
        }
    );

    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;
        }
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    const auto It = Domain->DoMatchmaking(
        MakeShared<Gs2::UE5::Matchmaking::Model::FEzPlayer>()
            ->WithUserId(TOptional<FString>("user-0001"))
            ->WithAttributes([]
            {
                const auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::Matchmaking::Model::FEzAttribute>>>();
                v->Add( MakeShared<Gs2::UE5::Matchmaking::Model::FEzAttribute>()
                    ->WithName(TOptional<FString>("attr1"))
                    ->WithValue(TOptional<int32>(1))
                );
                v->Add( MakeShared<Gs2::UE5::Matchmaking::Model::FEzAttribute>()
                    ->WithName(TOptional<FString>("attr2"))
                    ->WithValue(TOptional<int32>(1))
                );
                return v;
            }() // player
    );
    TArray<Gs2::UE5::Matchmaking::Model::FEzGatheringPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


---

### earlyCompleteMatchmaking

정원이 채워지지 않은 상태에서 매치메이킹을 조기 종료합니다<br>

모든 역할 슬롯이 채워지기 전에 매치메이킹을 종료합니다.<br>
원래 모집 인원보다 적은 인원으로 게임을 시작하고 싶을 때 사용합니다. 예를 들어 4인용 협력 던전을 3명으로 시작하는 경우입니다.<br>

이 API를 호출할 수 있는 것은 기어링을 생성한 플레이어뿐입니다.<br>
호출 후 매치메이킹은 완료된 것으로 처리되며, 모든 참가자에게 매치 완료 알림이 전송됩니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gatheringName | string |  | ✓| UUID |  ~ 128자 | 개더링 이름<br>개더링의 고유한 이름을 보유합니다.<br>이름은 UUID(Universally Unique Identifier) 형식으로 자동 생성되며, 개더링을 식별하기 위해 사용됩니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzGathering](#ezgathering) | 취소한 개더링|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    var result = await domain.EarlyCompleteMatchmakingAsync(
    );
    var item = await result.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    var future = domain.EarlyCompleteMatchmakingFuture(
    );
    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;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Gathering(
        "gathering-0001" // gatheringName
    );
    const auto Future = Domain->EarlyCompleteMatchmaking(
    );
    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();

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).me(game_session).gathering(
        "gathering-0001"
    )

var async_result = await domain.early_complete_matchmaking(
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---

### getGathering

기어링의 현재 상태를 취득합니다<br>

특정 기어링의 최신 정보를 취득합니다. 참가자, 모집 조건, 역할별 정원이 포함됩니다.<br>
대기 화면을 표시할 때 사용합니다. 예를 들어 "2/4명 참가 완료, 모집 중: 탱커 1명, 힐러 1명"과 같은 화면을 표시할 수 있습니다.<br>

모든 역할 슬롯이 채워졌는지 확인함으로써 매치메이킹이 완료되었는지 확인하는 용도로도 사용할 수 있습니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gatheringName | string |  | ✓| UUID |  ~ 128자 | 개더링 이름<br>개더링의 고유한 이름을 보유합니다.<br>이름은 UUID(Universally Unique Identifier) 형식으로 자동 생성되며, 개더링을 식별하기 위해 사용됩니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzGathering](#ezgathering) | 개더링|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->User(
        "user-0001" // userId
    )->Gathering(
        "gathering-0001" // gatheringName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).user(
        "user-0001"
    ).gathering(
        "gathering-0001"
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->User(
        "user-0001" // userId
    )->Gathering(
        "gathering-0001" // gatheringName
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Matchmaking::Model::FGathering> value) {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->Unsubscribe(CallbackId);

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).user(
        "user-0001"
    ).gathering(
        "gathering-0001"
    )

# 이벤트 핸들링 시작
var callback_id = domain.subscribe_model(func(value):
    # 값이 변화했을 때 호출됨
    # value에는 변경 후의 값이 전달됩니다
    pass
)

# 이벤트 핸들링 정지
domain.unsubscribe_model(callback_id)

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### ping

매치메이킹 대기 중 킵얼라이브를 전송합니다<br>

플레이어가 아직 매치메이킹을 대기 중임을 서버에 알립니다.<br>
플레이어가 매치메이킹 대기 화면에 있는 동안 주기적으로 호출하세요.<br>

이를 통해 어떤 플레이어가 아직 온라인 상태로 대기 중인지 시스템이 파악할 수 있습니다.<br>
네임스페이스에 타임아웃이 설정되어 있는 경우, 타임아웃 시간 내에 ping을 보내지 않은 플레이어는 기어링에서 자동으로 제외될 수 있습니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gatheringName | string |  | ✓| UUID |  ~ 128자 | 개더링 이름<br>개더링의 고유한 이름을 보유합니다.<br>이름은 UUID(Universally Unique Identifier) 형식으로 자동 생성되며, 개더링을 식별하기 위해 사용됩니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzGathering](#ezgathering) | 갱신한 개더링|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    var result = await domain.PingAsync(
    );
    var item = await result.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    var future = domain.PingFuture(
    );
    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;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Gathering(
        "gathering-0001" // gatheringName
    );
    const auto Future = Domain->Ping(
    );
    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();

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).me(game_session).gathering(
        "gathering-0001"
    )

var async_result = await domain.ping(
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---

### updateGathering

개더링의 모집 조건 변경<br>

아직 플레이어를 기다리고 있는 기존 개더링의 속성 범위 조건을 변경합니다.<br>
예를 들어 "레벨 15~20" 조건으로 플레이어가 모이지 않는 경우, "레벨 10~25"로 범위를 넓혀 참가 가능한 플레이어 모수를 늘릴 수 있습니다.<br>

변경할 수 있는 것은 속성 범위뿐입니다. 역할 정원이나 참가 허용 사용자 ID는 생성 후에는 변경할 수 없습니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gatheringName | string |  | ✓| UUID |  ~ 128자 | 개더링 이름<br>개더링의 고유한 이름을 보유합니다.<br>이름은 UUID(Universally Unique Identifier) 형식으로 자동 생성되며, 개더링을 식별하기 위해 사용됩니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| attributeRanges | [List&lt;EzAttributeRange&gt;](#ezattributerange) |  | | [] | 0 ~ 5 items | 모집 조건<br>이 개더링에 참가하기 위해 플레이어가 충족해야 하는 속성 범위 조건의 목록입니다.<br>각 항목은 속성 이름과 허용되는 최소값·최대값 범위를 지정합니다.<br>플레이어 자신의 속성값이 이 범위 내에 있지 않으면 참가할 수 없습니다. 최대 5건. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzGathering](#ezgathering) | 갱신한 개더링|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    var result = await domain.UpdateGatheringAsync(
        attributeRanges: new List<Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange {
                Name = "stage",
                Min = 1,
                Max = 1,
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange {
                Name = "level",
                Min = 0,
                Max = 50,
            },
        }
    );
    var item = await result.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Gathering(
        gatheringName: "gathering-0001"
    );
    var future = domain.UpdateGatheringFuture(
        attributeRanges: new List<Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange {
                Name = "stage",
                Min = 1,
                Max = 1,
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzAttributeRange {
                Name = "level",
                Min = 0,
                Max = 50,
            },
        }
    );
    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;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Gathering(
        "gathering-0001" // gatheringName
    );
    const auto Future = Domain->UpdateGathering(
        []
        {
            auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::Matchmaking::Model::FEzAttributeRange>>>();
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzAttributeRange>()
                ->WithName(TOptional<FString>("stage"))
                ->WithMin(TOptional<int32>(1))
                ->WithMax(TOptional<int32>(1)));
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzAttributeRange>()
                ->WithName(TOptional<FString>("level"))
                ->WithMin(TOptional<int32>(0))
                ->WithMax(TOptional<int32>(50)));
            return v;
        }() // attributeRanges
    );
    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();

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).me(game_session).gathering(
        "gathering-0001"
    )

var async_result = await domain.update_gathering(
    [
        (Gs2MatchmakingEzAttributeRange.new()
            .with_name("stage")
            .with_min(1)
            .with_max(1)),
        (Gs2MatchmakingEzAttributeRange.new()
            .with_name("level")
            .with_min(0)
            .with_max(50)),
    ] # attribute_ranges
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---

### getRatingModel

특정 레이팅 설정의 상세 정보를 취득합니다<br>

이름을 지정하여 하나의 레이팅 모델의 상세 정보를 취득합니다.<br>
레이팅 시스템의 설정(초기 레이팅 값 및 변동성 파라미터)을 표시할 때 사용합니다.<br>

변동성이 높을수록 대전마다 레이팅 변동 폭이 커지며(신규 플레이어의 실력을 빠르게 반영하는 데 적합), 변동성이 낮을수록 더 안정적이고 완만한 변화가 나타납니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| ratingName | string |  | ✓|  |  ~ 128자 | 레이팅 모델 이름<br>레이팅 모델 고유의 이름. 영숫자 및 -(하이픈), _(밑줄), .(마침표)로 지정합니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzRatingModel](#ezratingmodel) | 레이팅 모델|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).RatingModel(
        ratingName: "mode1"
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).RatingModel(
        ratingName: "mode1"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->RatingModel(
        "mode1" // ratingName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).rating_model(
        "mode1"
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).RatingModel(
        ratingName: "mode1"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).RatingModel(
        ratingName: "mode1"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->RatingModel(
        "mode1" // ratingName
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Matchmaking::Model::FRatingModel> value) {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->Unsubscribe(CallbackId);

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).rating_model(
        "mode1"
    )

# 이벤트 핸들링 시작
var callback_id = domain.subscribe_model(func(value):
    # 값이 변화했을 때 호출됨
    # value에는 변경 후의 값이 전달됩니다
    pass
)

# 이벤트 핸들링 정지
domain.unsubscribe_model(callback_id)

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### listRatingModels

레이팅 설정 목록을 취득합니다<br>

네임스페이스에 설정되어 있는 모든 레이팅 모델을 취득합니다.<br>
각 레이팅 모델은 플레이어의 실력 평가 시스템에 대한 파라미터를 정의합니다. 예를 들어 "랭크 배틀", "아레나", "토너먼트"별로 각각 다른 레이팅을 가질 수 있습니다.<br>

GS2에서는 레이팅 계산에 Glicko-2 알고리즘을 사용합니다. 각 모델은 초기 레이팅 값(기본값: 1500)과 변동성(대전마다 레이팅이 얼마나 크게 변하는지)을 지정합니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| items | [List&lt;EzRatingModel&gt;](#ezratingmodel) | 레이팅 모델 리스트|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    var items = await domain.RatingModelsAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    var it = domain.RatingModels(
    );
    List<EzRatingModel> items = new List<EzRatingModel>();
    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;
        }
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    );
    const auto It = Domain->RatingModels(
    );
    TArray<Gs2::UE5::Matchmaking::Model::FEzRatingModelPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeRatingModels(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeRatingModels(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeRatingModels(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeRatingModels(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->SubscribeRatingModels(
        []() {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->UnsubscribeRatingModels(CallbackId);

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### getRating

특정 카테고리의 플레이어 레이팅 점수를 취득합니다<br>

지정된 레이팅 이름에 대한 플레이어의 현재 레이팅 값을 취득합니다.<br>
하나의 레이팅을 표시할 때 사용합니다. 예를 들어 대전 결과 화면이나 로비에서 "당신의 랭크 배틀 레이팅: 1823"과 같이 표시할 수 있습니다.<br>

레이팅 값은 플레이어가 이기면 오르고 지면 내려갑니다. 변동 폭은 상대방의 레이팅과 변동성 설정에 따라 결정됩니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| ratingName | string |  | ✓|  |  ~ 128자 | 레이팅 이름<br>레이팅 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzRating](#ezrating) | 레이팅|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Rating(
        ratingName: "rating-0001"
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Rating(
        ratingName: "rating-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Rating(
        "rating-0001" // ratingName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).me(game_session).rating(
        "rating-0001"
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Rating(
        ratingName: "rating-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Rating(
        ratingName: "rating-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Rating(
        "rating-0001" // ratingName
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Matchmaking::Model::FRating> value) {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->Unsubscribe(CallbackId);

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).me(game_session).rating(
        "rating-0001"
    )

# 이벤트 핸들링 시작
var callback_id = domain.subscribe_model(func(value):
    # 값이 변화했을 때 호출됨
    # value에는 변경 후의 값이 전달됩니다
    pass
)

# 이벤트 핸들링 정지
domain.unsubscribe_model(callback_id)

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### listRatings

모든 레이팅 카테고리에 대한 플레이어의 레이팅 점수를 취득합니다<br>

플레이어의 현재 레이팅 값을 모두 취득합니다.<br>
게임에 여러 레이팅 카테고리(예: "랭크 배틀"과 "아레나")가 있는 경우, 각각의 점수가 반환됩니다.<br>

프로필 화면이나 전적 화면을 만들 때 사용합니다. 예를 들어 "랭크 배틀: 1823, 아레나: 1547"과 같이 표시할 수 있습니다.<br>
플레이어의 레이팅은 레이팅이 적용되는 매치에 처음 참가했을 때 자동으로 생성되며, 초기값(일반적으로 1500)부터 시작합니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| pageToken | string |  | |  |  ~ 1024자 | 데이터 취득을 시작할 위치를 지정하는 토큰 |
| limit | int |  | | 30 | 1 ~ 1000 | 조회한 데이터 건수 |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| items | [List&lt;EzRating&gt;](#ezrating) | 레이팅 리스트|
| nextPageToken | string | 목록의 나머지를 취득하기 위한 페이지 토큰|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var items = await domain.RatingsAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var it = domain.Ratings(
    );
    List<EzRating> items = new List<EzRating>();
    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;
        }
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    const auto It = Domain->Ratings(
    );
    TArray<Gs2::UE5::Matchmaking::Model::FEzRatingPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeRatings(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeRatings(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeRatings(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeRatings(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->SubscribeRatings(
        []() {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->UnsubscribeRatings(CallbackId);

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### createVote

대전 결과 보고용 서명된 투표용지를 생성합니다<br>

대전 결과를 보고할 때 사용하는 투표용지(밸럿)를 생성합니다.<br>
레이팅이 적용되는 대전이 끝난 후, 각 플레이어는 누가 이기고 누가 졌는지 보고해야 합니다. 이 API는 플레이어의 신원 정보와 암호 서명이 포함된 위변조 방지 투표용지를 생성합니다.<br>

대전 결과 보고 흐름:<br>
1. 대전이 종료되고, 각 플레이어의 게임 클라이언트가 CreateVote를 호출하여 서명된 투표용지를 취득한다<br>
2. 각 플레이어가 투표용지와 대전 결과를 Vote API로 전송한다<br>
3. 서버가 모든 투표를 집계하여 다수결로 최종 결과를 결정한다<br>
4. 확정된 결과에 따라 플레이어의 레이팅이 업데이트된다<br>

파라미터:<br>
- ratingName: 이 대전이 속한 레이팅 카테고리의 이름(예: "ranked_battle")<br>
- gatheringName: 이 대전이 진행된 기어링(매치메이킹 룸)의 이름<br>
- numberOfPlayer: 대전 참가 인원 수(2~10명)<br>
- keyId: 투표용지 서명에 사용할 암호화 키(커스텀 키를 설정하지 않은 경우 기본 키를 사용)<br>

반환된 투표용지 본문과 서명은 Vote 또는 VoteMultiple API 호출에 필요합니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| ratingName | string |  | ✓|  |  ~ 128자 | 레이팅 모델 이름<br>레이팅 모델 고유의 이름. 영숫자 및 -(하이픈), _(밑줄), .(마침표)로 지정합니다. |
| gatheringName | string |  | ✓| UUID |  ~ 128자 | 개더링 이름<br>개더링의 고유한 이름을 보유합니다.<br>이름은 UUID(Universally Unique Identifier) 형식으로 자동 생성되며, 개더링을 식별하기 위해 사용됩니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| numberOfPlayer | int |  | ✓|  | 2 ~ 10 | 참가 인원 |
| keyId | string |  | | "grn:gs2:{region}:{ownerId}:key:default:key:default" |  ~ 1024자 | 암호화 키 GRN |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzBallot](#ezballot) | 투표용지|
| body | string | 서명 대상 데이터|
| signature | string | 서명 데이터|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Ballot(
        ratingName: "rating-0001",
        gatheringName: "gathering-0001",
        numberOfPlayer: 4,
        keyId: "key-0001"
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Ballot(
        ratingName: "rating-0001",
        gatheringName: "gathering-0001",
        numberOfPlayer: 4,
        keyId: "key-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Ballot(
        "rating-0001", // ratingName
        "gathering-0001", // gatheringName
        4, // numberOfPlayer
        "key-0001" // keyId
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).me(game_session).ballot(
        "rating-0001",
        "gathering-0001",
        4,
        "key-0001"
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Ballot(
        ratingName: "rating-0001",
        gatheringName: "gathering-0001",
        numberOfPlayer: 4,
        keyId: "key-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Ballot(
        ratingName: "rating-0001",
        gatheringName: "gathering-0001",
        numberOfPlayer: 4,
        keyId: "key-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Ballot(
        "rating-0001", // ratingName
        "gathering-0001", // gatheringName
        4, // numberOfPlayer
        "key-0001" // keyId
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Matchmaking::Model::FBallot> value) {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->Unsubscribe(CallbackId);

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).me(game_session).ballot(
        "rating-0001",
        "gathering-0001",
        4,
        "key-0001"
    )

# 이벤트 핸들링 시작
var callback_id = domain.subscribe_model(func(value):
    # 값이 변화했을 때 호출됨
    # value에는 변경 후의 값이 전달됩니다
    pass
)

# 이벤트 핸들링 정지
domain.unsubscribe_model(callback_id)

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### vote

대전 결과 투표를 제출합니다<br>

대전 후, 각 플레이어가 이 API를 개별적으로 호출하여 누가 이기고 누가 졌는지 보고합니다.<br>
CreateVote로 취득한 투표용지 본문과 서명, 그리고 대전 결과(각 플레이어의 순위나 승패 목록)를 전달합니다.<br>

투표 방식:<br>
- 첫 번째 플레이어가 투표한 후, 다른 플레이어들이 투표할 수 있는 유예 시간은 5분입니다<br>
- 5분 이내에 모든 플레이어가 투표하면 결과가 즉시 확정됩니다<br>
- 5분 이내에 일부 플레이어가 투표하지 않으면, 그때까지 접수된 투표 내용으로 다수결에 따라 결과가 결정됩니다<br>
- 표가 동수인 경우(예: 2명이 "플레이어 A 승리", 2명이 "플레이어 B 승리"), 결과는 폐기되고 레이팅은 업데이트되지 않습니다(이 동작은 스크립트로 커스터마이즈할 수 있습니다)<br>

가장 단순한 방식으로, 각 플레이어가 독립적으로 투표합니다. 단점은 결과 반영에 최대 5분이 걸릴 수 있다는 점입니다.<br>

즉시 결과를 반영하고 싶다면 VoteMultiple을 사용하세요. 승리한 플레이어가 전원의 투표용지를 모아서 함께 전송합니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| ballotBody | string |  | ✓|  |  ~ 1024자 | 투표용지의 서명 대상 데이터 |
| ballotSignature | string |  | ✓|  |  ~ 256자 | 투표용지의 서명 |
| gameResults | [List&lt;EzGameResult&gt;](#ezgameresult) |  | |  | 0 ~ 10 items | 투표 내용. 대전을 진행한 플레이어 그룹 1에 속한 사용자 ID 리스트 |
| keyId | string |  | | "grn:gs2:{region}:{ownerId}:key:default:key:default" |  ~ 1024자 | 암호화 키 GRN |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzBallot](#ezballot) | 투표용지|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    var result = await domain.VoteAsync(
        ballotBody: "ballotBody...",
        ballotSignature: "ballotSignature...",
        gameResults: new List<Gs2.Unity.Gs2Matchmaking.Model.EzGameResult> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 1,
                UserId = "user-0001",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 2,
                UserId = "user-0002",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 2,
                UserId = "user-0003",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 3,
                UserId = "user-0004",
            },
        },
        keyId: "key-0001"
    );
    var item = await result.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    var future = domain.VoteFuture(
        ballotBody: "ballotBody...",
        ballotSignature: "ballotSignature...",
        gameResults: new List<Gs2.Unity.Gs2Matchmaking.Model.EzGameResult> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 1,
                UserId = "user-0001",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 2,
                UserId = "user-0002",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 2,
                UserId = "user-0003",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 3,
                UserId = "user-0004",
            },
        },
        keyId: "key-0001"
    );
    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;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    );
    const auto Future = Domain->Vote(
        "ballotBody...", // ballotBody
        "ballotSignature...", // ballotSignature
        []
        {
            auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::Matchmaking::Model::FEzGameResult>>>();
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(1))
                ->WithUserId(TOptional<FString>("user-0001"))
            );
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(2))
                ->WithUserId(TOptional<FString>("user-0002"))
            );
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(2))
                ->WithUserId(TOptional<FString>("user-0003"))
            );
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(3))
                ->WithUserId(TOptional<FString>("user-0004"))
            );
            return v;
        }(), // gameResults
        "key-0001" // keyId
    );
    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();

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    )

var async_result = await domain.vote(
    "ballotBody...", # ballot_body
    "ballotSignature...", # ballot_signature
    [
        Gs2MatchmakingEzGameResult.new()
            .with_rank(1)
            .with_user_id("user-0001"),
        Gs2MatchmakingEzGameResult.new()
            .with_rank(2)
            .with_user_id("user-0002"),
        Gs2MatchmakingEzGameResult.new()
            .with_rank(2)
            .with_user_id("user-0003"),
        Gs2MatchmakingEzGameResult.new()
            .with_rank(3)
            .with_user_id("user-0004"),
    ], # game_results
    "key-0001" # key_id
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---

### voteMultiple

모든 투표용지를 모아 한 번에 제출하여 대전 결과를 즉시 확정합니다<br>

각 플레이어가 개별적으로 투표하는 방식(최대 5분 소요) 대신, 승리한 플레이어가 전원의 서명된 투표용지를 모아 한 번에 제출합니다. 이를 통해 결과가 즉시 확정됩니다.<br>

권장 흐름:<br>
1. 대전 종료 — 각 플레이어가 CreateVote를 호출하여 서명된 투표용지를 취득한다<br>
2. 각 플레이어가 게임의 통신 수단(게임 서버나 P2P 통신 등)을 이용해 자신의 투표용지(본문 + 서명)를 승리한 측의 플레이어에게 전달한다<br>
3. 승리한 측의 플레이어가 VoteMultiple을 호출하여 수집한 모든 투표용지와 대전 결과를 전송한다<br>
4. 결과가 즉시 확정되고 레이팅이 업데이트된다<br>

왜 승리한 측이 투표용지를 모으는가:<br>
- 패배한 측은 이겼다고 거짓말할 이유가 없지만(얻을 것이 없으므로), 투표용지 제출을 거부할 수도 있습니다<br>
- 패배한 측이 협조하지 않더라도, 과반수의 투표용지(절반 초과)만 있으면 결과는 승인됩니다<br>
- 예를 들어 2대2 대전에서 승리한 2명이 투표용지를 제출하면 4명 중 2명분 — 과반수로 충분합니다<br>

구현은 다소 복잡해지지만 결과가 즉시 반영되므로 플레이어 경험 측면에서는 더 나은 방식입니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| signedBallots | [List&lt;EzSignedBallot&gt;](#ezsignedballot) |  | |  | 0 ~ 10 items | 서명이 첨부된 투표용지 리스트 |
| gameResults | [List&lt;EzGameResult&gt;](#ezgameresult) |  | |  | 0 ~ 10 items | 투표 내용. 대전을 진행한 플레이어 그룹 1에 속한 사용자 ID 리스트 |
| keyId | string |  | | "grn:gs2:{region}:{ownerId}:key:default:key:default" |  ~ 1024자 | 암호화 키 GRN |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzBallot](#ezballot) | 투표용지|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    var result = await domain.VoteMultipleAsync(
        signedBallots: new List<Gs2.Unity.Gs2Matchmaking.Model.EzSignedBallot> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzSignedBallot() {
                Body = "aaa",
                Signature = "bbb",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzSignedBallot() {
                Body = "aaa",
                Signature = "bbb",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzSignedBallot() {
                Body = "aaa",
                Signature = "bbb",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzSignedBallot() {
                Body = "aaa",
                Signature = "bbb",
            },
        },
        gameResults: new List<Gs2.Unity.Gs2Matchmaking.Model.EzGameResult> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 1,
                UserId = "user-0001",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 2,
                UserId = "user-0002",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 2,
                UserId = "user-0003",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 3,
                UserId = "user-0004",
            },
        },
        keyId: "key-0001"
    );
    var item = await result.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    var future = domain.VoteMultipleFuture(
        signedBallots: new List<Gs2.Unity.Gs2Matchmaking.Model.EzSignedBallot> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzSignedBallot() {
                Body = "aaa",
                Signature = "bbb",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzSignedBallot() {
                Body = "aaa",
                Signature = "bbb",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzSignedBallot() {
                Body = "aaa",
                Signature = "bbb",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzSignedBallot() {
                Body = "aaa",
                Signature = "bbb",
            },
        },
        gameResults: new List<Gs2.Unity.Gs2Matchmaking.Model.EzGameResult> {
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 1,
                UserId = "user-0001",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 2,
                UserId = "user-0002",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 2,
                UserId = "user-0003",
            },
            new Gs2.Unity.Gs2Matchmaking.Model.EzGameResult() {
                Rank = 3,
                UserId = "user-0004",
            },
        },
        keyId: "key-0001"
    );
    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;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    );
    const auto Future = Domain->VoteMultiple(
        []
        {
            auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::Matchmaking::Model::FEzSignedBallot>>>();
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzSignedBallot>()
                ->WithBody(TOptional<FString>("aaa"))
                ->WithSignature(TOptional<FString>("bbb"))
            );
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzSignedBallot>()
                ->WithBody(TOptional<FString>("aaa"))
                ->WithSignature(TOptional<FString>("bbb"))
            );
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzSignedBallot>()
                ->WithBody(TOptional<FString>("aaa"))
                ->WithSignature(TOptional<FString>("bbb"))
            );
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzSignedBallot>()
                ->WithBody(TOptional<FString>("aaa"))
                ->WithSignature(TOptional<FString>("bbb"))
            );
            return v;
        }(), // signedBallots
        []
        {
            auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::Matchmaking::Model::FEzGameResult>>>();
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(1))
                ->WithUserId(TOptional<FString>("user-0001"))
            );
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(2))
                ->WithUserId(TOptional<FString>("user-0002"))
            );
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(2))
                ->WithUserId(TOptional<FString>("user-0003"))
            );
            v->Add(
                MakeShared<Gs2::UE5::Matchmaking::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(3))
                ->WithUserId(TOptional<FString>("user-0004"))
            );
            return v;
        }(), // gameResults
        "key-0001" // keyId
    );
    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();

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    )

var async_result = await domain.vote_multiple(
    [
        Gs2MatchmakingEzSignedBallot.new()
            .with_body("aaa")
            .with_signature("bbb"),
        Gs2MatchmakingEzSignedBallot.new()
            .with_body("aaa")
            .with_signature("bbb"),
        Gs2MatchmakingEzSignedBallot.new()
            .with_body("aaa")
            .with_signature("bbb"),
        Gs2MatchmakingEzSignedBallot.new()
            .with_body("aaa")
            .with_signature("bbb"),
    ], # signed_ballots
    [
        Gs2MatchmakingEzGameResult.new()
            .with_rank(1)
            .with_user_id("user-0001"),
        Gs2MatchmakingEzGameResult.new()
            .with_rank(2)
            .with_user_id("user-0002"),
        Gs2MatchmakingEzGameResult.new()
            .with_rank(2)
            .with_user_id("user-0003"),
        Gs2MatchmakingEzGameResult.new()
            .with_rank(3)
            .with_user_id("user-0004"),
    ], # game_results
    "key-0001" # key_id
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


---

### getJoinedSeasonGathering

특정 시즌에서 플레이어가 참가한 시즌 개더링 조회<br>

지정된 시즌 번호에서 플레이어가 속한 시즌 개더링을 조회합니다.<br>
현재 시즌에서 플레이어가 어느 매치 그룹에 있는지 확인할 때 사용합니다. 예를 들어, 앱 재시작 후 매치 로비 화면을 복원하는 경우입니다.<br>

지정된 시즌에서 플레이어가 시즌 개더링에 참가하지 않은 경우, 또는 개더링이 이미 존재하지 않는 경우 정보는 반환되지 않습니다.<br>
이 경우에는 DoSeasonMatchmaking으로 새로운 매치메이킹 검색을 시작해 주세요.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| seasonName | string |  | ✓|  |  ~ 128자 | 시즌 모델 이름<br>시즌 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| season | long |  | |  | 0 ~ 9223372036854775805 | 시즌 |
| gameSession | GameSession | | ✓|  |  | GameSession |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzJoinedSeasonGathering](#ezjoinedseasongathering) | 시즌 개더링|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Season(
        seasonName: "season-0001",
        season: 0
    ).JoinedSeasonGathering(
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Season(
        seasonName: "season-0001",
        season: 0
    ).JoinedSeasonGathering(
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Season(
        "season-0001", // seasonName
        0 // season
    )->JoinedSeasonGathering(
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).me(game_session).season(
        "season-0001",
        0
    ).joined_season_gathering(
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Season(
        seasonName: "season-0001",
        season: 0
    ).JoinedSeasonGathering(
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Season(
        seasonName: "season-0001",
        season: 0
    ).JoinedSeasonGathering(
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Season(
        "season-0001", // seasonName
        0 // season
    )->JoinedSeasonGathering(
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Matchmaking::Model::FJoinedSeasonGathering> value) {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->Unsubscribe(CallbackId);

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).me(game_session).season(
        "season-0001",
        0
    ).joined_season_gathering(
    )

# 이벤트 핸들링 시작
var callback_id = domain.subscribe_model(func(value):
    # 값이 변화했을 때 호출됨
    # value에는 변경 후의 값이 전달됩니다
    pass
)

# 이벤트 핸들링 정지
domain.unsubscribe_model(callback_id)

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### listJoinedSeasonGatherings

플레이어가 참가한 시즌 개더링 목록 조회<br>

플레이어가 현재 멤버로 속해 있는 모든 시즌 개더링을 조회합니다.<br>
대전 이력이나 활성 대전 화면을 표시할 때 사용합니다. 예를 들어, 이번 시즌에 플레이어가 참가 중이거나 참가한 랭크전을 목록으로 표시할 수 있습니다.<br>

시즌 이름으로 필터링하여 특정 랭크 모드(예: 「랭크 1v1」만)의 대전만 표시할 수도 있습니다.<br>

주요 용도:<br>
- 게임 실행 시 플레이어의 현재 활성 대전을 표시<br>
- 대전 이력 화면을 구성<br>
- 새로운 매치메이킹 검색을 시작하기 전에 플레이어가 이미 대전 중인지 확인

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| seasonName | string |  | |  |  ~ 128자 | 시즌 모델 이름<br>시즌 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| items | [List&lt;EzJoinedSeasonGathering&gt;](#ezjoinedseasongathering) | 시즌 개더링 목록|
| nextPageToken | string | 목록의 나머지를 취득하기 위한 페이지 토큰|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Season(
        seasonName: "season-0001",
        season: 0
    );
    var items = await domain.JoinedSeasonGatheringsAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Season(
        seasonName: "season-0001",
        season: 0
    );
    var it = domain.JoinedSeasonGatherings(
    );
    List<EzJoinedSeasonGathering> items = new List<EzJoinedSeasonGathering>();
    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;
        }
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Season(
        "season-0001", // seasonName
        0 // season
    );
    const auto It = Domain->JoinedSeasonGatherings(
    );
    TArray<Gs2::UE5::Matchmaking::Model::FEzJoinedSeasonGatheringPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Season(
        seasonName: "season-0001",
        season: 0
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeJoinedSeasonGatherings(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeJoinedSeasonGatherings(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Season(
        seasonName: "season-0001",
        season: 0
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeJoinedSeasonGatherings(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeJoinedSeasonGatherings(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Season(
        "season-0001", // seasonName
        0 // season
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->SubscribeJoinedSeasonGatherings(
        []() {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->UnsubscribeJoinedSeasonGatherings(CallbackId);

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### doSeasonMatchmaking

참가 가능한 시즌 매치를 검색하여 참가합니다<br>

플레이어의 티어 내에서 빈 자리가 있는 시즌 기어링(영속적인 매치메이킹 그룹)을 검색하여 자동으로 참가합니다.<br>
플레이어의 티어는 연동된 GS2-Experience 모델의 경험치 레벨에 따라 결정되므로, 실력이 비슷한 플레이어끼리 매칭됩니다.<br>

일반적인 DoMatchmaking과 비슷한 구조이지만, 티어에 따른 그룹 분류가 있습니다:<br>
- 한 번의 호출로는 일정 시간만 검색합니다. 아직 매치를 찾지 못한 경우 `matchmakingContextToken`이 반환됩니다.<br>
- 다음 호출 시 이 토큰을 전달하면 이전 검색을 이어서 재개할 수 있습니다.<br>
- 매치가 발견될 때까지 반복해서 호출하세요.<br>

모든 시즌 기어링을 검색해도 빈 자리가 없는 경우, 시즌 기어링과 토큰 모두 `null`로 반환됩니다.<br>
일반 매치메이킹에서는 직접 새로운 기어링을 생성하지만, 시즌 매치메이킹에서는 필요에 따라 시스템이 자동으로 새로운 시즌 기어링을 생성합니다.<br>

일반적인 시즌 매치메이킹 흐름:<br>
1. DoSeasonMatchmaking을 루프로 호출하며 매번 토큰을 전달한다<br>
2. 시즌 기어링이 반환됨 → 매치 성립, 게임으로 진행<br>
3. 둘 다 null → 현재 이용 가능한 매치가 없음. "검색 중" 화면을 표시하고 잠시 대기 후 재시도

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| seasonName | string |  | ✓|  |  ~ 128자 | 시즌 모델 이름<br>시즌 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| gameSession | GameSession | | ✓|  |  | GameSession |
| matchmakingContextToken | string |  | |  |  ~ 5120자 | 검색 재개에 사용하는 매치메이킹 상태를 보유하는 토큰 |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzSeasonGathering](#ezseasongathering) | 참가한 시즌 개더링|
| matchmakingContextToken | string | 매치메이킹 상태를 보유하는 토큰|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Season(
        seasonName: "season-0001",
        season: 0
    );
    var items = await domain.DoSeasonMatchmakingAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Season(
        seasonName: "season-0001",
        season: 0
    );
    var it = domain.DoSeasonMatchmaking(
    );

    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;
        }
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Season(
        "season-0001", // seasonName
        0 // season
    );
    const auto It = Domain->DoSeasonMatchmaking(
    );

    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


---

### getSeasonGathering

시즌 기어링의 현재 상태를 취득합니다<br>

특정 시즌 기어링의 상세 정보를 취득합니다. 참가자 목록과 소속 티어 정보가 포함됩니다.<br>
시즌 매치의 로비나 대기 화면을 표시할 때 사용합니다. 예를 들어 "골드 티어 매치 #42: 3/4명 참가 중"과 같은 화면을 표시할 수 있습니다.<br>

정확한 시즌 기어링을 특정하려면 시즌 번호, 티어, 기어링 이름을 지정해야 합니다.<br>
이 정보는 DoSeasonMatchmaking을 통해 시즌 기어링 참가에 성공했을 때 반환됩니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| seasonName | string |  | ✓|  |  ~ 128자 | 시즌 모델 이름<br>시즌 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| season | long |  | |  | 0 ~ 9223372036854775805 | 시즌 |
| tier | long |  | ✓|  | 0 ~ 9223372036854775805 | 티어<br>비슷한 랭크의 플레이어를 그룹화하기 위한 티어 레벨입니다.<br>SeasonModel에서 지정된 GS2-Experience 모델에서의 플레이어 랭크에 따라 결정됩니다.<br>플레이어는 동일한 티어의 플레이어와만 매칭되어 공평한 대전이 보장됩니다. |
| seasonGatheringName | string |  | ✓| UUID |  ~ 128자 | 시즌 게더링명<br>시즌 게더링 고유의 이름입니다. 영숫자 및 -(하이픈), _(언더스코어), .(마침표)로 지정합니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzSeasonGathering](#ezseasongathering) | 시즌 개더링|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).Season(
        seasonName: "season-0001",
        season: 0
    ).SeasonGathering(
        tier: 0,
        seasonGatheringName: "gathering-0001"
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).Season(
        seasonName: "season-0001",
        season: 0
    ).SeasonGathering(
        tier: 0,
        seasonGatheringName: "gathering-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->User(
        "user-0001" // userId
    )->Season(
        "season-0001", // seasonName
        0 // season
    )->SeasonGathering(
        0, // tier
        "gathering-0001" // seasonGatheringName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).user(
        "user-0001"
    ).season(
        "season-0001",
        0
    ).season_gathering(
        0,
        "gathering-0001"
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).Season(
        seasonName: "season-0001",
        season: 0
    ).SeasonGathering(
        tier: 0,
        seasonGatheringName: "gathering-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).Season(
        seasonName: "season-0001",
        season: 0
    ).SeasonGathering(
        tier: 0,
        seasonGatheringName: "gathering-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->User(
        "user-0001" // userId
    )->Season(
        "season-0001", // seasonName
        0 // season
    )->SeasonGathering(
        0, // tier
        "gathering-0001" // seasonGatheringName
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Matchmaking::Model::FSeasonGathering> value) {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->Unsubscribe(CallbackId);

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).user(
        "user-0001"
    ).season(
        "season-0001",
        0
    ).season_gathering(
        0,
        "gathering-0001"
    )

# 이벤트 핸들링 시작
var callback_id = domain.subscribe_model(func(value):
    # 값이 변화했을 때 호출됨
    # value에는 변경 후의 값이 전달됩니다
    pass
)

# 이벤트 핸들링 정지
domain.unsubscribe_model(callback_id)

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### getSeasonModel

특정 시즌 매치메이킹 설정의 상세 정보를 취득합니다<br>

이름을 지정하여 하나의 시즌 모델의 상세 정보를 취득합니다.<br>
특정 랭크 모드의 규칙이나 설정을 표시할 때 사용합니다. 예를 들어 모드 선택 화면에서 "랭크 1대1: 최대 2명, 아레나 경험치로 티어 결정"과 같이 표시할 수 있습니다.<br>

응답에는 다음이 포함됩니다:<br>
- maximumParticipants: 한 경기에 참가할 수 있는 인원 수<br>
- experienceModelId: 플레이어의 티어를 결정하는 데 사용되는 GS2-Experience 모델. 플레이어의 경험치 레벨이 티어에 매핑되며, 같은 티어 내의 플레이어끼리만 매칭됩니다.<br>
- challengePeriodEventId: 설정되어 있는 경우, 지정된 기간 동안만 랭크전에 참가할 수 있습니다(예: 주말만, 매일 19시~22시 등)

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |
| seasonName | string |  | ✓|  |  ~ 128자 | 시즌 모델 이름<br>시즌 모델 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| item | [EzSeasonModel](#ezseasonmodel) | 시즌 모델|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).SeasonModel(
        seasonName: "season-0001"
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).SeasonModel(
        seasonName: "season-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->SeasonModel(
        "season-0001" // seasonName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).season_model(
        "season-0001"
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).SeasonModel(
        seasonName: "season-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    ).SeasonModel(
        seasonName: "season-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    )->SeasonModel(
        "season-0001" // seasonName
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Matchmaking::Model::FSeasonModel> value) {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->Unsubscribe(CallbackId);

```

**Godot**
```gdscript

var domain = ez.matchmaking.namespace_(
        "namespace-0001"
    ).season_model(
        "season-0001"
    )

# 이벤트 핸들링 시작
var callback_id = domain.subscribe_model(func(value):
    # 값이 변화했을 때 호출됨
    # value에는 변경 후의 값이 전달됩니다
    pass
)

# 이벤트 핸들링 정지
domain.unsubscribe_model(callback_id)

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

### listSeasonModels

시즌 매치메이킹 설정 목록을 취득합니다<br>

네임스페이스에 정의되어 있는 모든 시즌 모델을 취득합니다.<br>
시즌 매치메이킹은 랭크전이 있는 대전 게임을 위해 설계되었습니다. "시즌 1", "시즌 2"와 같이 기간별로 구분하고, 플레이어를 실력에 따라 티어(등급)로 나누어 매칭합니다.<br>

일반적인 기어링 기반 매치메이킹(임시 방을 생성하는 방식)과 달리, 시즌 매치메이킹에서는 시즌 동안 계속 유지되는 영속적인 그룹을 사용합니다.<br>
같은 티어의 플레이어끼리 매칭되므로 공정한 대전이 가능합니다.<br>

각 시즌 모델은 다음을 정의합니다:<br>
- 한 경기당 최대 참가 인원<br>
- 플레이어의 티어를 계산하는 데 사용되는 경험치 모델(GS2-Experience와 연동하여 브론즈, 실버, 골드 등의 실력대를 결정합니다)<br>
- 선택적인 챌린지 기간 이벤트(GS2-Schedule과 연동하여 대전 가능한 시간대를 제한할 수 있습니다)<br>

이용 가능한 랭크 모드 목록을 표시할 때 사용합니다. 예를 들어 "랭크 1대1", "랭크 3대3"과 같은 화면입니다.

#### Request

|  | 타입 | 활성화 조건 | 필수 | 기본값 | 값 제한 | 설명 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128자 | 네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다. |

#### Result

|  | 타입 | 설명 |
| --- | --- | --- |
| items | [List&lt;EzSeasonModel&gt;](#ezseasonmodel) | 시즌 모델 목록|

#### 구현 예제




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    var items = await domain.SeasonModelsAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    var it = domain.SeasonModels(
    );
    List<EzSeasonModel> items = new List<EzSeasonModel>();
    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;
        }
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    );
    const auto It = Domain->SeasonModels(
    );
    TArray<Gs2::UE5::Matchmaking::Model::FEzSeasonModelPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


##### 값 변경 이벤트 핸들링




**Unity (UniTask)**
```csharp
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeSeasonModels(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeSeasonModels(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Matchmaking.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.SubscribeSeasonModels(
        () => {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    domain.UnsubscribeSeasonModels(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Matchmaking->Namespace(
        "namespace-0001" // namespaceName
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->SubscribeSeasonModels(
        []() {
            // 리스트의 요소가 변화했을 때 호출됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->UnsubscribeSeasonModels(CallbackId);

```


**⚠️ Warning**

이 이벤트는 SDK가 가진 로컬 캐시의 값이 변경되었을 때 호출됩니다.

로컬 캐시는 SDK가 가진 API의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-Distributor를 통한 스탬프 시트의 실행, 또는 GS2-Gateway의 알림을 활성화한 GS2-JobQueue의 실행에 의해 변화한 것만이 대상이 됩니다.

따라서 이 방법 이외로 값이 변경된 경우 콜백은 호출되지 않습니다.

---

## 이벤트 핸들러

### OnJoinNotification

개더링에 새로운 참가자가 참가했을 때 사용하는 푸시 알림

 | 이름 | 타입 | 설명 |
| --- | --- | --- |
| namespaceName | string |네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.|
| gatheringName | string |개더링 이름<br>개더링의 고유한 이름을 보유합니다.<br>이름은 UUID(Universally Unique Identifier) 형식으로 자동 생성되며, 개더링을 식별하기 위해 사용됩니다.|
| joinUserId | string |사용자ID|

#### 구현 예제





**Unity (UniTask)**
```csharp

    gs2.Matchmaking.OnJoinNotification += notification =>
    {
        var namespaceName = notification.NamespaceName;
        var gatheringName = notification.GatheringName;
        var joinUserId = notification.JoinUserId;
    };
```

**Unity (Vanilla)**
```cs

    gs2.Matchmaking.OnJoinNotification += notification =>
    {
        var namespaceName = notification.NamespaceName;
        var gatheringName = notification.GatheringName;
        var joinUserId = notification.JoinUserId;
    };
```

**Unreal Engine 5**
```cpp

    Gs2->Matchmaking->OnJoinNotification().AddLambda([](const auto Notification)
    {
        const auto NamespaceName = Notification->NamespaceNameValue;
        const auto GatheringName = Notification->GatheringNameValue;
        const auto JoinUserId = Notification->JoinUserIdValue;
    });
```

**Godot**
```gdscript

    ez.matchmaking.join_notification.connect(func(notification):
        var namespace_name = notification.namespace_name
        var gathering_name = notification.gathering_name
        var join_user_id = notification.join_user_id
    )
```


---

### OnLeaveNotification

개더링에서 참가자가 이탈했을 때 사용하는 푸시 알림

 | 이름 | 타입 | 설명 |
| --- | --- | --- |
| namespaceName | string |네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.|
| gatheringName | string |개더링 이름<br>개더링의 고유한 이름을 보유합니다.<br>이름은 UUID(Universally Unique Identifier) 형식으로 자동 생성되며, 개더링을 식별하기 위해 사용됩니다.|
| leaveUserId | string |사용자ID|

#### 구현 예제





**Unity (UniTask)**
```csharp

    gs2.Matchmaking.OnLeaveNotification += notification =>
    {
        var namespaceName = notification.NamespaceName;
        var gatheringName = notification.GatheringName;
        var leaveUserId = notification.LeaveUserId;
    };
```

**Unity (Vanilla)**
```cs

    gs2.Matchmaking.OnLeaveNotification += notification =>
    {
        var namespaceName = notification.NamespaceName;
        var gatheringName = notification.GatheringName;
        var leaveUserId = notification.LeaveUserId;
    };
```

**Unreal Engine 5**
```cpp

    Gs2->Matchmaking->OnLeaveNotification().AddLambda([](const auto Notification)
    {
        const auto NamespaceName = Notification->NamespaceNameValue;
        const auto GatheringName = Notification->GatheringNameValue;
        const auto LeaveUserId = Notification->LeaveUserIdValue;
    });
```

**Godot**
```gdscript

    ez.matchmaking.leave_notification.connect(func(notification):
        var namespace_name = notification.namespace_name
        var gathering_name = notification.gathering_name
        var leave_user_id = notification.leave_user_id
    )
```


---

### OnCompleteNotification

매치메이킹이 성립했을 때 사용하는 푸시 알림

 | 이름 | 타입 | 설명 |
| --- | --- | --- |
| namespaceName | string |네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.|
| gatheringName | string |개더링 이름<br>개더링의 고유한 이름을 보유합니다.<br>이름은 UUID(Universally Unique Identifier) 형식으로 자동 생성되며, 개더링을 식별하기 위해 사용됩니다.|

#### 구현 예제





**Unity (UniTask)**
```csharp

    gs2.Matchmaking.OnCompleteNotification += notification =>
    {
        var namespaceName = notification.NamespaceName;
        var gatheringName = notification.GatheringName;
    };
```

**Unity (Vanilla)**
```cs

    gs2.Matchmaking.OnCompleteNotification += notification =>
    {
        var namespaceName = notification.NamespaceName;
        var gatheringName = notification.GatheringName;
    };
```

**Unreal Engine 5**
```cpp

    Gs2->Matchmaking->OnCompleteNotification().AddLambda([](const auto Notification)
    {
        const auto NamespaceName = Notification->NamespaceNameValue;
        const auto GatheringName = Notification->GatheringNameValue;
    });
```

**Godot**
```gdscript

    ez.matchmaking.complete_notification.connect(func(notification):
        var namespace_name = notification.namespace_name
        var gathering_name = notification.gathering_name
    )
```


---

### OnChangeRatingNotification

레이팅 값이 변동했을 때 사용하는 푸시 알림

 | 이름 | 타입 | 설명 |
| --- | --- | --- |
| namespaceName | string |네임스페이스 이름<br>네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.|
| ratingName | string |레이팅 이름<br>레이팅 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.|
| userId | string |사용자ID|
| rateValue | float |레이트 값<br>Glicko-2 알고리즘으로 계산된 플레이어의 현재 레이팅 점수입니다.<br>RatingModel에서 정의된 초기값(일반적으로 1500.0)이 기본값입니다.<br>대전 결과와 상대의 상대적인 실력에 따라 값이 증감합니다.|

#### 구현 예제





**Unity (UniTask)**
```csharp

    gs2.Matchmaking.OnChangeRatingNotification += notification =>
    {
        var namespaceName = notification.NamespaceName;
        var ratingName = notification.RatingName;
        var userId = notification.UserId;
        var rateValue = notification.RateValue;
    };
```

**Unity (Vanilla)**
```cs

    gs2.Matchmaking.OnChangeRatingNotification += notification =>
    {
        var namespaceName = notification.NamespaceName;
        var ratingName = notification.RatingName;
        var userId = notification.UserId;
        var rateValue = notification.RateValue;
    };
```

**Unreal Engine 5**
```cpp

    Gs2->Matchmaking->OnChangeRatingNotification().AddLambda([](const auto Notification)
    {
        const auto NamespaceName = Notification->NamespaceNameValue;
        const auto RatingName = Notification->RatingNameValue;
        const auto UserId = Notification->UserIdValue;
        const auto RateValue = Notification->RateValueValue;
    });
```

**Godot**
```gdscript

    ez.matchmaking.change_rating_notification.connect(func(notification):
        var namespace_name = notification.namespace_name
        var rating_name = notification.rating_name
        var user_id = notification.user_id
        var rate_value = notification.rate_value
    )
```


---



