به چالش کشیدن دوستان (Challenge)

دقت کنید که این مستند مخصوص رقابت آنلاین است و برای نیازمندی‌های چت هیچ کاربردی ندارد.

برای آنکه یک رقابت آنلاین را بین کاربران خود در بکتوری اجرا کنید، ابتدا باید کاربرانی که در این رقابت شرکت کرده‌اند را مشخص کنید. برای اینکه یا بایستی کاربران با درخواست Match-Making با دیگر کاربران آنلاین هم‌سطح با خود (به صورت تصادفی) بازی کنند، و یا اینکه کاربران خاص دیگری را به چالش بکشند.

در این مستند، ما قصد داریم نحوه به چالش کشیدن کاربران دیگر را شرح دهیم. در ادامه ارسال درخواست چالش به دوستان، رد یا پذیرش چالش درخواستی و شروع یک رقابت آنلاین (Match) با این کاربران را خواهیم دید.

پیش‌نیاز

  1. در صورتی که با سرویس بلادرنگ آشنایی ندارید، به معرفی سرویس بلادرنگ مراجعه کنید.
  2. در صورتی که هنوز با تنظیمات پنل سرویس بلادرنگ آشنا نشده اید، به تنظیمات پنل سرویس بلادرنگ مراجعه کنید.
  3. اگر هنوز SDK اندروید را راه‌اندازی نکرده‌اید، به راه‌اندازی SDK اندروید مراجعه کنید.
  4. در صورتی که با نحوه‌ی اتصال به سرویس بلادرنگ و ایجاد یک چت ساده به کمک آن آشنایی ندارید، مستند اتصال ساده و ارسال پیام را حتما مطالعه کنید.

تعریف چالش

در سرویس بلادرنگ، چالش (Challenge) به درخواستی گفته می‌شود که یک کاربر موبایل می‌تواند به تعدادی کاربر دیگر با داشتن UserId آنها بفرستد، در این حالت کاربران دیگر می‌توانند چالش را بپذیرند یا رد کنند. در صورتی که تعداد کسانی که چالش را پذیرفته‌اند به حد نصاب برسد، چالش موفق بوده و کاربران می‌توانند رقابت آنلاین خود را آغاز کنند. در ادامه نحوه انجام تمامی این کارها را خواهیم دید.

ارسال چالش به دیگران

برای ارسال یک چالش به چند کاربر دیگر کافیست بعد از آنکه اتصال به سرویس بلادرنگ برقرار گردید، کدی مانند زیر اجرا کنید:

// Get realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Send challenge to users
List<String> challengedUsers = new ArrayList<String>();
challengedUsers.add("<USER-ID-1>");
challengedUsers.add("<USER-ID-2>");
challengedUsers.add("<USER-ID-3>");

backtoryApi.requestChallengeAsync(challengedUsers, 60, 2,
        new BacktoryCallBack<ChallengeResponse>() {
            @Override
            public void onResponse(BacktoryResponse<ChallengeResponse> response) {
                // Check if sending challenge to backtory was successful or not
                if (response.isSuccessful()) {
                    Log.d("TAG", "Your challenge is received by backtory, " +
                            + "challengeId is: " + response.body().getChallengeId());
                } else {
                    Log.d("TAG", "Operation failed with code: "
                            + response.code()
                            + " and message: "
                            + response.message());
                }
            }
        });

همانطور که می‌بینید تابع requestChallenge یک درخواست چالش را ارسال می‌کند. این تابع سه پارامتر دارد که به ترتیب عبارتند از:

  1. challengedUsers: لیست شناسه کاربران به چالش کشیده شده.
  2. waitTime: مدت زمانی (به ثانیه) که کاربران دیگر وقت دارند به چالش پاسخ دهند. دقت کنید که این زمان می‌تواند حداکثر ۱۵ دقیقه باشد و در صورتی که عدد بیشتری به تابع پاس داده شود، سرور همان ۱۵ دقیقه را در نظر خواهد گرفت.
  3. minPlayer: حداقل تعداد کاربران برای آنکه چالش پذیرفته شود. در صورتی که این فیلد را null دهید، همه کاربران باید درخواست را بپذیرند.
  4. callback: کلاسی که تابع آن با دریافت پاسخ از سمت سرور بکتوری صدا زده می‌شود.

مهم: به طور پیشفرض فردی که چالش را مطرح می‌کند، آن را پذیرفته است. یعنی اگر مقدار minPlayer برابر ۲ باشد، تنها کافیست یک نفر دیگر چالش را بپذیرد.

لغو کردن درخواست چالش

در صورتی که فرد چالش‌کننده بخواهد درخواستش را از افراد چالش‌شده پس بگیرد، از طریق کدی مانند زیر می‌تواند اقدام کند. تابع cancelChallenge به عنوان آرگومان ورودی، ChallengeId مرتبط با چالشی که پیش از این درخواست شده است، را دریافت می‌کند.

// Get realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// Send challenge cancellation request
backtoryApi.cancelChallengeAsync("<CHALLENGE-ID>", new BacktoryCallBack<Void>() {
    @Override
    public void onResponse(BacktoryResponse<Void> response) {
        // Check if cancelling challenge was successful or not
        if (response.isSuccessful()) {
            Log.d("TAG", "challenge canceled successfully.");
        } else {
            Log.d("TAG", "Operation failed with code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

آگاهی از وضعیت چالش (Challenge-Listener)

جهت پذیرش چالش‌های دیگران، باید یک Listener از جنس ChallengeListener به اپلیکیشن خود اضافه کنیم. این Listener زمانی که چالشی از طرف کاربران دیگر برای شما ارسال شود، آن را دریافت خواهد کرد و به شما اجازه می‌دهد که در مورد آن تصمیم‌گیری کنید.

برای اضافه کردن این Listenerها کدی مانند زیر لازم است:

public class MainClass implements ChallengeListener, RealtimeSdkListener {

    public void init() {
        // 1. Get Realtime api
        BacktoryRealtimeAndroidApi backtoryApi =
                BacktoryRealtimeAndroidApi.getInstance();

        // 2. Set required listener
        backtoryApi.setRealtimeSdkListener(this);

        // 3. Set match making listener
        backtoryApi.setChallengeListener(this);

        // 4. Connect to backtory
        backtoryApi.connectAsync(new BacktoryCallBack<ConnectResponse>() {
            @Override
            public void onResponse(BacktoryResponse<ConnectResponse> response) {
                // 5. Check if connected Successful
                if (response.isSuccessful())
                    Log.d("TAG", "Connected: " + response.body().getUsername() + ":"
                            + response.body().getUserId());
                else
                    Log.d("TAG", "Connect failed with code: " + response.code()
                            + " and message: " + response.message());
            }
        });
    }


    /*********** Start Challenge Listener *************/
    @Override
    public void onChallengeInvitation(ChallengeInvitationMessage challengeInvitationMessage) {
        // TODO: If you are challenged, handle it here.
    }

    @Override
    public void onChallengeAccepted(ChallengeAcceptedMessage challengeAcceptedMessage) {
        // TODO: If your friends accepted your challenge, handle it here.
    }

    @Override
    public void onChallengeDeclined(ChallengeDeclinedMessage challengeDeclinedMessage) {
        // TODO: If your friends declined your challenge, handle it here.
    }

    @Override
    public void onChallengeCanceled(ChallengeCanceledMessage challengeCanceledMessage) {
        // TODO: If the requester cancels his/her challenge, handle it here.
    }

    @Override
    public void onChallengeExpired(ChallengeExpiredMessage challengeExpiredMessage) {
        // TODO: If your challenge expired, you are notified here.
    }

    @Override
    public void onChallengeImpossible(ChallengeImpossibleMessage challengeImpossibleMessage) {
        // TODO: If most of your friends declined,
        // and remaining ones are less than minPlayer,
        // you are notified here.
    }

    @Override
    public void onChallengeReady(ChallengeReadyMessage challengeReadyMessage) {
        // TODO: If challenge is ready, and CurrentUser has accepted,
        // handle it here.
    }

    @Override
    public void onChallengeWithoutYou(ChallengeReadyWithoutYou challengeReadyWithoutYou) {
        // TODO: If challenge is ready, and CurrentUser has rejected,
        // you are notified here.
    }
    /*********** End Challenge Listener *************/

    /*********** Start Realtime Sdk Listener *************/
    @Override
    public void onDisconnect() {}
    @Override
    public void onException(ExceptionMessage exceptionMessage) {}
    /*********** End Realtime Sdk Listener *************/
}

شما باید هر یک از توابعی که مورد نیازتان است را پیاده‌سازی کنید. توابعی که امکان پیاده‌سازی آنها هست عبارتند از:

دریافت چالش از دیگران

در صورتی که یک چالش از کاربر دیگری برای شما ارسال شود، به کمک تابع onChallengeInvitation به شما خبر داده می‌شود. کد زیر دریافت چالش و نمایش اطلاعات آن را انجام می‌دهد:

@Override
public void onChallengeInvitation(ChallengeInvitationMessage message) {
    Log.d("TAG", "Received challenge id is: " + message.getChallengeId());
    Log.d("TAG", "You are challenged by: " + message.getChallengerId());

    Log.d("TAG", "List of challenged users are: ");

    for (int i = 0; i < message.getChallengedUsers().size(); i++) {
        String userId = message.getChallengedUsers().get(i);
        Log.d("TAG", i + ": " + userId);
    }
}

همانطور که می‌بینید، شما به شناسه ChallengeId، شناسه کسی که چالش را آغاز کرده و لیست شناسه UserId تمام کسانی که چالش شده‌اند، دسترسی دارید.

لیست چالش‌های فعال

در صورتی که کاربر فعلی شما آفلاین بوده باشد، و در بازه آفلاین بودن، چالشی برای او ارسال شده باشد. به محض آنلاین شدن با کدی مانند زیر می‌تواند لیست چالش‌های فعال خود را دریافت کند:

// 1. Get realtime api
BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

// 2. Request for list of challenges
backtoryApi.requestListOfActiveChallengesAsync(
        new BacktoryCallBack<ActiveChallengesListResponse>() {
    @Override
    public void onResponse(BacktoryResponse<ActiveChallengesListResponse> response) {
        // 3. Check if list is retrieved successfully
        if (response.isSuccessful()) {
            Log.d("TAG", "Your have " + response.body().getActiveChallengeList().size()
                    + " active challenges.");
            for (int i = 0; i < response.body().getActiveChallengeList().size(); i++) {
                PendingChallengeInfo pendingChallenge =
                        response.body().getActiveChallengeList().get(i);

                Log.d("TAG", "Challenged by: " + pendingChallenge.getChallengerId());
                Log.d("TAG", "Challenge id is: " + pendingChallenge.getChallengeId());
                Log.d("TAG", "Number of challenged users: "
                        + pendingChallenge.getChallengedUsers().size());
            }
        } else {
            Log.d("TAG", "Operation failed with code: "
                    + response.code()
                    + " and message: "
                    + response.message());
        }
    }
});

همانطور که در کد بالا می‌بینید، به ازای هر چالش فعال، شناسه کاربری که چالش را ایجاد کرده (ChallengerUserId)، شناسه‌ی چالش و تعداد بازیکنانی که در این چالش شرکت کرده‌اند، چاپ شده‌اند.

پذیرش یک چالش

کاربر شما یا از طریق دریافت چالش‌های Offline و یا دریافت یک چالش آنلاین (یعنی دریافت یک چالش، لحظه‌ای که کاربر به چالش کشیده شده آنلاین است) به یک چالش دعوت می‌شود. در جواب کاربر موبایل باید چالش را بپذیرد و یا رد کند. پذیرش یک چالش ساده است و کافیست ChallengeId را از اطلاعات چالش ارسال شده استخراج کنید. به عنوان یک مثال ساده، می‌خواهیم هر وقت یک چالش به صورت آنلاین برای کاربر ارسال شد، درجا بپذیرد. کافیست در Listener دریافت چالش کدی مانند زیر را بنویسیم:

@Override
public void onChallengeInvitation(ChallengeInvitationMessage message) {
    Log.d("TAG", "Received challenge id is: " + message.getChallengeId());

    // Get realtime api
    BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

    // Accept the challenge here:
    backtoryApi.acceptChallengeAsync(
            message.getChallengeId(), new BacktoryCallBack<Void>() {
        @Override
        public void onResponse(BacktoryResponse<Void> response) {
            // Check if your accept is sent to challenger user successfully or not
            if (response.isSuccessful()) {
                Log.d("TAG", "Challenge Accepted!!!");
            } else {
                Log.d("TAG", "Operation failed, code: "
                        + response.code()
                        + " and message: "
                        + response.message());
            }
        }
    });
}

دریافت پذیرش از دیگران

در دریافت یک چالش آنلاین دیدید که چگونه می‌تواند از دریافت یک چالش آنلاین مطلع شد و در پذیرش یک چالش نیز دیدیم که چگونه چالش دریافتی را بپذیریم. قدم بعدی این است که، کاربری که چالش را مطرح کرده است، از اینکه چالشش پذیرفته شده است، اطلاع یابد. برای این کار کافیست تابع OnChallengeAccepted را مانند کد زیر پیاده‌سازی کنید:

@Override
public void onChallengeAccepted(ChallengeAcceptedMessage message) {
    Log.d("TAG", "Accepted challenge id: " + message.getChallengeId());
    Log.d("TAG", "Challenger user id: " + message.getChallengerId());
    Log.d("TAG", "Challenge is accepted by: " + message.getAcceptedId());
}

به همین سادگی می‌توان فهمید که چه کسی چه چالشی را پذیرفته است.

رد یک چالش

کاربر شما یا از طریق دریافت چالش‌های Offline و یا دریافت یک چالش آنلاین (یعنی دریافت یک چالش، لحظه‌ای که کاربر به چالش کشیده شده آنلاین است) به یک چالش دعوت می‌شود. در صورتی که کاربر شما تمایل به شرکت در چالش نداشته باشد، می‌تواند در جواب چالش دریافتی، آن را رد کند. برای مثال کد زیر به محض دریافت یک چالش آنلاین از طریق Listener دریافت چالش آن را رد می‌کند:

public void onChallengeInvitation(ChallengeInvitationMessage message) {
    Log.d("TAG", "Received challenge id is: " + message.getChallengeId());

    // Get realtime api
    BacktoryRealtimeAndroidApi backtoryApi = BacktoryRealtimeAndroidApi.getInstance();

    // Decline the challenge here:
    backtoryApi.declineChallengeAsync(message.getChallengeId(),
            new BacktoryCallBack<Void>() {
        @Override
        public void onResponse(BacktoryResponse<Void> response) {
            // Check if your decline is sent to challenger user successfully or not
            if (response.isSuccessful()) {
                Log.d("TAG", "Challenge Declined!!!");
            } else {
                Log.d("TAG", "Operation failed, code: "
                        + response.code()
                        + " and message: "
                        + response.message());
            }
        }
    });
}

دریافت رد از دیگران

در دریافت یک چالش آنلاین دیدید که چگونه می‌تواند از دریافت یک چالش آنلاین مطلع شد و در رد یک چالش نیز دیدیم که چگونه چالش دریافتی را رد کنیم. قدم بعدی این است که کاربری که چالش را مطرح کرده، از اینکه چالشش رد شده است، اطلاع یابد. برای این کار کافیست تابع onChallengeDeclined را مانند کد زیر پیاده‌سازی کنید:

@Override
public void onChallengeDeclined(ChallengeDeclinedMessage message) {
    Log.d("TAG", "Declined challenge id: " + message.getChallengeId());
    Log.d("TAG", "Challenger user id: " + message.getChallengerId());
    Log.d("TAG", "Challenge is declined by: " + message.getDeclinedId());
}

به همین سادگی می‌توان فهمید که چه کسی چه چالشی را رد کرده است.

لغو شدن درخواست چالش

در قسمت لغو کردن درخواست چالش مشاهده کردید که چگونه می‌توان یک درخواست چالش را که ارسال کرده‌ایم، لغو کرد. حال می‌خواهیم ببینیم اگر چالشی که به آن دعوت شده‌ایم، لغو شود، چگونه از آن مطلع شویم. برای این کار کافیست تابع onChallengeCanceled را مانند کد زیر پیاده‌سازی کنید:

@Override
public void onChallengeCanceled(ChallengeCanceledMessage message) {
    Log.d("TAG", "Canceled challenge id: " + message.getChallengeId());
}

منقضی شدن چالش

در صورتی که در زمان تعیین‌شده برای چالش (waitTime)، تعداد کافی از افراد چالش‌شده، درخواست چالش را نپذیرند، آن چالش منقضی شده است. در این صورت همه افراد به چالش کشیده شده، از منقضی شدن آن چالش به کمک تابع onChallengeExpired از کلاس کلاس ChallengeListener از این اتفاق مطلع می‌شوند. کد زیر اطلاعات چالش منقضی شده را در تابع onChallengeExpired لاگ می‌کند.

@Override
public void onChallengeExpired(ChallengeExpiredMessage challengeExpiredMessage) {
    Log.d("TAG", "Expired challenge id: " + challengeExpiredMessage.getChallengeId());
}

چالش غیرممکن

وضعیت چالش غیرممکن وقتی اتفاق می‌افتد که تعداد بازیکنانی که چالش را رد کرده‌اند، زیاد باشد؛ به طوری که حتی اگر همه افرادی که هنوز پاسخ به چالش نداده‌اند، آن را بپذیرند، باز هم تعداد آنها به حد نصاب minPlayer نرسد. در این حالت، برای همه افراد حاضر در چالش، پیام چالش غیرممکن ارسال می‌شود و عملا چالش کنسل می‌شود. کاربران شما از این اتفاق به کمک تابع onChallengeImpossible از کلاس ChallengeListener مانند کد زیر خبردار خواهند شد:

@Override
public void onChallengeImpossible(ChallengeImpossibleMessage message) {
    Log.d("TAG", "Challenge with id " + message.getChallengeId() + " is impossible.");
}

موفقیت یک چالش پذیرفته شده

در دریافت یک چالش دیدیم که چگونه می‌توانید از چالشی که برای کاربر شما ارسال می‌شود، خبردار شوید. در پذیرش یک چالش و رد یک چالش نیز نحوه پذیرش و یا رد یک چالش را دیدید. سرانجام، اگر تعداد افرادی که چالش را پذیرفته‌اند به حد نصاب minPlayer برسد، آن چالش پذیرفته شده است و در این حالت کاربرانی که چالش را پذیرفته‌اند، باید به مرحله بعد که انجام رقابت آنلاین است، بروند. اگر کاربر فعلی شما، یکی از کسانی باشد که چالش را پذیرفته است، از طریق تابع onChallengeReady به شکل زیر از موفقیت چالش خبردار خواهد شد:

@Override
public void onChallengeReady(ChallengeReadyMessage message) {
    Log.d("TAG", "Challenge is accepted with id: " + message.getChallengeId());
    Log.d("TAG", "Backtory's match for this challenge: " + message.getMatchId());
    Log.d("TAG", "Challenge ready webhook response: " + message.getExtraMessage());

    Log.d("TAG", "List of participants in match:");
    for (int i = 0; i < message.getParticipants().size(); i++) {
        String participantId = message.getParticipants().get(i);
        Log.d("TAG", "Participant no. " + i + ": " + participantId);
    }
}

موفقیت یک چالش رد شده

معادل با موفقیت یک چالش پذیرفته شده ممکن است یک چالش موفق شود، ولی کاربر فعلی شما آن را رد کرده باشد. این حالت نیز به کمک تابع onChallengeWithoutYou از کلاس ChallengeListener به شما خبر داده خواهد شد که صرفا بدانید وضعیت این چالش چه شده است.

@Override
public void onChallengeWithoutYou(ChallengeReadyWithoutYou challengeReadyWithoutYou) {
    Log.d("TAG", "Challenge is ready with id: " + challengeReadyWithoutYou.getChallengeId());
    Log.d("TAG", "But you missed your chance for participation, because you declined.");
}

به این ترتیب، همه کارهایی که می‌توان برای به چالش کشیدن کاربران دیگر انجام داد را دیدید. در یک اپلیکیشن واقعی کافیست یک واسط گرافیکی مناسب برای وضعیت چالش بگذارید و هر گاه که کسی چالش را می‌پذیرد و یا رد می‌کند، آن را به صورت زنده به‌روزرسانی کنید.

در بخش بعدی وارد رقابت آنلاین خواهیم شد، و می‌بینیم که پس از آنکه یک چالش پذیرفته می‌شود، چگونه باید یک رقابت آنلاین را آغاز کرد.

گام بعدی