@hieuzest/koishi-plugin-riichi-city 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/api.d.ts CHANGED
@@ -79,9 +79,11 @@ export declare class RiichiCityApi {
79
79
  stageType?: number;
80
80
  matchType?: number;
81
81
  gamePlay?: number;
82
- round?: number;
83
- classifyID: string;
84
- }): Promise<types.Game[]>;
82
+ round?: 1 | 2;
83
+ playerCount?: 3 | 4;
84
+ friend?: boolean;
85
+ classifyID?: string;
86
+ }): Promise<types.Room[]>;
85
87
  listPaipus(options: {
86
88
  startTime?: number;
87
89
  endTime?: number;
@@ -92,6 +94,8 @@ export declare class RiichiCityApi {
92
94
  limit?: number;
93
95
  skip?: number;
94
96
  }): Promise<types.Paipu[]>;
97
+ getRoomData(roomId: string): Promise<types.RoomData>;
98
+ getGameData(roomId: string, eventStartPos: number): Promise<types.GameData>;
95
99
  }
96
100
  export declare namespace RiichiCityApi {
97
101
  export interface Cookie {
package/lib/api.js CHANGED
@@ -270,6 +270,8 @@ var RiichiCityApi = class _RiichiCityApi {
270
270
  const res = await this.post("/lobbys/getSelfManageInfo", { matchID });
271
271
  return res.data;
272
272
  }
273
+ // Lobby games: { classifyID }
274
+ // Rank games: { playerCount, round, stageType }
273
275
  async listGames(options) {
274
276
  const res = await this.post("/record/readOnlineRoom", options);
275
277
  return res.data;
@@ -279,6 +281,14 @@ var RiichiCityApi = class _RiichiCityApi {
279
281
  const res = await this.post("/record/readPaiPuList", { limit, skip, ...options });
280
282
  return res.data;
281
283
  }
284
+ async getRoomData(roomId) {
285
+ const res = await this.post("/record/getRoomData", { isObserve: true, keyValue: roomId });
286
+ return res.data;
287
+ }
288
+ async getGameData(roomId, eventStartPos) {
289
+ const res = await this.post("/record/getGameData", { roomId, eventStartPos });
290
+ return res.data;
291
+ }
282
292
  };
283
293
  ((RiichiCityApi2) => {
284
294
  function md5(data) {
package/lib/index.d.ts CHANGED
@@ -1,20 +1,31 @@
1
- import { Context, Schema, Service } from 'koishi';
1
+ import { Context, Dict, Schema, Service } from 'koishi';
2
2
  import { RiichiCityApi } from './api';
3
3
  import { RiichiCityDHS } from './dhs';
4
4
  declare module 'koishi' {
5
5
  interface Context {
6
6
  'riichi-city': RiichiCity;
7
7
  }
8
+ interface Tables {
9
+ 'riichi-city.accounts': RiichiCityAccount;
10
+ }
11
+ }
12
+ export interface RiichiCityAccount {
13
+ userId: number;
14
+ nickname: string;
15
+ updatedAt?: number;
8
16
  }
9
17
  export declare class RiichiCity extends Service {
10
18
  ctx: Context;
11
19
  config: RiichiCity.Config;
12
20
  api: RiichiCityApi;
13
21
  constructor(ctx: Context, config: RiichiCity.Config);
22
+ getAccountsByNicknames(nicknames: string[], query?: boolean): Promise<Dict<RiichiCityAccount[]>>;
23
+ getAccounts(userIds: number[]): Promise<Dict<RiichiCityAccount | undefined>>;
24
+ setAccounts(accounts: RiichiCityAccount[]): Promise<void>;
14
25
  }
15
26
  export declare namespace RiichiCity {
27
+ const inject: string[];
16
28
  type Config = RiichiCityApi.Config & {
17
- name?: string;
18
29
  dhs: RiichiCityDHS.Config;
19
30
  };
20
31
  const Config: Schema<Config>;
package/lib/index.js CHANGED
@@ -188,7 +188,7 @@ ${config.extraHelp}`.trim();
188
188
  return "已关闭通知";
189
189
  } else {
190
190
  c.notifyIdle = 0;
191
- c.notifyCache = /* @__PURE__ */ Object.create(null);
191
+ c.notifyCache = [];
192
192
  c.notify = ctx.setInterval(async () => {
193
193
  const send = /* @__PURE__ */ __name(async (roomID, retry = 0) => {
194
194
  const paipu = await c.listPaipus().then((l) => l.find((x) => x.roomID === roomID));
@@ -206,19 +206,19 @@ ${config.extraHelp}`.trim();
206
206
  }, "send");
207
207
  try {
208
208
  const games = await c.listGames();
209
- if (c.notifyCache) {
209
+ if (c.notifyCache?.length) {
210
210
  for (const roomID of Object.keys(c.notifyCache)) {
211
211
  if (!games.some((g) => g.roomID === roomID)) {
212
212
  ctx.setTimeout(() => send(roomID), 1e3 * 5);
213
213
  }
214
214
  }
215
215
  }
216
- if (!games?.length && !Object.keys(c.notifyCache ?? {}).length) c.notifyIdle++;
216
+ if (!games?.length && !c.notifyCache?.length) c.notifyIdle++;
217
217
  if (c.notifyIdle > config.notifyIdle) {
218
218
  c.notify?.();
219
219
  return "自动关闭通知";
220
220
  }
221
- c.notifyCache = Object.fromEntries(games.map((g) => [g.roomID, g]));
221
+ c.notifyCache = games.map((g) => g.roomID);
222
222
  } catch (e) {
223
223
  console.warn(e);
224
224
  c.notifyIdle++;
@@ -394,6 +394,7 @@ var Rcpt = class {
394
394
  const findFriend = await this.api.findFriend(pattern).catch(import_koishi2.noop);
395
395
  const friend = findFriend?.friendList?.find((f) => f.nickname === pattern);
396
396
  if (!friend) return session.text(".failed");
397
+ ctx["riichi-city"].setAccounts([{ userId: friend.userID, nickname: friend.nickname }]);
397
398
  userId = friend.userID;
398
399
  }
399
400
  try {
@@ -429,10 +430,17 @@ ${session.text(".recent-results")} [${ranks.three.lastRankList.reverse().join(""
429
430
  // src/index.ts
430
431
  var RiichiCity = class extends import_koishi3.Service {
431
432
  constructor(ctx, config) {
432
- super(ctx, config.name || "riichi-city", true);
433
+ super(ctx, "riichi-city", true);
433
434
  this.ctx = ctx;
434
435
  this.config = config;
435
436
  ctx.i18n.define("zh-CN", require_zh_CN());
437
+ ctx.model.extend("riichi-city.accounts", {
438
+ userId: "unsigned",
439
+ nickname: "string",
440
+ updatedAt: "unsigned"
441
+ }, {
442
+ primary: "userId"
443
+ });
436
444
  this.api = new import_api2.RiichiCityApi(ctx, config);
437
445
  ctx.on("ready", async () => {
438
446
  await this.api.login().catch((e) => ctx.logger.warn(e));
@@ -444,12 +452,43 @@ var RiichiCity = class extends import_koishi3.Service {
444
452
  __name(this, "RiichiCity");
445
453
  }
446
454
  api;
455
+ async getAccountsByNicknames(nicknames, query = true) {
456
+ const curtime = Date.now() / 1e3;
457
+ const list = await this.ctx.database.select("riichi-city.accounts", { nickname: nicknames }).groupBy("nickname", {
458
+ accounts: /* @__PURE__ */ __name((row) => import_koishi3.$.array(import_koishi3.$.object(row)), "accounts")
459
+ }).execute();
460
+ const res = Object.fromEntries(list.map((l) => [l.nickname, l.accounts.sort((a, b) => b.updatedAt - a.updatedAt)]));
461
+ if (!query) return res;
462
+ const upsert = [];
463
+ await Promise.all(nicknames.filter((nickname) => !res[nickname]).map((nickname) => this.api.findFriend(nickname).catch(import_koishi3.noop))).then((friends) => {
464
+ friends.forEach((friend) => {
465
+ console.log(">", friend);
466
+ if (!friend?.friendList?.length) return;
467
+ for (const info of friend.friendList) {
468
+ (res[info.nickname] ??= []).push({ userId: info.userID, nickname: info.nickname, updatedAt: curtime });
469
+ upsert.push({ userId: info.userID, nickname: info.nickname, updatedAt: curtime });
470
+ }
471
+ });
472
+ });
473
+ if (upsert.length) this.setAccounts(upsert);
474
+ return res;
475
+ }
476
+ async getAccounts(userIds) {
477
+ const res = Object.fromEntries(userIds.map((userId) => [userId, void 0]));
478
+ Object.assign(Object.fromEntries(await this.ctx.database.get("riichi-city.accounts", { userId: userIds }).then((x) => x.map((x2) => [x2.userId, x2]))), res);
479
+ return res;
480
+ }
481
+ async setAccounts(accounts) {
482
+ const curtime = Date.now() / 1e3;
483
+ accounts = accounts.map((x) => ({ updatedAt: curtime, ...x }));
484
+ await this.ctx.database.upsert("riichi-city.accounts", accounts);
485
+ }
447
486
  };
448
487
  ((RiichiCity2) => {
488
+ RiichiCity2.inject = ["database"];
449
489
  RiichiCity2.Config = import_koishi3.Schema.intersect([
450
490
  import_api2.RiichiCityApi.Config,
451
491
  import_koishi3.Schema.object({
452
- name: import_koishi3.Schema.string(),
453
492
  dhs: RiichiCityDHS.Config
454
493
  })
455
494
  ]);
package/lib/lobby.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Dict, Disposable, SessionError } from 'koishi';
1
+ import { Disposable, SessionError } from 'koishi';
2
2
  import { RiichiCityApi } from './api';
3
3
  import { LobbyDetails } from './types';
4
4
  export declare class DHSError extends SessionError {
@@ -55,7 +55,7 @@ export declare class RiichiCityLobby {
55
55
  details?: LobbyDetails;
56
56
  notify?: Disposable;
57
57
  notifyIdle: number;
58
- notifyCache?: Dict<Game>;
58
+ notifyCache?: string[];
59
59
  constructor(api: RiichiCityApi, id: number);
60
60
  init(): Promise<void>;
61
61
  listAllowedPlayers(): Promise<RiichiCityApi.Identity[]>;
package/lib/types.d.ts CHANGED
@@ -146,7 +146,7 @@ export interface LobbyUser {
146
146
  status: number;
147
147
  userID: number;
148
148
  }
149
- export interface GamePlayer {
149
+ export interface RoomPlayer {
150
150
  headID: number;
151
151
  headTag: number;
152
152
  identity: number;
@@ -159,13 +159,13 @@ export interface GamePlayer {
159
159
  stageLevel: number;
160
160
  userId: number;
161
161
  }
162
- export interface Game {
162
+ export interface Room {
163
163
  isEnd: boolean;
164
164
  isPause: boolean;
165
165
  matchStage: number;
166
166
  nowTime: number;
167
167
  playerCount: number;
168
- players: GamePlayer[];
168
+ players: RoomPlayer[];
169
169
  roomId: string;
170
170
  stageNum: number;
171
171
  startTime: number;
@@ -196,4 +196,43 @@ export interface Paipu {
196
196
  startTime: number;
197
197
  players: PaipuPlayer[];
198
198
  }
199
+ export interface GameEventRecord {
200
+ data: string;
201
+ eventPos: number;
202
+ eventType: number;
203
+ handId: string;
204
+ startTime: number;
205
+ userId: number;
206
+ }
207
+ export interface GameRecord {
208
+ benChangNum: number;
209
+ changCi: number;
210
+ handCardEncode: string;
211
+ handCardSHA256: string;
212
+ handEventRecord: GameEventRecord[];
213
+ handID: string;
214
+ handPos: number;
215
+ paiShan: string;
216
+ players: PaipuPlayer[];
217
+ quanFeng: number;
218
+ }
219
+ export interface RoomData {
220
+ fangFu: number;
221
+ gamePlay: number;
222
+ handRecord: GameRecord[];
223
+ initPoints: number;
224
+ keyValue: string;
225
+ nowTime: number;
226
+ matchStage: number;
227
+ matchType: number;
228
+ roomId: string;
229
+ playerCount: number;
230
+ round: number;
231
+ stageNum: number;
232
+ stageType: number;
233
+ }
234
+ export interface GameData {
235
+ handEventRecord: GameEventRecord[];
236
+ nowTime: number;
237
+ }
199
238
  export declare const stages: string[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hieuzest/koishi-plugin-riichi-city",
3
3
  "description": "",
4
- "version": "0.3.1",
4
+ "version": "0.4.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [