GS2-SeasonRating

Season rating function

This function classifies players by player skill and enables matchmaking with players of similar skill. GS2-Matchmaking has a matchmaking function based on rating values, but it does not support the recently increasing system of ranking players over the course of a season, which can last from a few weeks to a few months in real time.

This microservice can be used to realize a game cycle in which players repeatedly play against each other to achieve a high tier during a season, considering a defined period of time as a season. Therefore, the indicator of strength in this feature is not a rate value, but is expressed by which tier the player belongs to.

Tiers

Tiers generally start at Bronze and go up through Silver, Gold, Platinum, and so on as you win more games. To move up a tier, you play against other players in the same tier, and if your points, which vary depending on your ranking, exceed a threshold, you move up to the next tier. If you lose the match, your points may decrease, and if your points fall below the threshold, you may move down to the previous tier.

Matchups across tiers

In rating matches, matchmaking rules should in principle consist of the same tier. However, when matchmaking includes players from the previous and next tiers due to a lack of players or other reasons, the amount of point fluctuation is determined based on the minimum and maximum fluctuation and ranking of the tier to which each player belongs. There is no mechanism to give bonus points when a player with a lower tier wins against a player with a higher tier or vice versa. It is recommended that tier thresholds be designed so that each tier has at least enough players to make gameplay viable, rather than trying to craft a game that pits players of different strengths against each other.

Point

Range of variation

For each tier, the amount of points subtracted at the lowest rank and the amount of points added at the highest rank can be set. If the middle ranking is taken, the amount of points added or subtracted is determined by dividing equally by the number of patterns in the reported ranking.

Entry Fee

Depending on the tier, it is possible to set that points must be spent to participate in the game. This allows for a series of games to also express the conditions required to move up a tier. Payment of the participation fee is made at the time of obtaining the ballot to report the game results to the server.

Rank Up Bonus

Bonus points can be added when a player is promoted to a higher rank by adding points. This prevents chatter that could result in immediate demotion after a promotion.

User Data Management

GS2-SeasonRating does not manage points and ranks. GS2-Experience is used for actual user data management.

Specify the GS2-Experience experience model that manages season points as the master data for the season, The season model ID is specified in the property ID, and the points are managed in the experience value, and the ranks are managed in which tier the user belongs to. In other words, the amount of increase or decrease in points is managed by the GS2-SeasonRating master data, but the user data, such as the threshold for determining rank by points and which tier a player belongs to, is managed by GS2-Experience. This allows for advanced features such as the rank value validation functionality provided by GS2-Experience to be used in the redemption process, whereby players can receive items if they are of a certain rank at the end of the season.

Match Sessions

To conduct a rating match, you must first create a match session resource in GS2-SeasonRating. GS2-Matchmaking has a linkage function that creates a match session with the name of the gatherer for which the matchmaking was established when the match is established. If there is no particular reason, please create a match session in this way.

Expiration Date of Match Session

Match sessions can have an expiration date in seconds, up to 24 hours. The results must be voted on within this period, and if 5 minutes have passed since the first vote and all votes have not been cast, the results will be counted at that point.

Vote for results

Once matchmaking is complete, each player will retrieve a ballot from the match session. The ballots are used to vote on the results. The ballot will be given the user IDs of the players who participated in the match and a list of their rankings.

Fragmentation of Voting Results

When the server attempts to take a majority vote of the accepted ballots, if the result is a tie and the final result cannot be determined, no rate calculation will be performed. This makes it difficult to determine the correct rate value in a 1vs1 game. To solve this problem, it is necessary to devise a solution such as matchmaking a third player who is not directly involved in the game behind the scenes and having that player vote from a third-party perspective.

Example Implementation

Get current points and rank

Use GS2-Experience’s API to obtain status. Specify the values specified in the season master data for “NamespaceName” and “ExperienceName” and the season model ID for “PropertyId”.

Create Match Session

Running the lottery cannot be handled by the SDK for the game engine.

Please use the GS2-Matchmaking integration feature.

Retrieve ballot

    var item = await gs2.SeasonRating.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Ballot(
        seasonName: "rating-0001",
        sessionName: "gathering-0001",
        numberOfPlayer: 4,
        keyId: "key-0001"
    ).ModelAsync();
    const auto Future = Gs2->SeasonRating->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Ballot(
        "rating-0001", // seasonName
        "gathering-0001", // sessionName
        4, // numberOfPlayer
        "key-0001" // keyId
    )->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

Vote

    var result = await gs2.SeasonRating.Namespace(
        namespaceName: "namespace-0001"
    ).VoteAsync(
        ballotBody: "ballotBody",
        ballotSignature: "ballotSignature",
        gameResults: new List<Gs2.Unity.Gs2SeasonRating.Model.EzGameResult> {
            new Gs2.Unity.Gs2SeasonRating.Model.EzGameResult() {
                Rank = 1,
                UserId = "user-0001",
            },
            new Gs2.Unity.Gs2SeasonRating.Model.EzGameResult() {
                Rank = 2,
                UserId = "user-0002",
            },
            new Gs2.Unity.Gs2SeasonRating.Model.EzGameResult() {
                Rank = 2,
                UserId = "user-0003",
            },
            new Gs2.Unity.Gs2SeasonRating.Model.EzGameResult() {
                Rank = 3,
                UserId = "user-0004",
            },
        },
        keyId: "key-0001"
    );
    const auto Future = Gs2->SeasonRating->Namespace(
        "namespace-0001" // namespaceName
    )->Vote(
        "ballotBody", // ballotBody
        "ballotSignature", // ballotSignature
        []
        {
            auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::SeasonRating::Model::FEzGameResult>>>();
            v->Add(
                MakeShared<Gs2::UE5::SeasonRating::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(1))
                ->WithUserId(TOptional<FString>("user-0001"))
            );
            v->Add(
                MakeShared<Gs2::UE5::SeasonRating::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(2))
                ->WithUserId(TOptional<FString>("user-0002"))
            );
            v->Add(
                MakeShared<Gs2::UE5::SeasonRating::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(2))
                ->WithUserId(TOptional<FString>("user-0003"))
            );
            v->Add(
                MakeShared<Gs2::UE5::SeasonRating::Model::FEzGameResult>()
                ->WithRank(TOptional<int32>(3))
                ->WithUserId(TOptional<FString>("user-0004"))
            );
            return v;
        }(), // gameResults
        "key-0001" // keyId
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

詳細なリファレンス