diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index 6894d28d..2cdf04ba 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -17,6 +17,11 @@ import { startTest } from './methods/auth/start-test' import { start } from './methods/auth/start' import { answerCallbackQuery } from './methods/bots/answer-callback-query' import { answerInlineQuery } from './methods/bots/answer-inline-query' +import { + getGameHighScores, + getInlineGameHighScores, +} from './methods/bots/get-game-high-scores' +import { setGameScore, setInlineGameScore } from './methods/bots/set-game-score' import { addChatMembers } from './methods/chats/add-chat-members' import { archiveChats } from './methods/chats/archive-chats' import { banChatMember } from './methods/chats/ban-chat-member' @@ -583,6 +588,84 @@ export interface TelegramClient extends BaseTelegramClient { parseMode?: string | null } ): Promise + /** + * Get high scores of a game + * + * @param chatId ID of the chat where the game was found + * @param message ID of the message containing the game + * @param userId ID of the user to find high scores for + */ + getGameHighScores( + chatId: InputPeerLike, + message: number, + userId?: InputPeerLike + ): Promise + /** + * Get high scores of a game from an inline message + * + * @param messageId ID of the inline message containing the game + * @param userId ID of the user to find high scores for + */ + getInlineGameHighScores( + messageId: string | tl.TypeInputBotInlineMessageID, + userId?: InputPeerLike + ): Promise + /** + * Set a score of a user in a game + * + * @param chatId Chat where the game was found + * @param message ID of the message where the game was found + * @param userId ID of the user who has scored + * @param score The new score (must be >0) + * @param params + * @returns The modified message + */ + setGameScore( + chatId: InputPeerLike, + message: number, + userId: InputPeerLike, + score: number, + params?: { + /** + * When `true`, the game message will not be modified + * to include the new score + */ + noEdit?: boolean + + /** + * Whether to allow user's score to decrease. + * This can be useful when fixing mistakes or banning cheaters + */ + force?: boolean + } + ): Promise + /** + * Set a score of a user in a game contained in + * an inline message + * + * @param messageId ID of the inline message + * @param userId ID of the user who has scored + * @param score The new score (must be >0) + * @param params + */ + setInlineGameScore( + messageId: string | tl.TypeInputBotInlineMessageID, + userId: InputPeerLike, + score: number, + params?: { + /** + * When `true`, the game message will not be modified + * to include the new score + */ + noEdit?: boolean + + /** + * Whether to allow user's score to decrease. + * This can be useful when fixing mistakes or banning cheaters + */ + force?: boolean + } + ): Promise /** * Add new members to a group, supergroup or channel. * @@ -2877,6 +2960,10 @@ export class TelegramClient extends BaseTelegramClient { start = start answerCallbackQuery = answerCallbackQuery answerInlineQuery = answerInlineQuery + getGameHighScores = getGameHighScores + getInlineGameHighScores = getInlineGameHighScores + setGameScore = setGameScore + setInlineGameScore = setInlineGameScore addChatMembers = addChatMembers archiveChats = archiveChats banChatMember = banChatMember diff --git a/packages/client/src/methods/bots/get-game-high-scores.ts b/packages/client/src/methods/bots/get-game-high-scores.ts new file mode 100644 index 00000000..13e746b8 --- /dev/null +++ b/packages/client/src/methods/bots/get-game-high-scores.ts @@ -0,0 +1,84 @@ +import { TelegramClient } from '../../client' +import { InputPeerLike, MtCuteInvalidPeerTypeError } from '../../types' +import { GameHighScore } from '../../types/bots/game-high-score' +import { tl } from '@mtcute/tl' +import { + createUsersChatsIndex, + normalizeToInputUser, +} from '../../utils/peer-utils' + +/** + * Get high scores of a game + * + * @param chatId ID of the chat where the game was found + * @param message ID of the message containing the game + * @param userId ID of the user to find high scores for + * @internal + */ +export async function getGameHighScores( + this: TelegramClient, + chatId: InputPeerLike, + message: number, + userId?: InputPeerLike +): Promise { + const chat = await this.resolvePeer(chatId) + + let user: tl.TypeInputUser + if (userId) { + const res = normalizeToInputUser(await this.resolvePeer(userId)) + if (!res) throw new MtCuteInvalidPeerTypeError(userId, 'user') + + user = res + } else { + user = { _: 'inputUserEmpty' } + } + + const res = await this.call({ + _: 'messages.getGameHighScores', + peer: chat, + id: message, + userId: user, + }) + + const { users } = createUsersChatsIndex(res) + + return res.scores.map((score) => new GameHighScore(this, score, users)) +} + +/** + * Get high scores of a game from an inline message + * + * @param messageId ID of the inline message containing the game + * @param userId ID of the user to find high scores for + * @internal + */ +export async function getInlineGameHighScores( + this: TelegramClient, + messageId: string | tl.TypeInputBotInlineMessageID, + userId?: InputPeerLike +): Promise { + const [id, connection] = await this._normalizeInline(messageId) + + let user: tl.TypeInputUser + if (userId) { + const res = normalizeToInputUser(await this.resolvePeer(userId)) + if (!res) throw new MtCuteInvalidPeerTypeError(userId, 'user') + + user = res + } else { + user = { _: 'inputUserEmpty' } + } + + const res = await this.call( + { + _: 'messages.getInlineGameHighScores', + id, + userId: user, + }, + { connection } + ) + + const { users } = createUsersChatsIndex(res) + + return res.scores.map((score) => new GameHighScore(this, score, users)) +} diff --git a/packages/client/src/methods/bots/set-game-score.ts b/packages/client/src/methods/bots/set-game-score.ts new file mode 100644 index 00000000..e7b2fc69 --- /dev/null +++ b/packages/client/src/methods/bots/set-game-score.ts @@ -0,0 +1,103 @@ +import { InputPeerLike, Message, MtCuteInvalidPeerTypeError } from '../../types' +import { TelegramClient } from '../../client' +import { normalizeToInputUser } from '../../utils/peer-utils' +import { tl } from '@mtcute/tl' + +/** + * Set a score of a user in a game + * + * @param chatId Chat where the game was found + * @param message ID of the message where the game was found + * @param userId ID of the user who has scored + * @param score The new score (must be >0) + * @param params + * @returns The modified message + * @internal + */ +export async function setGameScore( + this: TelegramClient, + chatId: InputPeerLike, + message: number, + userId: InputPeerLike, + score: number, + params?: { + /** + * When `true`, the game message will not be modified + * to include the new score + */ + noEdit?: boolean + + /** + * Whether to allow user's score to decrease. + * This can be useful when fixing mistakes or banning cheaters + */ + force?: boolean + } +): Promise { + if (!params) params = {} + + const chat = await this.resolvePeer(chatId) + const user = normalizeToInputUser(await this.resolvePeer(userId)) + if (!user) throw new MtCuteInvalidPeerTypeError(userId, 'user') + + const res = await this.call({ + _: 'messages.setGameScore', + peer: chat, + id: message, + userId: user, + score, + editMessage: !params.noEdit, + force: params.force, + }) + + return this._findMessageInUpdate(res, true) +} + +/** + * Set a score of a user in a game contained in + * an inline message + * + * @param messageId ID of the inline message + * @param userId ID of the user who has scored + * @param score The new score (must be >0) + * @param params + * @internal + */ +export async function setInlineGameScore( + this: TelegramClient, + messageId: string | tl.TypeInputBotInlineMessageID, + userId: InputPeerLike, + score: number, + params?: { + /** + * When `true`, the game message will not be modified + * to include the new score + */ + noEdit?: boolean + + /** + * Whether to allow user's score to decrease. + * This can be useful when fixing mistakes or banning cheaters + */ + force?: boolean + } +): Promise { + if (!params) params = {} + + const user = normalizeToInputUser(await this.resolvePeer(userId)) + if (!user) throw new MtCuteInvalidPeerTypeError(userId, 'user') + + const [id, connection] = await this._normalizeInline(messageId) + + await this.call( + { + _: 'messages.setInlineGameScore', + id, + userId: user, + score, + editMessage: !params.noEdit, + force: params.force, + }, + { connection } + ) +} diff --git a/packages/client/src/types/bots/game-high-score.ts b/packages/client/src/types/bots/game-high-score.ts new file mode 100644 index 00000000..2dc6d7bb --- /dev/null +++ b/packages/client/src/types/bots/game-high-score.ts @@ -0,0 +1,48 @@ +import { makeInspectable } from '../utils' +import { TelegramClient } from '../../client' +import { tl } from '@mtcute/tl' +import { User, UsersIndex } from '../peers' + +/** + * Game high score + */ +export class GameHighScore { + readonly client: TelegramClient + readonly raw: tl.RawHighScore + + readonly _users: UsersIndex + + constructor (client: TelegramClient, raw: tl.RawHighScore, users: UsersIndex) { + this.client = client + this.raw = raw + this._users = users + } + + private _user?: User + /** + * User who has scored this score + */ + get user(): User { + if (!this._user) { + this._user = new User(this.client, this._users[this.raw.userId]) + } + + return this._user + } + + /** + * Position in the records list + */ + get position(): number { + return this.raw.pos + } + + /** + * Score + */ + get score(): number { + return this.raw.score + } +} + +makeInspectable(GameHighScore)