@hieuzest/koishi-plugin-mahjongpub 0.2.11 → 0.2.13

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/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Context, Dict, Schema, Service } from 'koishi';
2
2
  import { ContestAdmin, TeamAdmin } from './api';
3
3
  import { ContestManager } from './manager';
4
+ import { MahjongPub as Contest } from './mahjongpub';
4
5
  declare module 'koishi' {
5
6
  interface Context {
6
7
  mahjongpub: MahjongPub;
@@ -26,6 +27,7 @@ export declare class MahjongPub extends Service {
26
27
  config: MahjongPub.Config;
27
28
  teams: Dict<TeamAdmin>;
28
29
  contests: Dict<ContestAdmin>;
30
+ contest: Contest;
29
31
  constructor(ctx: Context, config: MahjongPub.Config);
30
32
  getTeam(pw: string): Promise<TeamAdmin>;
31
33
  getContest(cid: string, pw: string): Promise<ContestAdmin>;
package/lib/index.js CHANGED
@@ -242,6 +242,7 @@ var ContestAdmin = class {
242
242
  // src/manager.ts
243
243
  var import_koishi2 = require("koishi");
244
244
  var import_api = require("@hieuzest/koishi-plugin-majsoul-dhs/api");
245
+ var import_api2 = require("@hieuzest/koishi-plugin-riichi-city/api");
245
246
  var import_lobby = require("@hieuzest/koishi-plugin-riichi-city/lobby");
246
247
 
247
248
  // src/mahjongpub.ts
@@ -321,7 +322,7 @@ var MahjongPub = class _MahjongPub {
321
322
  maxAge: 60
322
323
  },
323
324
  "getTeams": {
324
- maxAge: 30
325
+ maxAge: 15
325
326
  },
326
327
  "getMatches": {
327
328
  maxAge: 120
@@ -350,15 +351,18 @@ var ContestExtra = class {
350
351
  type;
351
352
  round;
352
353
  lobby;
354
+ playerIndex;
353
355
  ver = 0;
354
356
  async broadcast(msg) {
355
357
  this.subscribers.forEach((channel) => this.ctx.sendMessage(channel, msg).catch((e) => this.ctx.logger.debug(e)));
356
358
  }
357
359
  };
358
- function getRowPlayer(contest, team, rowi) {
359
- const roleList = contest.t_type.split(/\s+/);
360
- const roleSet = [...new Set(roleList).values()];
361
- const index = roleSet.indexOf(roleList[rowi]);
360
+ function getRowPlayer(contest, team, rowi, index) {
361
+ if ((0, import_koishi2.isNullable)(index)) {
362
+ const roleList = contest.t_type.split(/\s+/);
363
+ const roleSet = [...new Set(roleList).values()];
364
+ index = roleSet.indexOf(roleList[rowi]);
365
+ }
362
366
  return team.players[index]?.split("##", 1)[0];
363
367
  }
364
368
  __name(getRowPlayer, "getRowPlayer");
@@ -368,7 +372,7 @@ var ContestManager = class {
368
372
  this.config = config;
369
373
  this.mahjongpub = MahjongPub.new(ctx);
370
374
  ctx.command("mahjongpub.manager", { authority: 3 }).action(import_koishi2.noop);
371
- ctx.command("mahjongpub.manager.init").channelFields(["mahjongpub/bind-contest"]).option("clear", "-c").option("type", "-t [type:string]").option("ver", "-v [ver:number]").option("round", "-r [round:number]").option("lobby", "-l [lobby:string]").action(async ({ session, options }) => {
375
+ ctx.command("mahjongpub.manager.init").channelFields(["mahjongpub/bind-contest"]).option("clear", "-c").option("type", "-t [type:string]").option("ver", "-v [ver:number]").option("round", "-r [round:number]").option("lobby", "-l [lobby:string]").option("index", "-i [index:number]").action(async ({ session, options }) => {
372
376
  const cid = +(session.channel["mahjongpub/bind-contest"] || 0);
373
377
  if (!cid) return "Unauthorized.";
374
378
  this.extra[cid] ??= new ContestExtra(ctx);
@@ -378,6 +382,7 @@ var ContestManager = class {
378
382
  if (!(0, import_koishi2.isNullable)(options.ver)) this.extra[cid].ver = options.ver;
379
383
  if (!(0, import_koishi2.isNullable)(options.round)) this.extra[cid].round = options.round;
380
384
  if (!(0, import_koishi2.isNullable)(options.lobby)) this.extra[cid].lobby = options.lobby;
385
+ if (!(0, import_koishi2.isNullable)(options.index)) this.extra[cid].playerIndex = options.index;
381
386
  return "Finished.";
382
387
  });
383
388
  ctx.command("mahjongpub.manager.deinit").channelFields(["mahjongpub/bind-contest"]).option("clear", "-c").action(async ({ session, options }) => {
@@ -387,14 +392,16 @@ var ContestManager = class {
387
392
  this.extra[cid].subscribers.delete(session.cid);
388
393
  return "Finished.";
389
394
  });
390
- ctx.command("mahjongpub.manager.start [cls:number]").channelFields(["mahjongpub/bind-contest"]).option("force", "-f").action(async ({ session, options }, cls) => {
395
+ ctx.command("mahjongpub.manager.start [...cls:number]").channelFields(["mahjongpub/bind-contest"]).option("force", "-f").action(async ({ session, options }, ...clsz) => {
391
396
  const cid = +(session.channel["mahjongpub/bind-contest"] || 0);
392
397
  if (!cid) return "Unauthorized.";
393
398
  const cextra = this.extra[cid] ??= new ContestExtra(ctx);
394
399
  cextra.subscribers.add(session.cid);
395
- if (cls) {
396
- cextra.stopCls.delete(cls);
397
- await this.startMatch(cid, cls);
400
+ if (clsz.length) {
401
+ for (const cls of clsz) {
402
+ cextra.stopCls.delete(cls);
403
+ await this.startMatch(cid, cls, 0, options.force);
404
+ }
398
405
  } else {
399
406
  cextra.stopCls.clear();
400
407
  const contest = await this.mahjongpub.getContest(cid);
@@ -406,12 +413,14 @@ var ContestManager = class {
406
413
  }
407
414
  }
408
415
  });
409
- ctx.command("mahjongpub.manager.stop [cls:number]").channelFields(["mahjongpub/bind-contest"]).action(async ({ session }, cls) => {
416
+ ctx.command("mahjongpub.manager.stop [...cls:number]").channelFields(["mahjongpub/bind-contest"]).action(async ({ session }, ...clsz) => {
410
417
  const cid = +(session.channel["mahjongpub/bind-contest"] || 0);
411
- if (!cid) return "Unauthorized/";
418
+ if (!cid) return "Unauthorized.";
412
419
  const cextra = this.extra[cid] ??= new ContestExtra(ctx);
413
- if (cls) {
414
- cextra.stopCls.add(cls);
420
+ if (clsz.length) {
421
+ for (const cls of clsz) {
422
+ cextra.stopCls.add(cls);
423
+ }
415
424
  } else {
416
425
  const contest = await this.mahjongpub.getContest(cid);
417
426
  const rounds = await this.mahjongpub.getRounds(cid);
@@ -473,31 +482,36 @@ var ContestManager = class {
473
482
  return;
474
483
  }
475
484
  const round = Object.values(rounds).find((x) => x.round === (cextra.round ?? contest.c_round) && x.t_class === cls);
476
- const players = round.tids.map((tid) => getRowPlayer(contest, teams[tid], rowi));
485
+ const players = round.tids.map((tid) => getRowPlayer(contest, teams[tid], rowi, cextra.playerIndex));
477
486
  if (!players.every((x) => x)) {
478
487
  cextra.broadcast(`[${tag}] 失败: 名单未填写`);
479
488
  return;
480
489
  }
490
+ let failPatterns;
481
491
  try {
482
492
  if (cextra.type === "ti") {
483
- this.ctx.logger.info(`starting ti match ${cid}-${cls}, players ${players.map((x, i) => `${x} ${lastRecord ? lastRecord.results?.[i].num : 1e5}`).join(", ")}`);
493
+ failPatterns = players.map((x, i) => `${x} ${lastRecord ? lastRecord.results?.[i].num : 1e5}`).join(", ");
494
+ this.ctx.logger.info(`starting ti match ${cid}-${cls}, players ${failPatterns}`);
484
495
  await this.ctx["zx-dhs"].startMatch(
485
496
  +(cextra.lobby ?? round.code),
486
497
  players.map((x, i) => import_lobby.Player.fromPattern(x, lastRecord ? lastRecord.results?.[i].num : 1e5))
487
498
  );
488
499
  } else if (cextra.type === "ssb") {
489
- this.ctx.logger.info(`starting ssb match ${cid}-${cls}, players ${players.join(", ")}`);
500
+ failPatterns = players.join(", ");
501
+ this.ctx.logger.info(`starting ssb match ${cid}-${cls}, players ${failPatterns}`);
490
502
  await this.ctx["majsoul-dhs"].startMatch(+(cextra.lobby ?? round.code), players.map((x) => import_api.Player.fromPattern(x, 25e3)));
503
+ } else {
504
+ throw new Error(`unknown contest type: ${cextra.type}`);
491
505
  }
492
- cextra.broadcast(`[${tag}] 成功:` + players.join(""));
506
+ cextra.broadcast(`[${tag}] 成功:` + players.join(", "));
493
507
  } catch (e) {
494
- if (e instanceof import_lobby.DHSError || e instanceof import_api.DHSError) {
508
+ if (e instanceof import_lobby.DHSError || e instanceof import_api2.RiichiCityError || e instanceof import_api.DHSError) {
495
509
  cextra.broadcast(`[${tag}] 失败:` + e.message + ` (timeout=${timeout / import_koishi2.Time.second}s)`);
496
510
  if (timeout < this.config.startMaxTimeout) {
497
511
  this.ctx.setTimeout(() => this.startMatch(cid, cls, timeout + this.config.startTimeoutInterval), this.config.startTimeoutInterval);
498
512
  } else {
499
513
  this.ctx.logger.warn(`start match ${cid}-${cls} exceed max retires`);
500
- cextra.broadcast(`[${tag}] 失败:超过最大重试时间 【${players.join(" ")}】`);
514
+ cextra.broadcast(`[${tag}] 失败:超过最大重试时间 【${failPatterns}】`);
501
515
  }
502
516
  } else {
503
517
  this.ctx.logger.warn(`start match ${cid}-${cls} failed: ${e.message}`);
@@ -553,6 +567,7 @@ var MahjongPub2 = class extends import_koishi3.Service {
553
567
  this.config = config;
554
568
  ctx.plugin(ContestManager, config.manager);
555
569
  ctx.i18n.define("zh-CN", require_zh_CN());
570
+ this.contest = MahjongPub.new(ctx);
556
571
  ctx.model.extend("user", {
557
572
  "mahjongpub/bind-team": "string",
558
573
  "mahjongpub/bind-teams": "json"
@@ -813,6 +828,31 @@ var MahjongPub2 = class extends import_koishi3.Service {
813
828
  }
814
829
  });
815
830
  if (ctx.get("mahjong.database")) {
831
+ ctx.command("mahjongpub.database.record.last <round:natural>", { authority: 3 }).option("rowi", "-i <rowi:integer>", { fallback: -1 }).option("ver", "-v <ver:integer>", { fallback: 0 }).channelFields(["mahjongpub/bind-contest"]).action(async ({ session, options }, round, cls) => {
832
+ const [cid] = [session.channel["mahjongpub/bind-contest"]];
833
+ try {
834
+ const cteams = await this.contest.getTeams(+cid);
835
+ const record = await ctx.mahjong.database.db("scoreboard").collection("matches").find({
836
+ cid,
837
+ round,
838
+ ver: options.ver,
839
+ ...options.rowi === -1 ? {} : { rowi: options.rowi }
840
+ }).sort({ cls: 1, rowi: -1 }).toArray();
841
+ if (!record.length) return session.text(".failed");
842
+ const filtered = [];
843
+ const seenCls = /* @__PURE__ */ new Set();
844
+ record.forEach((r) => {
845
+ if (!seenCls.has(r.cls)) {
846
+ filtered.push(r);
847
+ seenCls.add(r.cls);
848
+ }
849
+ });
850
+ return filtered.map((r) => `[${r.cls}-${r.rowi + 1}] ` + r.results.map((x, i) => `${cteams[r.tids[i]].t_name} ${x.num}`).join(" / ")).join("\n");
851
+ } catch (e) {
852
+ ctx.logger.warn(e);
853
+ return session.text(".failed");
854
+ }
855
+ });
816
856
  ctx.command("mahjongpub.database.record.get <round:natural> <cls:natural>", { authority: 3 }).option("rowi", "-i <rowi:integer>", { fallback: -1 }).option("ver", "-v <ver:integer>", { fallback: 0 }).channelFields(["mahjongpub/bind-contest"]).action(async ({ session, options }, round, cls) => {
817
857
  const [cid] = [session.channel["mahjongpub/bind-contest"]];
818
858
  try {
@@ -897,6 +937,7 @@ var MahjongPub2 = class extends import_koishi3.Service {
897
937
  }
898
938
  teams = {};
899
939
  contests = {};
940
+ contest;
900
941
  async getTeam(pw) {
901
942
  return new TeamAdmin(this.ctx, pw, this.config);
902
943
  }
@@ -17,7 +17,7 @@ export declare class MahjongPub {
17
17
  readonly maxAge: 60;
18
18
  };
19
19
  readonly getTeams: {
20
- readonly maxAge: 30;
20
+ readonly maxAge: 15;
21
21
  };
22
22
  readonly getMatches: {
23
23
  readonly maxAge: 120;
package/lib/manager.d.ts CHANGED
@@ -28,6 +28,7 @@ declare class ContestExtra {
28
28
  type: 'ti' | 'ssb';
29
29
  round?: number;
30
30
  lobby?: string;
31
+ playerIndex?: number;
31
32
  ver: number;
32
33
  constructor(ctx: Context);
33
34
  broadcast(msg: string): Promise<void>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hieuzest/koishi-plugin-mahjongpub",
3
3
  "description": "Mahjong.pub API",
4
- "version": "0.2.11",
4
+ "version": "0.2.13",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [