> For the complete documentation index, see [llms.txt](https://docs.ggwp.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ggwp.com/jp/ggwp-client-sdk/heno.md).

# 制裁への対応

クライアントSDKでは、すべてのチャネルにわたる警告と制裁の処理が可能です - `チャット`, `ゲーム` および `ボイス` 。これらはユーザーに次のいずれかの方法で付与できます [ダッシュボードから手動で](/jp/dasshubdoyzgaido/pureiy.md#sanctioning-a-player) または [automod](https://docs.ggwp.com/jp/ggwp-client-sdk/pages/c7b07dc0ff67de20718baa1c0e076a64f9f24a82#id-4.2-ggwp-automod).&#x20;

SDKの初期化後にSanctionsが利用可能になります：

```csharp
GGWPSDK.Instance?.InitializeSDK("user_id", "username");

if (GGWPSDK.Instance?.SanctionsAPI != null)
{
    // 制裁コールバックの準備ができています
}
```

#### Sanctionsの購読

```csharp
using GGWP.Sanctions;
using GGWP.Utils.Async;

// 認証前にサブスクリプションを作成できます
var subscriber = new Subscriber<ChannelSanctionsState>(
    GGWPSDK.Instance?.SanctionsAPI.SubscribeSanctionsState()
);

// ただし、リアルタイム更新はコード交換認証後にのみ開始されます
string authCode = GetAuthCodeFromYourBackend();
await GGWPSDK.Instance?.AuthManager.ExchangeAuthCode(authCode);

// これで接続が確立され、リアルタイム更新を受信できます
await foreach (var state in subscriber.GetStream())
{
    Debug.Log($"チャットの状態: {state.chat.status}");
    Debug.Log($"ゲームの状態: {state.game.status}");
    Debug.Log($"ボイスの状態: {state.voice.status}");
}
```

#### 制裁状態の監視

すべてのチャネルにわたる制裁状態の変更を購読します。リアルタイム更新は、認証を完了してから流れ始めることを忘れないでください：

```csharp
using GGWP.Sanctions;
using GGWP.Utils.Async;

var subscriber = new Subscriber<ChannelSanctionsState>(
    GGWPSDK.Instance?.SanctionsAPI.SubscribeSanctionsState()
);

await foreach (var state in subscriber.GetStream())
{
    // チャットチャネルを確認
    Debug.Log($"チャットの状態: {state.chat.status}");
    
    // ゲームチャネルを確認
    Debug.Log($"ゲームの状態: {state.game.status}");
    
    // ボイスチャネルを確認
    Debug.Log($"ボイスの状態: {state.voice.status}");
}
```

#### チャネルの状態を理解する

各チャネルには次のプロパティがあります：

```csharp
// 特定のチャネルの状態を取得
SanctionState chatState = state.chat;

// ステータス（有効またはミュート）
GGWP.Sanctions.Impl.MuteStatus status = chatState.status;

// 有効期限（ミュートの場合）
DateTime? expiryAt = chatState.expiryAt;

// 警告情報（警告済みの場合）
var warning = chatState.warning;

// 制裁の詳細（制裁済みの場合）
var sanction = chatState.sanction;
```

#### 初期状態

ユーザーに制裁がない場合、すべてのチャネルは有効状態になります。認証後に接続が確立されると、この初期状態を1回受け取ります：

```csharp
await foreach (var state in subscriber.GetStream())
{
    // すべてのチャネルは有効から開始
    Assert.AreEqual(state.chat.status, GGWP.Sanctions.Impl.MuteStatus.Active);
    Assert.AreEqual(state.game.status, GGWP.Sanctions.Impl.MuteStatus.Active);
    Assert.AreEqual(state.voice.status, GGWP.Sanctions.Impl.MuteStatus.Active);
    
    // 有効期限、警告、制裁なし
    Assert.Null(state.chat.expiryAt);
    Assert.Null(state.chat.warning);
    Assert.Null(state.chat.sanction);
    
    break;
}
```

#### 適用された制裁の処理

制裁が適用されたら、状態の変化を監視します。

```csharp
using System.Threading;

var subscriber = new Subscriber<ChannelSanctionsState>(
    GGWPSDK.Instance?.SanctionsAPI.SubscribeSanctionsState()
);

using var cts = new CancellationTokenSource();

await foreach (var state in subscriber.GetStream(cts.Token))
{
    if (state.game.status == GGWP.Sanctions.Impl.MuteStatus.Muted)
    {
        Debug.Log("ユーザーはゲームチャネルでミュートされています");
        
        // ミュートが解除される時刻を確認するため、有効期限をチェックします
        if (state.game.expiryAt != null)
        {
            Debug.Log($"ミュートの期限切れ時刻: {state.game.expiryAt}");
        }
        
        // 状態遷移を理解するために制裁の詳細を取得
        if (state.game.sanction != null)
        {
            var sanction = state.game.sanction.Value;
            Debug.Log($"前のステータス: {sanction.previousStatus}");
            Debug.Log($"現在のステータス: {sanction.currentStatus}");
        }
        
        break;
    }
}
```

#### 推奨される使用パターン

推奨されるパターンは、まず認証し、その後に制裁を購読することです。これにより、接続がすぐに確立され、初期状態情報を見逃しません：

```csharp
// 手順1: ユーザーを認証する
string authCode = GetAuthCodeFromYourBackend();
var authResult = await GGWPSDK.Instance?.AuthManager.ExchangeAuthCode(authCode);

if (authResult == GGWP.Impl.Result.Success)
{
    // 手順2: 次に制裁を購読する
    var subscriber = new Subscriber<ChannelSanctionsState>(
        GGWPSDK.Instance?.SanctionsAPI.SubscribeSanctionsState()
    );

    // 手順3: 制裁状態の更新をリアルタイムで処理する
    await foreach (var state in subscriber.GetStream())
    {
        // 発生した制裁状態の変化を処理する
        Debug.Log($"チャット: {state.chat.status}");
    }
}
```

#### キャンセルトークンの使用

キャンセルトークンを使ってサブスクリプションの寿命を制御します。これは、ユーザーがログアウトしたり特定の画面を閉じたりしたときなど、制裁の監視を停止したい場合に便利です：

```csharp
using System.Threading;

var cts = new CancellationTokenSource();

try
{
    await foreach (var state in subscriber.GetStream(cts.Token))
    {
        // 状態を処理
        
        if (someCondition)
        {
            cts.Cancel(); // リスニングを停止
            break;
        }
    }
}
catch (OperationCanceledException)
{
    Debug.Log("制裁の監視がキャンセルされました");
}
```
