권한
봇은 권한을 Discord 형태의 53비트 정수 비트필드로 받습니다. 비트와 의미는 Discord와 같고, 값은 GameVox의 기본 그룹·채널 권한 테이블에서 나옵니다. GameVox에 대응물이 없는 비트는 0을 반환합니다.
기본 → Discord 매핑
| Discord 비트 | 16진수 | GameVox 원본 |
|---|---|---|
| ADMINISTRATOR | 0x8 | groups.group_type IN ('owner', 'admin') |
| VIEW_CHANNEL | 0x400 | channel_permissions.view_channel / group_permissions.view_channels |
| READ_MESSAGE_HISTORY | 0x10000 | VIEW_CHANNEL과 동일(별도의 기록 토글은 없습니다) |
| SEND_MESSAGES | 0x800 | send_messages |
| MANAGE_MESSAGES | 0x2000 | manage_messages |
| EMBED_LINKS | 0x4000 | can_post_links |
| ATTACH_FILES | 0x8000 | send_files |
| ADD_REACTIONS | 0x40 | add_reactions |
| MENTION_EVERYONE | 0x20000 | v1에서는 관리자만 |
| CONNECT (voice) | 0x100000 | join_voice |
| SPEAK | 0x200000 | speak_in_voice |
| STREAM (screen share) | 0x200 | screen_share |
| USE_VAD | 0x2000000 | use_vad(기본값 true. false로 두면 눌러서 말하기가 됩니다) |
| KICK_MEMBERS | 0x2 | kick_users != 'deny' |
| BAN_MEMBERS | 0x4 | ban_users != 'deny' |
| MUTE_MEMBERS | 0x400000 | mute_users != 'deny' |
| MOVE_MEMBERS | 0x1000000 | move_users != 'deny' |
| MANAGE_CHANNELS | 0x10 | create_channels / edit_channels / delete_channels가 모두 'deny'가 아닐 것 |
| MANAGE_GUILD | 0x20 | edit_server != 'deny' |
| MANAGE_ROLES | 0x10000000 | manage_members |
| MANAGE_NICKNAMES | 0x8000000 | manage_members(MANAGE_ROLES와 묶여 있습니다) |
| CHANGE_NICKNAME | 0x4000000 | 항상 부여됩니다(Discord의 기본값과 같습니다) |
| MANAGE_WEBHOOKS | 0x20000000 | v1에서는 소유자 / 관리자 |
| VIEW_AUDIT_LOG | 0x80 | v1에서는 소유자 / 관리자 |
| PRIORITY_SPEAKER | 0x100 | priority_speaker |
| MANAGE_EVENTS | 0x200000000 | manage_events != 'deny' |
| CREATE_EVENTS | 0x100000000000 | manage_events != 'deny'(MANAGE_EVENTS와 묶여 있습니다) |
| MANAGE_GUILD_EXPRESSIONS | 0x40000000 | manage_emojis != 'deny' |
| CREATE_GUILD_EXPRESSIONS | 0x80000000000 | manage_emojis != 'deny'(묶여 있습니다) |
| DEAFEN_MEMBERS | 0x800000 | deafen_users != 'deny' |
| SEND_MESSAGES_IN_THREADS | 0x4000000000 | send_messages(SEND_MESSAGES와 묶여 있습니다) |
기본으로 켜져 있는 비트
거부되지 않은 모든 구성원에게 설정되며, Discord의 기본 역할 동작과 같습니다. 봇 로직이 이를 확인한다면, (차단된 경우가 아니라면) 항상 부여된 것으로 보입니다.
CREATE_INSTANT_INVITE(0x1)USE_APPLICATION_COMMANDS(0x80000000)USE_EXTERNAL_EMOJIS(0x40000)USE_EXTERNAL_STICKERS(0x2000000000)
항상 0을 반환하는 비트
GameVox에는 아직 대응물이 없어 설정되지 않은 것으로 보고됩니다. 이에 의존하는 봇은 기능을 부드럽게 축소해 동작하도록 만드세요(대부분의 라이브러리는 이미 거부된 비트를 “여기서는 지원하지 않는 기능”으로 처리합니다).
MANAGE_THREADS,USE_PUBLIC_THREADS,USE_PRIVATE_THREADS: v1에서 스레드는 자리표시 수준입니다.MODERATE_MEMBERS(타임아웃): 대응하는 기능이 없습니다.USE_EMBEDDED_ACTIVITIES: 액티비티 기능이 없습니다.USE_SOUNDBOARD,SEND_VOICE_MESSAGES: 구현되지 않았습니다.- 수익화 관련 비트: Premium Apps가 없습니다.
권한 계산
Discord의 7단계 알고리즘과 동일합니다.
- 길드의
@everyone권한에서 시작합니다. - 구성원이 가진 모든 역할을 OR로 합칩니다.
- 결과에 ADMINISTRATOR가 있으면 여기서 멈추고, 모든 권한을 가진 것으로 봅니다.
@everyone의 채널 오버라이드를 적용합니다(allow 다음 deny).- 각 역할의 채널 오버라이드를 적용합니다(allow 다음 deny).
- 해당 사용자의 채널 오버라이드를 적용합니다(allow 다음 deny).
- 채널이 카테고리 안에 있으면 카테고리의 오버라이드도 역할·사용자 단계에서 함께 적용됩니다.
아래에서 설명하는 차이는 2단계에서 드러납니다. GameVox 구성원은 그룹 하나에만 속하므로 OR로 합칠 역할이 하나뿐입니다. 구성원당 하나의 그룹을 참고하세요.
구성원당 하나의 그룹
Discord와 가장 크게 다른 동작입니다. GameVox 구성원은 서버마다 정확히 하나의 그룹에 속하는 반면, Discord 구성원은 여러 역할을 동시에 가질 수 있습니다. 그룹을 지정하면 이전 그룹은 대체됩니다.
역할 엔드포인트는 그대로 동작하고, 기존에 쓰던 라이브러리도 계속 호출합니다. 다만 그 하나의 그룹으로 해석될 뿐입니다.
| 호출 | 어떻게 되는지 |
|---|---|
PUT .../members/{id}/roles/{rid} | 구성원이 그 그룹으로 들어갑니다. 이전 그룹은 함께 유지되지 않고 대체됩니다. |
DELETE .../members/{id}/roles/{rid} | 제거합니다. 그것이 유일한 그룹이었다면 그룹이 없는 상태가 아니라 서버의 기본 그룹으로 되돌아갑니다. |
roles: [...]를 담은 PATCH .../members/{id} | 받아들인 뒤 목록에서 가장 상위 그룹으로 정리됩니다. 빈 목록은 기본 그룹을 의미합니다. |
평범한 member.roles.set([...])가 계속 동작하도록, 목록은 거부하지 않고 정리합니다. 가장 상위가 이기는 이유는 위치를 정하는 것이 랭크이기 때문입니다. 조정 그룹과 색상 그룹이 있다면 그 구성원은 조정자입니다.
그룹에는 업로드, 음성, 카메라, 화면 공유 상한이 있으며, 구성원은 속한 그룹 중 가장 넉넉한 상한을 적용받습니다. 그룹이 하나라면 그저 그 그룹의 상한입니다. 이것이 앱이 누군가를 두 그룹에 넣을 수 없는 또 다른 이유입니다. 그렇게 하면 운영자가 정한 상한을 우회하는 수단이 되기 때문입니다.
애플리케이션 자신의 그룹(설치가 만든 그룹)은 이 이야기와 무관합니다. 그 소속은 설치에 속하며, 어떤 앱도 자신을 넣거나 다른 앱을 빼낼 수 없습니다.
역할 계층
기본 groups.rank는 Discord의 role.position에 대응합니다. 봇은 자신의 최상위 역할 위치보다 아래에 있는 역할만 관리할 수 있으며, Discord의 규칙과 같습니다. 봇의 최상위 역할과 같거나 그보다 높은 역할에 대한 PATCH .../members/{id}/roles/{rid}는 403을 반환합니다.
타임아웃
Discord의 communication_disabled_until 필드에 대응하는 것은 v1 GameVox에 없습니다. 이 필드를 담아 구성원에게 PATCH하면 명확한 오류와 함께 400을 반환합니다. 대신 추방 / 음소거 / 차단을 사용하세요.