ICRC Games stats standard

Context

The proposed ICRC-14 Game General Stats standard is important because it establishes a common format for games to expose their main game stats and player stats. This format can be used by various ICP games, tools, and gamers to query gaming data in a standardized way, thereby improving interoperability between games and enabling collaboration between multiple projects.

Data details

  • icrc: 14
  • title: ICRC-14 Game General Stats
  • author: Ricardo Capuz ricardo@byvibrant.xyz & Esteban Suárez esteban@byvibrant.xyz,
  • status: Deliberating
  • category: ICRC
  • requires: None
  • created: 2023-03-09
  • updated: 2023-03-09

Summary

Minimal set of types and methods for games to expose their main game stats and players stats to boost collaboration and side tooling.

Introduction

This proposal describes the minimal set of types and methods that will help games to have standard stats for their main stats and player stats. We hope that this will boost ICP games interoperability and thrive the collaborations between multiple projects.

Goals

  • Allow games, tools and gamers to query main gaming stats for any game.
  • Allow gamers to query their gaming data.
  • Allow authorized third-parties to query their gaming data (Should be on another standard).
  • Provide an authorization mechanism for gamers to approve who manages their data (Should be on another standard).

References

icrc14_get_game_stats

type StatsRequest = variant {
    StartDate : Int;
    EndDate : Int;
};

type Stats = record {
    active_players : Nat;
    unique_players : Nat;
    peak_concurrent_players : Nat;
    hours_played : Nat;
    cycles_burned : Nat;
    session_time_average : Nat;
    extras : vec {Property};
};

type RangeRequested = variant {
    StartDate : Int;
    EndDate : Int;
};

type Property = record {name : text; value : Value};

type Value = variant {
    Array : vec {Value};
    Principal : principal;
    Class : vec {Property};
    Option : opt Value;
    Bytes : vec {Nat8};

    Nat : nat;
    Nat8 : nat8;
    Nat16 : nat16;
    Nat32 : nat32;
    Nat64 : nat64;
   
    Int : int;
    Int8 : int8;
    Int16 : int16;
    Int32 : int32;
    Int64 : int64;


    Blob : blob;
    Bool : bool;
    Text : text;
    Float : float64;
};


service : {
icrc14_get_game_stats: (StatsRequest, ?RangeRequested ) -> (Stats);
}

icrc14_get_gamer_stats

type Identity = variant {
    Principal : principal;
};

type GamerStatsResults = variant {
    Ok : GamerStats;
    Err : opt GamerStatsError;
};

type GamerStats = record {
    hours_played : Nat;
    session_time_average : Nat;
    extras : vec {Property};
};

type GamerStatsError = variant {
    NotAuthorized: record { reason: text };
};

service : {
    icrc14_get_gamer_stats: (Identity, ?RangeRequested ) -> (GamerStatsResults);
}

Complementary standards

There should probably be a standard to manage gamer data authorization and multiple standards to manage genre specific stats.

Hope to receive a lot of ideas and contributions to go forward with this standard.

11 Likes

Great ideas here @CapuzR.

Some questions / feedback


type Identity = variant {
    Principal : principal;
};

Is the intention here to allow for additional identity types to be added in the future? If so you might have to rethink this part a bit; check the feedback Andreas left here.

Applying his his advice above to the Results type…

type GamerStatsResults = variant {
    Ok : GamerStats;
    Err : opt GamerStatsError;  
};

Next, regarding:

type GamerStats = record {
    hours_played : Nat;
    session_time_average : Nat;
    extras : Value;
};

and

type Stats = record {
    active_players : Nat;
    unique_players : Nat;
    peak_concurrent_players : Nat;
    hours_played : Nat;
    cycles_burned : Nat;
    session_time_average : Nat;
    extras : Value;
};

What are your thoughts about potentially typing extras as a vec Property? Essentially, making it easily interpreted as a map by consumers.

I think this would also make it easier to quickly find some agreement on, and implement, genre specific stats as you allude to. e.g. fps games implementing ICRC-14 MUST include accuracy : Float in extras.

5 Likes

We (Eimolad) have added only one text variable in JSON format to the backend for ease of operation. In your case, it might look something like this:

type metadata = Text;

metadata = ""metadata": [{"active_players": 10, "unique_players": 3, "name": "eimolad", …},{"active_players": 8, "unique_players":5, "name": "othername", …}, … {} ]";

This way we can easily add or change variables.

In fact, no one can predict the variety of upcoming games and determine the entire list of stats for the future. We use our NFT (EXT standard) as an account access key. The player’s account contains all stats. In different games, players can have different types of stats. Therefore, it would be reasonable to get stats from players’ game accounts, and not from tokens. This does not require any standard of token. Any programming language can easily parse the JSON format.

You can see how we get stats for dwarves from our game accounts on the website: https://ictokens.app/

4 Likes

Thanks for the feedback @Hazel

Optional to support backwards compatibility in older clients

I have done some tests and I think Andrea’s feedback applies for GamerStatsError (Already updated) but my tests allows me to add identity variants without breaking frontends/otherCanis.

Here’s my basic test on motoko playground

Here’s a test using ICRC-11’s AuthRequest on motoko playground

In both of them, you can remove commented Text variant and check what I mean. Maybe I’m missing something, please let me know.

vec Property

Agreed and already updated!! Love to use a vec record and not a vec tuple that is usually a pain on frontends imo. DAB uses vec tuple for details, maybe we could talk/suggest Funded to change this to vec record, do you see any advantage on vec tuple approach?

I’m going to write this answer on ICRC-14 Github issue also and will tag you. Please answer there.

1 Like

Let’s try to do this in practice. We need any two games for that

1 Like

Thanks a lot for taking the time to collab on this @iBardak

I want to clarify, this is not a token standard, these are just types and methods to be added on the main game canister if the game supports the standard.

The idea is to have an standard as simple as possible here (These are Game Stats). In Stats record you can see stats that every game normally have (I think):

type Stats = record {
    active_players : Nat;
    unique_players : Nat;
    peak_concurrent_players : Nat;
    hours_played : Nat;
    cycles_burned : Nat;
    session_time_average : Nat;
    extras : vec {Property};
};

and for Players is the same, I think these stats applies for every game:

type GamerStats = record {
    hours_played : Nat;
    session_time_average : Nat;
    extras : vec {Property};
};

I would love if you can give us your thoughts on this stats, if you consider that they are important enough to be on the basic standard and what other do you think that applies for all games.

Of course there are a lot of stats that varies between projects and this isn’t by any means a restriction to use whatever stats a game wants to manage.

If we agree and use this standard, all the games on the IC can interoperate -with stats- easily based on that, and it will be super easy for additional tools (Internal and external to the IC) to map games and stats on the IC Game Ecosystem and give additional benefits to everyone.

After this basic standard we can work in by genre specific stats standard to complement this one (this will not be a restriction for games to use others than the ones on the standard though).

I’m going to write this answer on ICRC-14 Github issue also and will tag you. Please answer there.

1 Like

Awesome!! Let’s agree on an initial one and test it with a couple of games.

is there a ready-made implementation of this functionality on motoko? Starting from recording, ending with storing and issuing information

1 Like

I’ve referenced this ICRC from ICRC-16: ICRC-16 - CandyShared - Standardizing Unstructured Data Interoperability - #4 by skilesare

I’d propose we use CandyShared as the “Value” type for this library so devs get prebuilt libraries to have fast access to handle the data types inside their canisters.

1 Like

This is more-so about adding a variant type

The following is a screenshot from the candid spec here

Great work! Personally, I do not. However, I’m a bit biased. I did a lot of backend development as a result I prefer to have my Request / Responses wrapped in records (its JSON all the way down).

2 Likes

Yeah!! JSON is most proper for backend (Motoko)

1 Like

Yes but is only on method results, right? Identity is used only on method arguments so that shouldn’t be a problem.

Yep, agree.

I have a question about NFTs and metadata. Is there a way to give permission to an authorized canister to upgrade or update the metadata associated with an NFT? ex. Level 1, Level 2 with different properties

and I’m wondering if it’s possible to merge different NFTs into one. For example, if I have two NFTs that represent same parts, can I combine them into a single NFT that represents and upgraded version?

Btw, great job and thanks for this proposal!

Yes, Eimolad uses this for in-game crafting. You can burn several NFTs and tokens and the mint of a new NFT. The sequence of these actions can be linked by a smart contract. This way you won’t have to change registry entries.

1 Like