ارسال درخواست Match-Making

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

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

در این مستند کارهایی که با SDK اندروید برای Match-Making می‌توانید انجام دهید را توضیح خواهیم داد.

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

پیش‌نیاز

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

درخواست برای Match-Making

در صورتی که به سرویس بلادرنگ بکتوری متصل شوید، می‌توانید بر روی اتصال انجام شده درخواست Match-Making دهید. همچنین باید تعریف انواع Match-Making را در پنل انجام داده باشید.

در اپلیکیشن شما، کاربر با کلیک بر روی دکمه یا منو یا … با محتوای “درخواست رقابت” اعلام می‌کند که می‌خواهد وارد یک رقابت آنلاین با دیگر کاربران شود. شما پس از درخواست کاربر باید کدی مشابه زیر را برای درخواست یک رقابت آنلاین به بکتوری بدهید: (از این مثال استفاه شده است.)

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

// 2. Request for match making
backtoryApi.requestMatchmakingAsync(
        "group_fight_classic",
        3300,
        "{\"name\": \"ali\", \"profilePic\": \"http://storage.backtory.com/my-app/test.png\" }",
        new BacktoryCallBack<MatchmakingResponse>() {
            @Override
            public void onResponse(BacktoryResponse<MatchmakingResponse> response) {
                // 3. Check if request sent successfully or not
                if (response.isSuccessful()) {
                    // 4. Print and Save RequestId for later
                    Log.d("TAG", "Your matchmaking started with Id: "
                            + response.body().getRequestId());
                } else {
                    Log.d("TAG", "Operation failed with code: "
                            + response.code()
                            + " and message: "
                            + response.message());
                }
            }
        });

توضیح: کد بالا در چهار قدم کوچک، یک درخواست group_fight_classic داد:

  1. شیء بلادرنگ بکتوری را با ()getInstance دریافت کرد.
  2. یک درخواست برای group_fight_classic با مقدار MMR برابر 3300 و یک متادیتا ارسال کرد.
  3. چک کرد که درخواست با موفقیت به دست سرور رسیده باشد.
  4. در صورت موفقیت فیلد ()response.body().getRequestId را که شناسه یکتای درخواست بود، چاپ و ذخیره کرد.

فیلد MetaData: در مثال بالا یک رشته دلخواه به عنوان متادیتای کاربر فعلی به سرویس Match-Making ارسال شد، این متادیتا تاثیری در فرآیند انطباق بازیکنان با هم ندارد. در صورتی که یک رقابت آنلاین برای این درخواست پیدا شود، این متادیتا برای همه بازیکنان در آن رقابت ارسال خواهد شد و می‌توانند نام بازیکن (ali) و تصویر او (test.png) را در صفحه بازی نشان دهند.

کنسل کردن درخواست Match-Making

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

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

// 2. cancel previous RequestId
backtoryApi.cancelMatchmakingAsync("group_fight_classic", "<REQUEST-ID-HERE>",
        new BacktoryCallBack<Void>() {
            @Override
            public void onResponse(BacktoryResponse<Void> response) {
                // 3. Check if request cancelled successfully or not
                if (response.isSuccessful()) {
                    Log.d("TAG", "Your matchmaking request is cancelled now.");
                } else {
                    Log.d("TAG", "Operation failed with code: "
                            + response.code()
                            + " and message: "
                            + response.message());
                }
            }
        });

همانطور که می‌بینید، در چهار مرحله با داشتن RequestId می‌توان درخواست قبلی را لغو کرد:

  1. شیء بلادرنگ بکتوری را با ()getInstance دریافت کرد.
  2. یک درخواست کنسل برای group_fight_classic و مقدار RequestId که داریم، ارسال می‌کنیم.
  3. چک کرد که درخواست با موفقیت به دست سرور رسیده باشد.
  4. در صورت موفقیت پیامی با این مضمون چاپ می‌کنیم.

تنظیم MatchmakingListener

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

برای دریافت این سه پیام باید از کلاس MatchmakingListener استفاده کنید که نمونه کد راه‌اندازی آن به صورت زیر است:

public class MainClass implements MatchmakingListener, 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.setMatchmakingListener(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 Matchmaking Listener *************/
    @Override
    public void onMatchFound(MatchFoundMessage matchFoundMessage) {
        // TODO: handle match found here
    }

    @Override
    public void onMatchUpdate(MatchUpdateMessage matchUpdateMessage) {
        // TODO: handle match update here
    }

    @Override
    public void onMatchNotFound(MatchNotFoundMessage matchNotFoundMessage) {
        // TODO: handle match not found here
    }
    /*********** End Matchmaking Listener *************/

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

توضیح: همانطور که دیده می‌شود، ما کلاس خود را از MatchmakingListener به ارث برده‌ایم. سپس در تابع init پس از دریافت api بلادرنگ، به کمک تابع setMatchmakingListener، کلاس را به عنوان Listener برای اتفاقات مربوط به Match-Making تعیین کردیم. در این حالت سه تابع زیر اضافه می‌شود که در مواقع لازم، توسط بکتوری فراخوانی خواهند شد و شما می‌توانید منطق مورد نظر خود را در این سه تابع پیاده‌سازی کنید:

دریافت پیام Match Update

از زمانی که شما درخواست Match-Making بدهید، تا زمانی که واقعا بازی به حد نصاب برسد، چندین بار وضعیت Match-Making به روزرسانی می‌شود. برای مثال در یک رقابت ده نفره، وقتی نفر دوم درخواست می‌دهد و با نفر اول انطباق پیدا می‌کند، وضعیت Match-Making از وضعیت یک نفره به وضعیت دو نفره می‌رود. همینطور برای بازیکنان سوم، چهارم، … تا دهم. در واقع وقتی کاربر شما درخواست برای رقابت آنلاین می‌دهد، تا زمانی که همه بازیکنان درخواست بدهند و بازی آغاز شود، به ازای هر تغییر در وضعیت، تمام بازیکنان خبردار می‌شوند. همانطور که در قسمت قبل دیدیم، این خبردارشدن به واسطه MatchmakingListener و از طریق تابع OnMatchUpdate اتفاق می‌افتد.

@Override
public void onMatchUpdate(MatchUpdateMessage matchUpdateMessage) {
    Log.d("TAG", "RequestId: " + matchUpdateMessage.getRequestId());
    Log.d("TAG", "Match update webhook response: " +
                    matchUpdateMessage.getExtraMessage());

    Log.d("TAG", "Players of Match until now: ");
    for (int i = 0; i < matchUpdateMessage.getParticipants().size(); i++) {
        MatchUpdateParticipant participant =
                matchUpdateMessage.getParticipants().get(i);
        Log.d("TAG", "UserId: " + participant.getUserId());
        Log.d("TAG", "MetaData is: " + participant.getMetaData());
    }
}

دریافت پیام Match Found

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

دقت کنید که در Match-Found شما یک RequestId دریافت خواهید کرد که بیان می‌کند، رقابت آنلاین پیدا شده، مربوط به کدام یک از درخواست‌های Match-Making است، زیرا ممکن است شما چندین درخواست همزمان برای چندین بازی داده باشید و مقدار RequestId تعیین می‌کند که رقابت پیداشده مربوط به کدام یک از درخواست‌های شما بوده است.

نمونه کد زیر تابع OnMatchFound از MatchmakingListener را پیاده‌سازی و اطلاعات رقابت آنلاین را چاپ می‌کند:

@Override
public void onMatchFound(MatchFoundMessage matchFoundMessage) {
    Log.d("TAG", "RequestId: " + matchFoundMessage.getRequestId());
    Log.d("TAG", "Found Match Id: " + matchFoundMessage.getMatchId());
    Log.d("TAG", "Match found webhook response: " +
                    matchFoundMessage.getExtraMessage());

    Log.d("TAG", "Players of Match: ");
    for (int i = 0; i < matchFoundMessage.getParticipants().size(); i++) {
        MatchFoundParticipant participant = matchFoundMessage.getParticipants().get(i);
        Log.d("TAG", "UserId: " + participant.getUserId());
        Log.d("TAG", "MMR is: " + participant.getSkill());
        Log.d("TAG", "MetaData is: " + participant.getMetaData());
    }
}

در کد بالا، شناسه درخواست همان RequestId است که پیشتر گفته شد. فیلد MatchId شناسه رقابت آنلاینی است که ایجاد شده و در ادامه راه به کمک این MatchId باید به رقابت آنلاین وصل شده و بازی را انجام دهید.

دریافت پیام Match Not Found

در حالتی که تعدادی کاربر درخواست Match-Making بدهند، و در زمان معین شده در پنل تعداد بازیکنان به حد نصاب نرسد، عملیات با شکست مواجه خواهد شد. در این حالت، همه کاربرانی که درخواست داده بودند، از طریق تابع onMatchNotFound از MatchmakingListener مطلع خواهند شد.

تکه کد زیر بخشی از اطلاعاتی را که در شیء MatchNotFoundMessage دریافت شده وجود دارد، لاگ می‌زند.

@Override
public void onMatchNotFound(MatchNotFoundMessage matchNotFoundMessage) {
    Log.d("TAG", "Request with id: " + matchNotFoundMessage.getRequestId() + " failed.");
}

در قسمت دریافت پیام Match Found دیدید که چگونه با پیدا شدن یک Match در بکتوری، یک MatchId دریافت می‌کنید. در ادامه راه، به کمک این شناسه باید به رقابت آنلاین وصل شده و بازی را انجام دهید. در مستند رقابت آنلاین خواهید دید که چگونه می‌توان یک رقابت را به کمک بکتوری انجام داد.

گام بعدی