-
Notifications
You must be signed in to change notification settings - Fork 0
/
Gamestats.ts
187 lines (143 loc) · 5.96 KB
/
Gamestats.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import { Protobuf, System, SafeMath, authority, Token } from "@koinos/sdk-as";
import { gamestats } from "./proto/gamestats";
import { LeaderboardStorage } from "./state/LeaderboardStorage";
import { PlayersStorage } from "./state/PlayersStorage";
import { GamesStatsStorage } from "./state/GamesStatsStorage";
import { MetadataStorage } from "./state/MetadataStorage";
export class Gamestats {
_contractId: Uint8Array = System.getContractId();
_metadataStorage: MetadataStorage = new MetadataStorage(this._contractId);
_playersStorage: PlayersStorage = new PlayersStorage(this._contractId);
_gamesStatsStorage: GamesStatsStorage = new GamesStatsStorage(this._contractId);
_leaderboardStorage: LeaderboardStorage = new LeaderboardStorage(this._contractId);
initialize(args: gamestats.initialize_arguments): gamestats.empty_message {
// only this contract can initialize itself
System.requireAuthority(authority.authorization_type.contract_call, this._contractId);
const metadata = this._metadataStorage.get()!;
System.require(!metadata.initialized, 'already initialized');
System.require(args.rewards_token_address.length, 'missing rewards_token_address argument');
metadata.initialized = true;
metadata.rewards_token_address = args.rewards_token_address;
this._metadataStorage.put(metadata);
return new gamestats.empty_message();
}
submit_game_stats(args: gamestats.submit_game_stats_arguments): gamestats.empty_message {
const game_stats = args.game_stats;
System.require(game_stats != null, 'missing "game_stats" argument');
// get player object
const playerObj = this._playersStorage.get(game_stats!.winner)!;
// delete current leaderboard object for this player
// since the number of wins is going to change for that player
let playerLeaderboardKey = new gamestats.leaderboard_key(playerObj.wins, game_stats!.winner);
this._leaderboardStorage.remove(playerLeaderboardKey);
// update players storage
playerObj.wins = SafeMath.add(playerObj.wins, 1);
this._playersStorage.put(game_stats!.winner, playerObj);
// update leaderboard
playerLeaderboardKey.wins = playerObj.wins;
this._leaderboardStorage.put(playerLeaderboardKey, new gamestats.empty_message());
// increment last game id
const metadata = this._metadataStorage.get()!;
metadata.last_game_id = SafeMath.add(metadata.last_game_id, 1);
this._metadataStorage.put(metadata);
// save game stats
game_stats!.game_id = metadata.last_game_id;
game_stats!.timestamp = System.getHeadInfo().head_block_time;
this._gamesStatsStorage.put(
new gamestats.game_stats_key(metadata.last_game_id),
game_stats!
);
// mint token rewards
const token = new Token(metadata.rewards_token_address);
System.require(
token.mint(game_stats!.winner, game_stats!.rewards),
'failed to mint rewards'
);
return new gamestats.empty_message();
}
get_player_info(args: gamestats.get_player_info_arguments): gamestats.player_object {
const player = args.player;
return this._playersStorage.get(player)!;
}
get_leaderboard(args: gamestats.get_leaderboard_arguments): gamestats.get_leaderboard_result {
const offset_key = args.offset_key;
let limit = args.limit || u64.MAX_VALUE;
// least_to_most_wins indicates if we want to get the leaderboard
// from the player with the least to the most wins
// which is the default ordering in the state
const least_to_most_wins = args.least_to_most_wins;
// construct leaderboard key
let key = new gamestats.leaderboard_key();
// if an offset key was provided
if (offset_key) {
key = offset_key;
}
// if we want to get the leaderboard from the players with the most wins
// then we need to start iterating the state from the "bottom"
else if (!least_to_most_wins) {
key.wins = u32.MAX_VALUE;
key.player = new Uint8Array(25).fill(u8.MAX_VALUE);
}
const res = new gamestats.get_leaderboard_result();
let obj: System.ProtoDatabaseObject<gamestats.empty_message> | null;
let tmpKey: gamestats.leaderboard_key;
do {
obj = least_to_most_wins
? this._leaderboardStorage.getNext(key)
: this._leaderboardStorage.getPrev(key);
if (obj) {
// decode key
tmpKey = Protobuf.decode<gamestats.leaderboard_key>(
obj.key!,
gamestats.leaderboard_key.decode
);
// add key to result
res.leaderboard.push(tmpKey);
// decrease limit
limit--;
key = tmpKey;
}
} while (obj != null && limit > 0);
return res;
}
get_games_stats(
args: gamestats.get_games_stats_arguments
): gamestats.get_games_stats_result {
const offset_key = args.offset_key;
let limit = args.limit || u64.MAX_VALUE;
// oldest_to_newest indicates that we want the games
// from the oldest to the newest ones
const oldest_to_newest = args.oldest_to_newest;
// construct leaderboard key
let key = new gamestats.game_stats_key();
// if an offset key was provided
if (offset_key) {
key = offset_key;
}
// if no offset key was provided and we want the games stats from the newest to the oldest
else if (!oldest_to_newest) {
key.game_id = u64.MAX_VALUE;
}
const res = new gamestats.get_games_stats_result();
let obj: System.ProtoDatabaseObject<gamestats.game_stats_object> | null;
let tmpKey: gamestats.game_stats_key;
do {
obj = oldest_to_newest
? this._gamesStatsStorage.getNext(key)
: this._gamesStatsStorage.getPrev(key);
if (obj) {
// decode key
tmpKey = Protobuf.decode<gamestats.game_stats_key>(
obj.key!,
gamestats.game_stats_key.decode
);
// add game stats object to result
res.games_stats.push(obj.value);
// decrease limit
limit--;
key = tmpKey;
}
} while (obj != null && limit > 0);
return res;
}
}