> 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/chatto-na.md).

# チャット: 完全な統合例

以下は、Dynamic Token 認証、カスタム置換戦略、制裁監視、再認証処理を含む、典型的な Unity SDK の使用例を示す完全なサンプルです:

{% code fullWidth="true" %}

```csharp
using UnityEngine;
using System.Threading.Tasks;
using GGWP.Chat;
using GGWP.Sanctions;
using GGWP.Utils.Async;

public class GGWPIntegration : MonoBehaviour
{
    private Subscriber<ChannelSanctionsState> sanctionsSubscriber;
    private Subscriber<SanitizationResponse> sanitizationSubscriber;
    private Subscriber<GGWP.Impl.AuthStatus> authSubscriber;

    async void Start()
    {
        await InitializeSDK();
        // 制裁にサブスクライブする前に認証して、即時の WebSocket 接続を確立します
        await AuthenticateUser();
        ConfigureReplacementStrategy();
        MonitorAuthentication();
        // 認証後に制裁へサブスクライブして、即時のリアルタイム更新を取得します
        MonitorSanctions();
        MonitorSanitization();
    }

    async Task InitializeSDK()
    {
        if (GGWPSDK.Instance == null)
        {
            Debug.LogError("GGWPSDK は利用できません");
            return;
        }

        // 顧客 ID と任意のユーザー名で初期化します
        GGWPSDK.Instance.InitializeSDK("your_customer_id", "player_username");
        Debug.Log("SDK を初期化しました");
    }

    async Task AuthenticateUser()
    {
        // OAuth コード交換認証を使用します（推奨）
        // これにより、制裁更新用の WebSocket 接続も確立されます
        string authCode = GetAuthCodeFromBackend();
        
        try
        {
            var result = await GGWPSDK.Instance?.AuthManager.ExchangeAuthCode(authCode);

            if (result == GGWP.Impl.Result.Success)
            {
                Debug.Log("OAuth 認証に成功しました");
            }
        }
        catch (Exception ex)
        {
            Debug.LogError($"認証に失敗しました: {ex.Message}");
        }
    }

    void ConfigureReplacementStrategy()
    {
        // 任意: 使用するメッセージのバージョンを設定します
        // 設定しない場合は、UseFiltered 戦略を使うサービスの既定値が使用されます
        GGWPSDK.Instance?.ChatAPI.SetSanitizationConfig(new SanitizationConfigUpdate
        {
            client = new GGWP.Chat.Impl.SanitizationClientConfig
            {
                // AI に各メッセージに最適な置換戦略を選ばせます
                messageReplacementConfig = ReplacementStrategy.UseRecommended
            },
            service = null  // フィルタリング設定にはサービスの既定値を使用します
        });
    }

    async void MonitorAuthentication()
    {
        authSubscriber = new Subscriber<GGWP.Impl.AuthStatus>(
            GGWPSDK.Instance?.AuthManager.SubscribeAuthUpdates()
        );

        await foreach (var status in authSubscriber.GetStream())
        {
            switch (status.status)
            {
                case GGWP.Impl.AuthStatusName.CodeExchangeSession:
                    Debug.Log("OAuth セッションがアクティブです - 更新は自動的に処理されます");
                    break;
                    
                case GGWP.Impl.AuthStatusName.NoAuth:
                    // 非常にまれなケース: セッション更新に複数回連続で失敗しました
                    Debug.LogWarning("認証セッションを失いました - 再認証が必要です");
                    
                    if (status.error.ToNullable() != null)
                    {
                        Debug.LogError($"認証エラー: {status.error.ToNullable()}");
                    }
                    
                    // セッションを復元するために、別のコード交換を実行します
                    await ReauthenticateUser();
                    break;
            }
        }
    }

    private async Task ReauthenticateUser()
    {
        try
        {
            Debug.Log("ユーザーの再認証を試行しています...");
            
            // バックエンドから新しい認証コードを取得します
            string newAuthCode = GetAuthCodeFromBackend();
            
            // 新しいコードを交換して新しいセッションを取得します
            var result = await GGWPSDK.Instance?.AuthManager.ExchangeAuthCode(newAuthCode);
            
            if (result == GGWP.Impl.Result.Success)
            {
                Debug.Log("再認証に成功しました");
            }
            else
            {
                Debug.LogError("再認証に失敗しました");
                ShowLoginScreen();
            }
        }
        catch (Exception ex)
        {
            Debug.LogError($"再認証エラー: {ex.Message}");
            ShowLoginScreen();
        }
    }

    async void MonitorSanctions()
    {
        // WebSocket が接続されるように、認証後に制裁へサブスクライブします
        sanctionsSubscriber = new Subscriber<ChannelSanctionsState>(
            GGWPSDK.Instance?.SanctionsAPI.SubscribeSanctionsState()
        );

        await foreach (var state in sanctionsSubscriber.GetStream())
        {
            // ユーザーがチャットでミュートされているかを確認し、それに応じて UI を更新します
            if (state.chat.status == GGWP.Sanctions.Impl.MuteStatus.Muted)
            {
                Debug.Log("ユーザーはチャットでミュートされています");
                DisableChatInput();
                
                // 必要に応じて、ミュートの有効期限を表示します
                if (state.chat.expiryAt != null)
                {
                    ShowMuteExpiryNotification(state.chat.expiryAt.Value);
                }
            }
            else
            {
                EnableChatInput();
            }
        }
    }

    async void MonitorSanitization()
    {
        // ログ記録や分析のために、すべてのサニタイズイベントへサブスクライブします
        sanitizationSubscriber = new Subscriber<SanitizationResponse>(
            GGWPSDK.Instance?.ChatAPI.SubscribeSanitizedMessages()
        );

        await foreach (var sanitized in sanitizationSubscriber.GetStream())
        {
            LogMessageSanitization(sanitized);
        }
    }

    public async Task<bool> SendChatMessage(string message)
    {
        // ReplaceMessage は設定された置換戦略を使用します（この場合は UseRecommended）
        var replaced = await GGWPSDK.Instance?.ChatAPI.ReplaceMessage(
            new ChatMessage { message = message }
        );

        if (replaced == null)
        {
            Debug.Log("メッセージがブロックされました - ユーザーが制裁対象の可能性があります");
            ShowMessageBlockedNotification();
            return false;
        }

        // 返されるメッセージは、設定した ReplacementStrategy によって異なります
        // UseFiltered: アスタリスクで不適切な単語を置き換えます
        // UseReplaced: 代替語で不適切な単語を置き換えます
        // UseRecommended: AI が文脈に基づいて最適な版を選択します
        // UseOriginal: 元のメッセージは変更されません
        SendToChat(replaced.messageDetails.replacedMessage);
        return true;
    }

    private string GetAuthCodeFromBackend() 
    { 
        /* 実装してください - GGWP サービスから認証コードを取得するためにバックエンドを呼び出します */ 
        return ""; 
    }
    
    private void DisableChatInput() 
    { 
        /* 実装してください - チャット入力 UI を無効にします */ 
    }
    
    private void EnableChatInput() 
    { 
        /* 実装してください - チャット入力 UI を有効にします */ 
    }
    
    private void LogMessageSanitization(SanitizationResponse response) 
    { 
        /* 実装してください - 分析用にサニタイズイベントを記録します */ 
    }
    
    private void SendToChat(string message) 
    { 
        /* 実装してください - メッセージをチャットシステムに送信します */ 
    }
    
    private void ShowLoginScreen() 
    { 
        /* 実装してください - ユーザーにログイン画面を表示します */ 
    }
    
    private void ShowMuteExpiryNotification(DateTime expiryAt) 
    { 
        /* 実装してください - ミュートの有効期限を表示します */ 
    }
    
    private void ShowMessageBlockedNotification() 
    { 
        /* 実装してください - メッセージがブロックされたことをユーザーに通知します */ 
    }

    void OnDestroy()
    {
        // メモリリークを防ぐため、すべてのサブスクライバーをクリーンアップします
        authSubscriber?.Dispose();
        sanctionsSubscriber?.Dispose();
        sanitizationSubscriber?.Dispose();
    }
}

```

{% endcode %}

}
