koishi-plugin-dew-bot 1.0.232 → 1.0.239

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.
Files changed (86) hide show
  1. package/README.md +23 -0
  2. package/assets/item-card/paper.webp +0 -0
  3. package/assets/leaderboard/README.md +9 -0
  4. package/assets/leaderboard/header.svg +1 -0
  5. package/assets/skill-card/LICENSE.yugioh-card +21 -0
  6. package/assets/skill-card/README.md +4 -0
  7. package/assets/skill-card/card-spell.png +0 -0
  8. package/assets/skill-card/card-trap.png +0 -0
  9. package/lib/index.d.ts +10 -0
  10. package/lib/index.js +1278 -0
  11. package/lib/inits.d.ts +3 -0
  12. package/lib/plugin/cardLayout.d.ts +2 -0
  13. package/lib/plugin/itemCardTemplate.d.ts +3 -0
  14. package/lib/plugin/leaderboardTemplate.d.ts +3 -0
  15. package/lib/plugin/messageQueue.d.ts +11 -0
  16. package/lib/plugin/server.d.ts +21 -0
  17. package/lib/plugin/serverHandel/handel_base.d.ts +9 -0
  18. package/lib/plugin/serverHandel/image.d.ts +5 -0
  19. package/lib/plugin/serverHandel/text.d.ts +5 -0
  20. package/lib/plugin/sessions.d.ts +12 -0
  21. package/lib/plugin/skillArtwork.d.ts +2 -0
  22. package/lib/plugin/skillCard.d.ts +5 -0
  23. package/lib/plugin/skillCardTemplate.d.ts +2 -0
  24. package/lib/shared/bot/MsgMessage.d.ts +7 -0
  25. package/lib/shared/bot/PtlMessage.d.ts +17 -0
  26. package/lib/shared/bot/PtlPing.d.ts +8 -0
  27. package/lib/shared/bot/analysisMsg.d.ts +5 -0
  28. package/lib/shared/bot/protocols/base.d.ts +13 -0
  29. package/lib/shared/bot/serviceProto.d.ts +20 -0
  30. package/lib/shared/face/index.d.ts +81 -0
  31. package/lib/skill-card-preview.cjs +133 -0
  32. package/package.json +17 -22
  33. package/src/index.ts +18 -0
  34. package/src/inits.ts +26 -0
  35. package/src/plugin/cardLayout.ts +29 -0
  36. package/src/plugin/itemCardTemplate.ts +19 -0
  37. package/src/plugin/leaderboardTemplate.ts +26 -0
  38. package/src/plugin/messageQueue.ts +36 -0
  39. package/src/plugin/server.ts +154 -0
  40. package/src/plugin/serverHandel/handel_base.ts +26 -0
  41. package/src/plugin/serverHandel/image.ts +21 -0
  42. package/src/plugin/serverHandel/text.ts +10 -0
  43. package/src/plugin/sessions.ts +30 -0
  44. package/src/plugin/skillArtwork.ts +29 -0
  45. package/src/plugin/skillCard.ts +67 -0
  46. package/src/plugin/skillCardTemplate.ts +12 -0
  47. package/src/shared/bot/MsgMessage.ts +8 -0
  48. package/src/shared/bot/PtlMessage.ts +22 -0
  49. package/src/shared/bot/PtlPing.ts +13 -0
  50. package/src/shared/bot/analysisMsg.ts +29 -0
  51. package/src/shared/bot/protocols/base.ts +16 -0
  52. package/src/shared/bot/serviceProto.ts +679 -0
  53. package/src/shared/face/index.ts +69 -0
  54. package/dist/html/css/body.css +0 -287
  55. package/dist/html/css/panel_common.css +0 -102
  56. package/dist/html/css/ranking.css +0 -215
  57. package/dist/html/page/body.html +0 -96
  58. package/dist/html/page/panel_common.html +0 -82
  59. package/dist/html/page/ranking.html +0 -257
  60. package/dist/html/res/avatar.jpg +0 -0
  61. package/dist/html/res/body/box.png +0 -0
  62. package/dist/html/res/body/share/test.png +0 -0
  63. package/dist/html/res/body/title/test.png +0 -0
  64. package/dist/html/res/body/title/test1.png +0 -0
  65. package/dist/html/res/font/cn.ttf +0 -0
  66. package/dist/html/res/font/xiaomai.ttf +0 -0
  67. package/dist/html/res/vue2.js +0 -11
  68. package/dist/index.js +0 -18
  69. package/dist/inits.js +0 -30
  70. package/dist/plugin/messageQueue.js +0 -136
  71. package/dist/plugin/puppeteer.js +0 -79
  72. package/dist/plugin/server.js +0 -219
  73. package/dist/plugin/serverHandel/handel_base.js +0 -36
  74. package/dist/plugin/serverHandel/image.js +0 -18
  75. package/dist/plugin/serverHandel/none.js +0 -15
  76. package/dist/plugin/serverHandel/text.js +0 -17
  77. package/dist/plugin/sessions.js +0 -35
  78. package/dist/shared/bot/AnalysisClass/class_battleLog.js +0 -104
  79. package/dist/shared/bot/AnalysisClass/class_skillDetail.js +0 -152
  80. package/dist/shared/bot/MsgMessage.js +0 -2
  81. package/dist/shared/bot/PtlMessage.js +0 -6
  82. package/dist/shared/bot/analysisMsg.js +0 -65
  83. package/dist/shared/bot/protocols/base.js +0 -2
  84. package/dist/shared/bot/serviceProto.js +0 -352
  85. package/dist/shared/face/index.js +0 -23
  86. package/readme.md +0 -80
package/lib/index.js ADDED
@@ -0,0 +1,1278 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
+ var __export = (target, all) => {
9
+ for (var name2 in all)
10
+ __defProp(target, name2, { get: all[name2], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ Config: () => Config,
34
+ apply: () => apply2,
35
+ inject: () => inject,
36
+ name: () => name
37
+ });
38
+ module.exports = __toCommonJS(src_exports);
39
+ var import_koishi2 = require("koishi");
40
+
41
+ // src/plugin/serverHandel/image.ts
42
+ var import_koishi = require("koishi");
43
+
44
+ // src/shared/bot/analysisMsg.ts
45
+ var AnalysisMsg = class {
46
+ static {
47
+ __name(this, "AnalysisMsg");
48
+ }
49
+ parse(data) {
50
+ let msg = "";
51
+ let haveTitle = false;
52
+ for (const item of data.line) {
53
+ switch (item.type) {
54
+ case 0 /* title */:
55
+ haveTitle = true;
56
+ msg += `┄━═${item.content}═━┄
57
+ `;
58
+ break;
59
+ case 1 /* line */:
60
+ msg += `${item.content}
61
+ `;
62
+ break;
63
+ case 2 /* error */:
64
+ msg += `❌出错了!错误原因:${item.content},请反馈至联系开发者
65
+ `;
66
+ break;
67
+ default:
68
+ break;
69
+ }
70
+ }
71
+ if (haveTitle) {
72
+ msg += "┄━════════━┄";
73
+ }
74
+ return msg;
75
+ }
76
+ };
77
+
78
+ // src/plugin/itemCardTemplate.ts
79
+ var escape = /* @__PURE__ */ __name((value) => String(value ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]), "escape");
80
+ function itemCardHtml(card, artwork, paper) {
81
+ return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><style>
82
+ *{box-sizing:border-box}html,body{margin:0;width:760px;color:#29271f;font-family:SimSun,'Noto Serif CJK SC','Microsoft YaHei',serif}
83
+ #capture{width:760px;min-height:1140px;padding:30px 48px 38px;background-color:#f3eddf;${paper ? `background-image:url('${escape(paper)}');background-size:100% 100%;` : ""}box-shadow:inset 0 0 55px #85796228;position:relative}
84
+ .catalog-label{display:flex;align-items:center;justify-content:center;gap:22px;font-size:25px;letter-spacing:8px;margin-bottom:32px}.catalog-label:before,.catalog-label:after{content:'';width:106px;height:1px;background:#69625288}
85
+ .item-heading{display:grid;grid-template-columns:140px minmax(0,1fr) 140px;align-items:center;margin-bottom:10px;min-height:76px}.item-title{font-family:KaiTi,STKaiti,'Noto Serif CJK SC',serif;font-weight:700;font-size:51px;line-height:1.3;overflow-wrap:anywhere;grid-column:2;text-align:center;margin:0}
86
+ .quality{grid-column:3;grid-row:1;justify-self:end;display:flex;align-items:center;gap:8px;flex-shrink:0}.quality-label{writing-mode:vertical-rl;font-size:18px;letter-spacing:4px}.quality-seal{border:3px double #a33f31;padding:8px 5px;min-width:68px;max-width:116px;text-align:center;color:#a33f31;font-family:KaiTi,STKaiti,serif;font-size:33px;font-weight:bold;box-shadow:inset 0 0 0 2px #a33f3126;overflow-wrap:anywhere}
87
+ .item-type{text-align:center;font-size:24px;margin:16px 0 22px;overflow-wrap:anywhere}
88
+ .item-art-frame{width:548px;height:548px;padding:8px;margin:0 auto;border:2px solid #4b473d;outline:1px solid #4b473d88;outline-offset:4px;background:#eee6d5}
89
+ .item-artwork{display:block;width:100%;height:100%;object-fit:cover;background:#ede6d8}
90
+ .item-count{display:flex;gap:20px;justify-content:center;align-items:center;font-size:26px;margin:25px 0 30px;overflow-wrap:anywhere}.item-count:before,.item-count:after{content:'';height:1px;width:85px;background:#77705f88}
91
+ .description-title{display:flex;align-items:center;gap:22px;font-family:KaiTi,STKaiti,serif;font-size:34px;font-weight:bold;margin-bottom:16px}.description-title:after{content:'';height:1px;background:#655e5088;flex:1}
92
+ .item-description{font-size:25px;line-height:1.75;white-space:pre-wrap;overflow-wrap:anywhere;margin:0 0 42px;min-height:88px}
93
+ .item-price{border-top:1px solid #736b5b88;padding-top:22px;font-size:24px;line-height:1.6;white-space:pre-wrap;overflow-wrap:anywhere}
94
+ </style></head><body><article id="capture"><div class="catalog-label">道具图鉴</div><header class="item-heading"><h1 class="item-title">${escape(card.name)}</h1><div class="quality"><span class="quality-label">品质</span><span class="quality-seal">${escape(card.quality)}</span></div></header><div class="item-type">类型:${escape(card.type)}</div><div class="item-art-frame"><img class="item-artwork" alt="道具插画" src="${escape(artwork)}"></div><div class="item-count">数量:${escape(card.count)}</div><div class="description-title">描述</div><p class="item-description">${escape(card.description)}</p><footer class="item-price">参考价格:${escape(card.referencePrice)}</footer></article></body></html>`;
95
+ }
96
+ __name(itemCardHtml, "itemCardHtml");
97
+
98
+ // src/plugin/cardLayout.ts
99
+ async function layoutCard(document = globalThis.document) {
100
+ await document.fonts.ready;
101
+ const itemArtwork = document.querySelector(".item-artwork");
102
+ if (itemArtwork) await itemArtwork.decode();
103
+ const artwork = document.querySelector(".skill-artwork");
104
+ if (artwork) {
105
+ try {
106
+ await artwork.decode();
107
+ } catch {
108
+ artwork.remove();
109
+ }
110
+ }
111
+ const background = document.querySelector(".board-background");
112
+ if (background) {
113
+ try {
114
+ await background.decode();
115
+ } catch {
116
+ background.remove();
117
+ document.getElementById("capture")?.classList.remove("has-background");
118
+ }
119
+ }
120
+ for (const avatar of document.querySelectorAll(".avatar")) {
121
+ for (let size = 30; size >= 16; size--) {
122
+ avatar.style.fontSize = size + "px";
123
+ if (avatar.scrollWidth <= avatar.clientWidth) break;
124
+ }
125
+ }
126
+ const name2 = document.getElementById("name");
127
+ if (!name2) return;
128
+ for (let size = 36; size >= 20; size--) {
129
+ name2.style.fontSize = size + "px";
130
+ if (name2.scrollWidth <= name2.clientWidth && name2.scrollHeight <= name2.clientHeight) break;
131
+ }
132
+ const effect = document.getElementById("effect");
133
+ for (let size = 23; size >= 18; size--) {
134
+ effect.style.fontSize = size + "px";
135
+ if (effect.scrollHeight <= effect.clientHeight) break;
136
+ }
137
+ if (effect.scrollHeight > effect.clientHeight) {
138
+ const extra = effect.scrollHeight - effect.clientHeight;
139
+ effect.style.height = effect.scrollHeight + "px";
140
+ document.getElementById("card").style.height = 1107 + extra + "px";
141
+ }
142
+ }
143
+ __name(layoutCard, "layoutCard");
144
+
145
+ // src/plugin/leaderboardTemplate.ts
146
+ var escape2 = /* @__PURE__ */ __name((s) => String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]), "escape");
147
+ function leaderboardHtml(data, _headerImage, backgroundImage) {
148
+ const rows = data.rows.slice(0, 20);
149
+ const row = /* @__PURE__ */ __name((r, mine = false) => `<div class="row rank-${r.rank} ${mine ? "personal" : ""}"><div class="rank">${mine ? "<small>我的排名</small>" : ""}<b>${escape2(r.rank)}</b></div><div class="avatar">${escape2(r.emoji || "👤")}</div><div class="name">${escape2(r.name)}</div><div class="value">${escape2(r.value.toLocaleString("zh-CN", { maximumFractionDigits: 2 }))}</div></div>`, "row");
150
+ const personal = data.mine ? row(data.mine, true) : "";
151
+ return `<!doctype html><html lang="zh-CN"><meta charset="utf-8"><style>
152
+ *{box-sizing:border-box}body{margin:0;width:760px;color:#242725;font-family:"Microsoft YaHei","Noto Sans CJK SC",sans-serif}
153
+ .row{display:grid;grid-template-columns:64px 58px minmax(0,1fr) 180px;align-items:center;gap:9px;padding:12px 10px;min-height:81px;border-bottom:1px solid #d8d2c8}.rank{text-align:center;font-size:26px;font-family:Georgia,"Times New Roman",serif;color:#3f4140}.rank b{font-weight:500}.avatar{display:grid;place-items:center;width:54px;height:54px;border-radius:50%;background:#e2ded3;border:1px solid #c8bfae;font-family:"Segoe UI Emoji","Noto Color Emoji",sans-serif;font-size:30px;white-space:nowrap;overflow:hidden}
154
+ .name{font-size:22px;font-weight:600;line-height:1.4;overflow-wrap:anywhere}.value{text-align:right;font-size:26px;font-family:Georgia,"Times New Roman",serif;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
155
+ .rank-1,.rank-2,.rank-3{margin-bottom:6px;border-radius:6px;border:1px solid #d8bd75;background:linear-gradient(105deg,#e6c37455,#fbefd0)}.rank-2{border-color:#bbc4cb;background:linear-gradient(105deg,#aebdce75,#f0f1f3)}.rank-3{border-color:#d4baa2;background:linear-gradient(105deg,#ba8a6355,#f3e8df)}
156
+ .rank-1 .rank b,.rank-2 .rank b,.rank-3 .rank b{display:inline-grid;place-items:center;width:46px;height:52px;background:linear-gradient(140deg,#f6dd89,#b57b20);clip-path:polygon(50% 0,65% 12%,90% 6%,88% 34%,100% 50%,86% 70%,87% 91%,61% 90%,50% 100%,36% 88%,12% 92%,14% 67%,0 49%,13% 30%,10% 6%,35% 13%);color:white;text-shadow:0 1px 3px #513209;font-size:30px}.rank-2 .rank b{background:linear-gradient(140deg,#dceafb,#5d7d9e)}.rank-3 .rank b{background:linear-gradient(140deg,#ecc6a0,#8e5534)}.rank-1 .value{color:#9b6613}.rank-2 .value{color:#536779}.rank-3 .value{color:#945c32}
157
+ .personal{margin-top:13px;border:1px solid #b6bcc1;border-radius:5px;background:linear-gradient(100deg,#c0cedf88,#f6ead4);min-height:92px}.personal .rank small{display:block;font-family:"Microsoft YaHei",sans-serif;font-size:12px;white-space:nowrap;margin-bottom:4px}.personal .rank b{clip-path:none;background:none;color:#334650;text-shadow:none;height:auto;font-size:29px}.personal .value{color:#94661e}
158
+ .empty{text-align:center;padding:55px 10px;color:#827965;font-size:20px}
159
+ #capture{position:relative;width:760px;min-height:180px;padding:28px 24px;border:1px solid #c4b89b;overflow:hidden;background:#f3eee2}
160
+ .board-title{position:relative;margin:12px 0 30px;padding:8px 10px 20px;text-align:center;font-family:KaiTi,STKaiti,"Microsoft YaHei",serif;font-size:42px;line-height:1.4;color:#574128;letter-spacing:3px;overflow-wrap:anywhere;text-shadow:0 1px 3px #fff9e8}
161
+ .board-background{position:absolute;inset:0;width:100%;height:100%;object-fit:fill;z-index:0}
162
+ .sheet{position:relative;margin:0;padding:10px;border:1px solid #c4b89b88;border-radius:12px;background:#fcfaf5d9;box-shadow:none}
163
+ .row:last-child{border-bottom:0}.name{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;max-height:62px}
164
+ .value{font-size:23px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
165
+ #capture.has-background{padding:90px 80px}.has-background .sheet{background:rgba(250,247,238,.20);border:0}.has-background .row{grid-template-columns:48px 46px minmax(0,1fr) 142px;gap:6px;padding:10px 6px}.has-background .avatar{width:42px;height:42px;font-size:26px}.has-background .name{font-size:20px}
166
+ .has-background .row{background-color:rgba(255,253,246,.38)}
167
+ </style><body><div id="capture" class="${backgroundImage ? "has-background" : ""}">${backgroundImage ? '<img class="board-background" alt="" src="' + escape2(backgroundImage) + '">' : ""}<h1 class="board-title">${escape2(data.title)}</h1><main class="sheet">${rows.length ? rows.map((r) => row(r)).join("") : '<div class="empty">暂无玩家上榜</div>'}${personal}</main></div></body></html>`;
168
+ }
169
+ __name(leaderboardHtml, "leaderboardHtml");
170
+
171
+ // src/plugin/skillCard.ts
172
+ var import_promises = __toESM(require("node:fs/promises"));
173
+ var import_node_path = __toESM(require("node:path"));
174
+
175
+ // src/plugin/skillCardTemplate.ts
176
+ var escape3 = /* @__PURE__ */ __name((value) => String(value ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]), "escape");
177
+ var colors = { F: "#b6c3c9", E: "#82cf88", D: "#5fbeed", C: "#9b8cfa", B: "#d97eee", A: "#f9b25f", S: "#f2dc88", SS: "#ff9e78", SSS: "#fff0b1" };
178
+ function skillCardHtml(card, frame2, artwork) {
179
+ const quality = card.quality.replace(/[+-]$/, ""), color = colors[quality] ?? colors.F;
180
+ const desc = card.description || "暂无描述";
181
+ return `<!doctype html><html><head><meta charset="utf-8"><style>
182
+ *{box-sizing:border-box}html,body{margin:0;width:760px;background:#141c26;color:#15252b;font-family:'Microsoft YaHei','Noto Sans CJK SC',sans-serif}body{padding:0}#capture{width:760px}#card{width:760px;height:1107px;position:relative;background-image:url('${frame2}');background-size:100% 100%}.name{position:absolute;left:58px;top:46px;width:644px;height:74px;display:flex;align-items:center;font-size:36px;font-weight:800;color:#f5f7e9;text-shadow:1px 2px 2px #163838;overflow:hidden}.badge{position:absolute;right:57px;top:54px;width:68px;height:62px;border:2px solid ${color};background:#163338;border-radius:50%;color:${color};display:grid;place-items:center;font:bold 25px Georgia}.meta{position:absolute;left:92px;right:91px;top:151px;display:flex;justify-content:space-between;color:#f9f1cf;font-size:21px;font-weight:700}.art{position:absolute;left:93px;top:205px;width:574px;height:574px;overflow:hidden;background:radial-gradient(ellipse at 50% 43%,#284951 0,#12222f 42%,#070d19 90%);border:3px solid #bea874}.skill-artwork{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:1}.art svg{position:absolute;width:100%;height:100%;color:${color}}.glyph{position:absolute;top:157px;width:100%;text-align:center;font-size:147px;filter:drop-shadow(0 0 30px ${color})}.art-title{position:absolute;bottom:113px;left:25px;right:25px;text-align:center;font-size:18px;letter-spacing:6px;color:${color}}.number{position:absolute;top:786px;right:94px;color:#e2eade;font:14px Georgia;letter-spacing:2px}.effect{position:absolute;top:837px;left:62px;width:636px;height:197px;overflow:hidden;font-size:23px;line-height:1.48}.effect b{font-size:23px}.effect p{margin:8px 0;white-space:pre-wrap;overflow-wrap:anywhere}
183
+ </style></head><body><div id="capture"><div id="card"><div class="name" id="name">${escape3(card.quality)}级 ${escape3(card.name)}</div><div class="meta"><span>【${card.passive ? "被动" : "主动"}技能】</span><span>Lv.${card.level} / ${card.maxLevel}</span></div>
184
+ <div class="art"><svg viewBox="0 0 574 574" xmlns="http://www.w3.org/2000/svg"><defs><radialGradient id="glow"><stop stop-color="${color}" stop-opacity=".25"/><stop offset="1" stop-color="${color}" stop-opacity="0"/></radialGradient></defs><circle cx="287" cy="244" r="220" fill="url(#glow)"/><g stroke="currentColor" fill="none"><circle cx="287" cy="244" r="191" opacity=".35"/><circle cx="287" cy="244" r="179" stroke-dasharray="2 13" opacity=".8"/><circle cx="287" cy="244" r="158" opacity=".6"/><path d="M287 65 442 334 132 334Z M287 423 132 155 442 155Z" opacity=".3"/><path d="M60 244H130M444 244H514M287 18V85M287 403V470" stroke-width="2" opacity=".6"/><path d="M80 440 491 72M102 457 505 95" opacity=".13" stroke-width="16"/></g></svg><div class="art-title">${escape3(card.passive ? "被 动 铭 刻" : "技 能 术 式")}</div>${artwork ? '<img class="skill-artwork" alt="" src="' + escape3(artwork) + '">' : ""}</div>
185
+ <div class="number">DEW · SKILL / ${escape3(card.quality)}</div><div class="effect" id="effect"><p>${escape3(desc)}</p></div></div></div></body></html>`;
186
+ }
187
+ __name(skillCardHtml, "skillCardHtml");
188
+
189
+ // src/plugin/skillArtwork.ts
190
+ var import_image_size = require("image-size");
191
+ async function loadSkillArtwork(address) {
192
+ if (!address) return void 0;
193
+ try {
194
+ const url = new URL(address);
195
+ if (url.protocol !== "https:" || url.username || url.password || url.port || !/^[a-z0-9-]+-\d+\.cos\.[a-z]+-[a-z]+(?:-\d+)?\.myqcloud\.com$/.test(url.hostname)) return void 0;
196
+ const response = await fetch(url, { redirect: "error", signal: AbortSignal.timeout(5e3) });
197
+ const mime = response.headers.get("content-type")?.split(";")[0].trim().toLowerCase();
198
+ if (!response.ok || !["image/png", "image/jpeg", "image/webp"].includes(mime ?? "")) {
199
+ await response.body?.cancel();
200
+ return void 0;
201
+ }
202
+ if (!response.body) return void 0;
203
+ const reader = response.body.getReader(), chunks = [];
204
+ let length = 0;
205
+ while (true) {
206
+ const { done, value } = await reader.read();
207
+ if (done) break;
208
+ length += value.length;
209
+ if (length > 20 * 1024 * 1024) {
210
+ await reader.cancel();
211
+ return void 0;
212
+ }
213
+ chunks.push(value);
214
+ }
215
+ const bytes = Buffer.concat(chunks);
216
+ const dimensions = (0, import_image_size.imageSize)(bytes);
217
+ const formats = { png: "image/png", jpg: "image/jpeg", webp: "image/webp" };
218
+ const detectedMime = formats[dimensions.type ?? ""];
219
+ if (!detectedMime || detectedMime !== mime || !dimensions.width || !dimensions.height || dimensions.width > 4096 || dimensions.height > 4096) return void 0;
220
+ return "data:" + detectedMime + ";base64," + bytes.toString("base64");
221
+ } catch {
222
+ return void 0;
223
+ }
224
+ }
225
+ __name(loadSkillArtwork, "loadSkillArtwork");
226
+
227
+ // src/plugin/skillCard.ts
228
+ var running = 0;
229
+ var waiting = [];
230
+ async function itemPaper() {
231
+ for (const base of ["../assets/item-card", "../../assets/item-card"]) {
232
+ try {
233
+ return "data:image/webp;base64," + (await import_promises.default.readFile(import_node_path.default.resolve(__dirname, base, "paper.webp"))).toString("base64");
234
+ } catch {
235
+ }
236
+ }
237
+ return void 0;
238
+ }
239
+ __name(itemPaper, "itemPaper");
240
+ var frames = /* @__PURE__ */ new Map();
241
+ async function frame(passive) {
242
+ const file = passive ? "card-trap.png" : "card-spell.png";
243
+ if (!frames.has(file)) frames.set(file, import_promises.default.readFile(import_node_path.default.resolve(__dirname, "../assets/skill-card", file)).catch(() => import_promises.default.readFile(import_node_path.default.resolve(__dirname, "../../assets/skill-card", file))).then((b) => "data:image/png;base64," + b.toString("base64")).catch((e) => {
244
+ frames.delete(file);
245
+ throw e;
246
+ }));
247
+ return frames.get(file);
248
+ }
249
+ __name(frame, "frame");
250
+ async function leaderboardHeader() {
251
+ for (const base of ["../assets/leaderboard", "../../assets/leaderboard"]) {
252
+ for (const [file, mime] of [["header.png", "image/png"], ["header.jpg", "image/jpeg"], ["header.webp", "image/webp"], ["header.svg", "image/svg+xml"]]) {
253
+ try {
254
+ return "data:" + mime + ";base64," + (await import_promises.default.readFile(import_node_path.default.resolve(__dirname, base, file))).toString("base64");
255
+ } catch (error) {
256
+ if (error.code !== "ENOENT") throw error;
257
+ }
258
+ }
259
+ }
260
+ return void 0;
261
+ }
262
+ __name(leaderboardHeader, "leaderboardHeader");
263
+ async function renderSkillCard(ctx, card, leaderboard, itemCard) {
264
+ if (!ctx.puppeteer) throw new Error("Puppeteer 未启用");
265
+ if (JSON.stringify(itemCard ?? card ?? leaderboard ?? {}).length > 24e3) throw new Error("技能卡片内容过长");
266
+ if (running >= 2) {
267
+ if (waiting.length >= 16) throw new Error("绘图繁忙");
268
+ await new Promise((resolve) => waiting.push(resolve));
269
+ } else running++;
270
+ let page;
271
+ let timeout;
272
+ let expired = false;
273
+ try {
274
+ const work = /* @__PURE__ */ __name(async () => {
275
+ const art = await loadSkillArtwork(itemCard?.artworkUrl ?? leaderboard?.backgroundUrl ?? card?.artworkUrl);
276
+ if (itemCard && !art) throw new Error("道具图片读取失败");
277
+ const html = itemCard ? itemCardHtml(itemCard, art, await itemPaper()) : leaderboard ? leaderboardHtml(leaderboard, await leaderboardHeader(), art) : skillCardHtml(card, await frame(card.passive), art);
278
+ page = await ctx.puppeteer.page();
279
+ if (expired) {
280
+ await page.close();
281
+ throw new Error("绘图超时");
282
+ }
283
+ await page.setViewport({ width: 760, height: 1107, deviceScaleFactor: 1 });
284
+ await page.setJavaScriptEnabled(false);
285
+ await page.setRequestInterception(true);
286
+ page.on("request", (req) => {
287
+ if (req.url().startsWith("data:") || req.url() === "about:blank") void req.continue();
288
+ else void req.abort();
289
+ });
290
+ await page.setContent(html, { waitUntil: "load", timeout: 1e4 });
291
+ await page.evaluate(layoutCard);
292
+ const target = await page.$("#capture");
293
+ if (!target) throw new Error("卡片元素缺失");
294
+ const bounds = await target.boundingBox();
295
+ if (!bounds || bounds.height > 1e4) throw new Error("卡片内容过长");
296
+ return Buffer.from(await target.screenshot({ type: "png" }));
297
+ }, "work");
298
+ return await Promise.race([work(), new Promise((_, reject) => {
299
+ timeout = setTimeout(() => {
300
+ expired = true;
301
+ reject(new Error("绘图超时"));
302
+ }, 15e3);
303
+ })]);
304
+ } finally {
305
+ if (timeout) clearTimeout(timeout);
306
+ try {
307
+ await page?.close();
308
+ } catch {
309
+ }
310
+ const next = waiting.shift();
311
+ if (next) next();
312
+ else running--;
313
+ }
314
+ }
315
+ __name(renderSkillCard, "renderSkillCard");
316
+
317
+ // src/plugin/sessions.ts
318
+ function sessionKey(userId, channelId) {
319
+ return `${userId}:${channelId}`;
320
+ }
321
+ __name(sessionKey, "sessionKey");
322
+ var Sessions = class {
323
+ static {
324
+ __name(this, "Sessions");
325
+ }
326
+ store = /* @__PURE__ */ new Map();
327
+ init(ctx) {
328
+ ctx.on("dispose", () => {
329
+ this.clear();
330
+ });
331
+ }
332
+ set(key, value) {
333
+ this.store.set(key, value);
334
+ }
335
+ get(key) {
336
+ return this.store.get(key);
337
+ }
338
+ clear() {
339
+ this.store.clear();
340
+ }
341
+ };
342
+ var sessions_default = new Sessions();
343
+
344
+ // src/plugin/serverHandel/handel_base.ts
345
+ var handel_base = class {
346
+ static {
347
+ __name(this, "handel_base");
348
+ }
349
+ ctx;
350
+ constructor(_data) {
351
+ }
352
+ set(ctx) {
353
+ this.ctx = ctx;
354
+ }
355
+ async send(data, content) {
356
+ const session = sessions_default.get(sessionKey(data.userId, data.channelId));
357
+ if (!session) {
358
+ this.ctx.logger.info("session not found", data.userId, data.channelId);
359
+ return;
360
+ }
361
+ await session.send(content);
362
+ }
363
+ async start(_data) {
364
+ }
365
+ };
366
+
367
+ // src/plugin/serverHandel/image.ts
368
+ var ImageHandler = class extends handel_base {
369
+ static {
370
+ __name(this, "ImageHandler");
371
+ }
372
+ async start(data) {
373
+ let content;
374
+ let rendered = false;
375
+ try {
376
+ if (!data.itemCard && !data.card && !data.leaderboard) throw new Error("缺少卡片数据");
377
+ content = import_koishi.h.image(await renderSkillCard(this.ctx, data.card, data.leaderboard, data.itemCard), "image/png").toString();
378
+ rendered = true;
379
+ } catch (error) {
380
+ this.ctx.logger.warn("卡片绘制失败,使用文字详情", error instanceof Error ? error.message : "unknown");
381
+ content = new AnalysisMsg().parse(data);
382
+ }
383
+ await this.send(data, content);
384
+ if (rendered && (data.card || data.itemCard)) await this.send(data, new AnalysisMsg().parse(data));
385
+ }
386
+ };
387
+
388
+ // src/plugin/serverHandel/text.ts
389
+ var handelr_text = class extends handel_base {
390
+ static {
391
+ __name(this, "handelr_text");
392
+ }
393
+ async start(data) {
394
+ const content = new AnalysisMsg().parse(data);
395
+ await this.send(data, content);
396
+ }
397
+ };
398
+
399
+ // src/plugin/messageQueue.ts
400
+ var handlers = {
401
+ ["text" /* text */]: handelr_text,
402
+ ["image" /* image */]: ImageHandler
403
+ };
404
+ var MessageQueue = class {
405
+ static {
406
+ __name(this, "MessageQueue");
407
+ }
408
+ tails = /* @__PURE__ */ new Map();
409
+ generation = 0;
410
+ init(ctx) {
411
+ ctx.on("dispose", () => this.clearQueue());
412
+ }
413
+ addToQueue(data, ctx) {
414
+ const key = JSON.stringify([data.botId, data.channelId, data.userId]);
415
+ const generation = this.generation;
416
+ const previous = this.tails.get(key) ?? Promise.resolve();
417
+ const next = previous.then(async () => {
418
+ if (generation !== this.generation) return;
419
+ const Handler = handlers[data.handleType];
420
+ if (!Handler) {
421
+ ctx.logger.warn("未知 handleType: " + data.handleType);
422
+ return;
423
+ }
424
+ const handler = new Handler(data);
425
+ handler.set(ctx);
426
+ await handler.start(data);
427
+ }).catch((error) => {
428
+ ctx.logger.error("消息处理失败", error);
429
+ }).finally(() => {
430
+ if (this.tails.get(key) === next) this.tails.delete(key);
431
+ });
432
+ this.tails.set(key, next);
433
+ return true;
434
+ }
435
+ clearQueue() {
436
+ this.generation++;
437
+ this.tails.clear();
438
+ }
439
+ };
440
+ var messageQueue = new MessageQueue();
441
+
442
+ // src/plugin/server.ts
443
+ var import_tsrpc = require("tsrpc");
444
+
445
+ // src/shared/bot/serviceProto.ts
446
+ var serviceProto = {
447
+ "version": 6,
448
+ "services": [
449
+ {
450
+ "id": 0,
451
+ "name": "Message",
452
+ "type": "msg"
453
+ },
454
+ {
455
+ "id": 1,
456
+ "name": "Message",
457
+ "type": "api",
458
+ "conf": {
459
+ "needLogin": false
460
+ }
461
+ },
462
+ {
463
+ "id": 2,
464
+ "name": "Ping",
465
+ "type": "api",
466
+ "conf": {
467
+ "needLogin": false
468
+ }
469
+ }
470
+ ],
471
+ "types": {
472
+ "MsgMessage/MsgMessage": {
473
+ "type": "Interface",
474
+ "extends": [
475
+ {
476
+ "id": 2,
477
+ "type": {
478
+ "type": "Reference",
479
+ "target": "../../../protocols/base/BaseMessage"
480
+ }
481
+ },
482
+ {
483
+ "id": 1,
484
+ "type": {
485
+ "type": "Reference",
486
+ "target": "messageFace/IMessage"
487
+ }
488
+ }
489
+ ],
490
+ "properties": [
491
+ {
492
+ "id": 0,
493
+ "name": "userId",
494
+ "type": {
495
+ "type": "String"
496
+ }
497
+ },
498
+ {
499
+ "id": 1,
500
+ "name": "channelId",
501
+ "type": {
502
+ "type": "String"
503
+ }
504
+ },
505
+ {
506
+ "id": 2,
507
+ "name": "botId",
508
+ "type": {
509
+ "type": "String"
510
+ }
511
+ }
512
+ ]
513
+ },
514
+ "../../../protocols/base/BaseMessage": {
515
+ "type": "Interface"
516
+ },
517
+ "messageFace/IMessage": {
518
+ "type": "Interface",
519
+ "properties": [
520
+ {
521
+ "id": 0,
522
+ "name": "handleType",
523
+ "type": {
524
+ "type": "Reference",
525
+ "target": "messageFace/MessageHandleType"
526
+ }
527
+ },
528
+ {
529
+ "id": 2,
530
+ "name": "card",
531
+ "type": {
532
+ "type": "Reference",
533
+ "target": "messageFace/SkillCardData"
534
+ },
535
+ "optional": true
536
+ },
537
+ {
538
+ "id": 4,
539
+ "name": "itemCard",
540
+ "type": {
541
+ "type": "Reference",
542
+ "target": "messageFace/ItemCardData"
543
+ },
544
+ "optional": true
545
+ },
546
+ {
547
+ "id": 3,
548
+ "name": "leaderboard",
549
+ "type": {
550
+ "type": "Reference",
551
+ "target": "messageFace/LeaderboardImageData"
552
+ },
553
+ "optional": true
554
+ },
555
+ {
556
+ "id": 1,
557
+ "name": "line",
558
+ "type": {
559
+ "type": "Array",
560
+ "elementType": {
561
+ "type": "Reference",
562
+ "target": "messageFace/IMessageItem"
563
+ }
564
+ }
565
+ }
566
+ ]
567
+ },
568
+ "messageFace/MessageHandleType": {
569
+ "type": "Enum",
570
+ "members": [
571
+ {
572
+ "id": 0,
573
+ "value": "text"
574
+ },
575
+ {
576
+ "id": 1,
577
+ "value": "image"
578
+ }
579
+ ]
580
+ },
581
+ "messageFace/SkillCardData": {
582
+ "type": "Interface",
583
+ "properties": [
584
+ {
585
+ "id": 13,
586
+ "name": "artworkUrl",
587
+ "type": {
588
+ "type": "String"
589
+ },
590
+ "optional": true
591
+ },
592
+ {
593
+ "id": 0,
594
+ "name": "name",
595
+ "type": {
596
+ "type": "String"
597
+ }
598
+ },
599
+ {
600
+ "id": 2,
601
+ "name": "quality",
602
+ "type": {
603
+ "type": "String"
604
+ }
605
+ },
606
+ {
607
+ "id": 3,
608
+ "name": "level",
609
+ "type": {
610
+ "type": "Number"
611
+ }
612
+ },
613
+ {
614
+ "id": 4,
615
+ "name": "maxLevel",
616
+ "type": {
617
+ "type": "Number"
618
+ }
619
+ },
620
+ {
621
+ "id": 5,
622
+ "name": "passive",
623
+ "type": {
624
+ "type": "Boolean"
625
+ }
626
+ },
627
+ {
628
+ "id": 6,
629
+ "name": "description",
630
+ "type": {
631
+ "type": "String"
632
+ }
633
+ },
634
+ {
635
+ "id": 7,
636
+ "name": "mechanism",
637
+ "type": {
638
+ "type": "String"
639
+ }
640
+ },
641
+ {
642
+ "id": 8,
643
+ "name": "cost",
644
+ "type": {
645
+ "type": "String"
646
+ }
647
+ },
648
+ {
649
+ "id": 9,
650
+ "name": "cooldown",
651
+ "type": {
652
+ "type": "String"
653
+ }
654
+ },
655
+ {
656
+ "id": 10,
657
+ "name": "tags",
658
+ "type": {
659
+ "type": "Array",
660
+ "elementType": {
661
+ "type": "String"
662
+ }
663
+ }
664
+ },
665
+ {
666
+ "id": 11,
667
+ "name": "sources",
668
+ "type": {
669
+ "type": "Array",
670
+ "elementType": {
671
+ "type": "String"
672
+ }
673
+ }
674
+ },
675
+ {
676
+ "id": 12,
677
+ "name": "note",
678
+ "type": {
679
+ "type": "String"
680
+ }
681
+ }
682
+ ]
683
+ },
684
+ "messageFace/ItemCardData": {
685
+ "type": "Interface",
686
+ "properties": [
687
+ {
688
+ "id": 0,
689
+ "name": "artworkUrl",
690
+ "type": {
691
+ "type": "String"
692
+ }
693
+ },
694
+ {
695
+ "id": 1,
696
+ "name": "name",
697
+ "type": {
698
+ "type": "String"
699
+ }
700
+ },
701
+ {
702
+ "id": 2,
703
+ "name": "quality",
704
+ "type": {
705
+ "type": "String"
706
+ }
707
+ },
708
+ {
709
+ "id": 3,
710
+ "name": "type",
711
+ "type": {
712
+ "type": "String"
713
+ }
714
+ },
715
+ {
716
+ "id": 4,
717
+ "name": "description",
718
+ "type": {
719
+ "type": "String"
720
+ }
721
+ },
722
+ {
723
+ "id": 5,
724
+ "name": "count",
725
+ "type": {
726
+ "type": "String"
727
+ }
728
+ },
729
+ {
730
+ "id": 6,
731
+ "name": "referencePrice",
732
+ "type": {
733
+ "type": "String"
734
+ }
735
+ }
736
+ ]
737
+ },
738
+ "messageFace/LeaderboardImageData": {
739
+ "type": "Interface",
740
+ "properties": [
741
+ {
742
+ "id": 7,
743
+ "name": "backgroundUrl",
744
+ "type": {
745
+ "type": "String"
746
+ },
747
+ "optional": true
748
+ },
749
+ {
750
+ "id": 0,
751
+ "name": "title",
752
+ "type": {
753
+ "type": "String"
754
+ }
755
+ },
756
+ {
757
+ "id": 1,
758
+ "name": "metric",
759
+ "type": {
760
+ "type": "String"
761
+ }
762
+ },
763
+ {
764
+ "id": 2,
765
+ "name": "schedule",
766
+ "type": {
767
+ "type": "String"
768
+ }
769
+ },
770
+ {
771
+ "id": 3,
772
+ "name": "updated",
773
+ "type": {
774
+ "type": "String"
775
+ }
776
+ },
777
+ {
778
+ "id": 4,
779
+ "name": "total",
780
+ "type": {
781
+ "type": "Number"
782
+ }
783
+ },
784
+ {
785
+ "id": 5,
786
+ "name": "rows",
787
+ "type": {
788
+ "type": "Array",
789
+ "elementType": {
790
+ "type": "Interface",
791
+ "properties": [
792
+ {
793
+ "id": 0,
794
+ "name": "rank",
795
+ "type": {
796
+ "type": "Number"
797
+ }
798
+ },
799
+ {
800
+ "id": 1,
801
+ "name": "name",
802
+ "type": {
803
+ "type": "String"
804
+ }
805
+ },
806
+ {
807
+ "id": 2,
808
+ "name": "emoji",
809
+ "type": {
810
+ "type": "String"
811
+ }
812
+ },
813
+ {
814
+ "id": 3,
815
+ "name": "value",
816
+ "type": {
817
+ "type": "Number"
818
+ }
819
+ }
820
+ ]
821
+ }
822
+ }
823
+ },
824
+ {
825
+ "id": 6,
826
+ "name": "mine",
827
+ "type": {
828
+ "type": "Interface",
829
+ "properties": [
830
+ {
831
+ "id": 0,
832
+ "name": "rank",
833
+ "type": {
834
+ "type": "Number"
835
+ }
836
+ },
837
+ {
838
+ "id": 1,
839
+ "name": "name",
840
+ "type": {
841
+ "type": "String"
842
+ }
843
+ },
844
+ {
845
+ "id": 2,
846
+ "name": "emoji",
847
+ "type": {
848
+ "type": "String"
849
+ }
850
+ },
851
+ {
852
+ "id": 3,
853
+ "name": "value",
854
+ "type": {
855
+ "type": "Number"
856
+ }
857
+ }
858
+ ]
859
+ },
860
+ "optional": true
861
+ }
862
+ ]
863
+ },
864
+ "messageFace/IMessageItem": {
865
+ "type": "Union",
866
+ "members": [
867
+ {
868
+ "id": 0,
869
+ "type": {
870
+ "type": "Reference",
871
+ "target": "messageFace/ITitleMessage"
872
+ }
873
+ },
874
+ {
875
+ "id": 1,
876
+ "type": {
877
+ "type": "Reference",
878
+ "target": "messageFace/ILineMessage"
879
+ }
880
+ },
881
+ {
882
+ "id": 2,
883
+ "type": {
884
+ "type": "Reference",
885
+ "target": "messageFace/IErrorMessage"
886
+ }
887
+ }
888
+ ]
889
+ },
890
+ "messageFace/ITitleMessage": {
891
+ "type": "Interface",
892
+ "properties": [
893
+ {
894
+ "id": 0,
895
+ "name": "type",
896
+ "type": {
897
+ "type": "Literal",
898
+ "literal": 0
899
+ }
900
+ },
901
+ {
902
+ "id": 1,
903
+ "name": "content",
904
+ "type": {
905
+ "type": "String"
906
+ }
907
+ }
908
+ ]
909
+ },
910
+ "messageFace/MessageType": {
911
+ "type": "Enum",
912
+ "members": [
913
+ {
914
+ "id": 0,
915
+ "value": 0
916
+ },
917
+ {
918
+ "id": 1,
919
+ "value": 1
920
+ },
921
+ {
922
+ "id": 2,
923
+ "value": 2
924
+ }
925
+ ]
926
+ },
927
+ "messageFace/ILineMessage": {
928
+ "type": "Interface",
929
+ "properties": [
930
+ {
931
+ "id": 0,
932
+ "name": "type",
933
+ "type": {
934
+ "type": "Literal",
935
+ "literal": 1
936
+ }
937
+ },
938
+ {
939
+ "id": 1,
940
+ "name": "content",
941
+ "type": {
942
+ "type": "String"
943
+ }
944
+ }
945
+ ]
946
+ },
947
+ "messageFace/IErrorMessage": {
948
+ "type": "Interface",
949
+ "properties": [
950
+ {
951
+ "id": 0,
952
+ "name": "type",
953
+ "type": {
954
+ "type": "Literal",
955
+ "literal": 2
956
+ }
957
+ },
958
+ {
959
+ "id": 1,
960
+ "name": "content",
961
+ "type": {
962
+ "type": "String"
963
+ }
964
+ }
965
+ ]
966
+ },
967
+ "PtlMessage/ReqMessage": {
968
+ "type": "Interface",
969
+ "extends": [
970
+ {
971
+ "id": 1,
972
+ "type": {
973
+ "type": "Reference",
974
+ "target": "../../../protocols/base/BaseRequest"
975
+ }
976
+ }
977
+ ],
978
+ "properties": [
979
+ {
980
+ "id": 0,
981
+ "name": "bot",
982
+ "type": {
983
+ "type": "Interface",
984
+ "properties": [
985
+ {
986
+ "id": 0,
987
+ "name": "id",
988
+ "type": {
989
+ "type": "String"
990
+ }
991
+ },
992
+ {
993
+ "id": 1,
994
+ "name": "platform",
995
+ "type": {
996
+ "type": "String"
997
+ }
998
+ }
999
+ ]
1000
+ }
1001
+ },
1002
+ {
1003
+ "id": 1,
1004
+ "name": "user",
1005
+ "type": {
1006
+ "type": "Interface",
1007
+ "properties": [
1008
+ {
1009
+ "id": 0,
1010
+ "name": "id",
1011
+ "type": {
1012
+ "type": "String"
1013
+ }
1014
+ }
1015
+ ]
1016
+ }
1017
+ },
1018
+ {
1019
+ "id": 2,
1020
+ "name": "channel",
1021
+ "type": {
1022
+ "type": "Interface",
1023
+ "properties": [
1024
+ {
1025
+ "id": 0,
1026
+ "name": "id",
1027
+ "type": {
1028
+ "type": "String"
1029
+ }
1030
+ }
1031
+ ]
1032
+ }
1033
+ },
1034
+ {
1035
+ "id": 3,
1036
+ "name": "content",
1037
+ "type": {
1038
+ "type": "String"
1039
+ }
1040
+ }
1041
+ ]
1042
+ },
1043
+ "../../../protocols/base/BaseRequest": {
1044
+ "type": "Interface"
1045
+ },
1046
+ "PtlMessage/ResMessage": {
1047
+ "type": "Interface",
1048
+ "extends": [
1049
+ {
1050
+ "id": 1,
1051
+ "type": {
1052
+ "type": "Reference",
1053
+ "target": "../../../protocols/base/BaseResponse"
1054
+ }
1055
+ }
1056
+ ]
1057
+ },
1058
+ "../../../protocols/base/BaseResponse": {
1059
+ "type": "Interface"
1060
+ },
1061
+ "PtlPing/ReqPing": {
1062
+ "type": "Interface",
1063
+ "extends": [
1064
+ {
1065
+ "id": 1,
1066
+ "type": {
1067
+ "type": "Reference",
1068
+ "target": "../../../protocols/base/BaseRequest"
1069
+ }
1070
+ }
1071
+ ]
1072
+ },
1073
+ "PtlPing/ResPing": {
1074
+ "type": "Interface",
1075
+ "extends": [
1076
+ {
1077
+ "id": 1,
1078
+ "type": {
1079
+ "type": "Reference",
1080
+ "target": "../../../protocols/base/BaseResponse"
1081
+ }
1082
+ }
1083
+ ],
1084
+ "properties": [
1085
+ {
1086
+ "id": 0,
1087
+ "name": "pong",
1088
+ "type": {
1089
+ "type": "Literal",
1090
+ "literal": true
1091
+ }
1092
+ },
1093
+ {
1094
+ "id": 1,
1095
+ "name": "time",
1096
+ "type": {
1097
+ "type": "Date"
1098
+ }
1099
+ }
1100
+ ]
1101
+ }
1102
+ }
1103
+ };
1104
+
1105
+ // src/plugin/server.ts
1106
+ var Server = class {
1107
+ static {
1108
+ __name(this, "Server");
1109
+ }
1110
+ wsClient;
1111
+ ctx;
1112
+ onConnectedCallback;
1113
+ messageListenerSetup = false;
1114
+ _init = false;
1115
+ async init(ctx, config) {
1116
+ this.ctx = ctx;
1117
+ ctx.on("dispose", () => {
1118
+ this.dispose();
1119
+ });
1120
+ if (this.wsClient) {
1121
+ await this.dispose();
1122
+ }
1123
+ const serverUrl = config.服务器地址;
1124
+ if (!serverUrl || serverUrl.trim() === "") {
1125
+ throw new Error("服务器地址不能为空");
1126
+ }
1127
+ this.setWsUrl(serverUrl).catch((error) => {
1128
+ this.ctx.logger.error("初始化连接失败:", error);
1129
+ });
1130
+ }
1131
+ onConnected(callback) {
1132
+ this.onConnectedCallback = callback;
1133
+ if (this._init && this.wsClient && !this.messageListenerSetup) {
1134
+ callback();
1135
+ this.messageListenerSetup = true;
1136
+ }
1137
+ }
1138
+ async dispose() {
1139
+ this._init = false;
1140
+ if (this.wsClient) {
1141
+ this.wsClient.unlistenMsgAll(/.*/);
1142
+ this.wsClient.disconnect();
1143
+ this.wsClient = null;
1144
+ }
1145
+ this.onConnectedCallback = void 0;
1146
+ this.messageListenerSetup = false;
1147
+ }
1148
+ listenMsg(msgName, handler) {
1149
+ if (!this._init || !this.wsClient) {
1150
+ this.ctx.logger.warn("WebSocket 未连接,无法监听消息");
1151
+ return;
1152
+ }
1153
+ return this.wsClient.listenMsg(msgName, handler);
1154
+ }
1155
+ async setWsUrl(link, maxRetries = 99999) {
1156
+ this._init = true;
1157
+ this.wsClient = new import_tsrpc.WsClient(serviceProto, { server: link, json: true });
1158
+ let retryCount = 0;
1159
+ const attemptConnect = /* @__PURE__ */ __name(async () => {
1160
+ const connect = await this.wsClient.connect();
1161
+ if (connect.isSucc) {
1162
+ this.wsClient.flows.postDisconnectFlow.push((event) => {
1163
+ if (!event.isManual && this._init) {
1164
+ this.ctx.logger.info("开始断线重连");
1165
+ this.reconnect();
1166
+ }
1167
+ return event;
1168
+ });
1169
+ this.ctx.logger.info("游戏服连接成功");
1170
+ if (this.onConnectedCallback && !this.messageListenerSetup) {
1171
+ this.onConnectedCallback();
1172
+ this.messageListenerSetup = true;
1173
+ }
1174
+ return true;
1175
+ }
1176
+ retryCount += 1;
1177
+ if (retryCount < maxRetries && this._init) {
1178
+ this.ctx.logger.warn(`连接失败,${retryCount}/${maxRetries},5秒后重试`);
1179
+ this.ctx.setTimeout(() => {
1180
+ void attemptConnect();
1181
+ }, 5e3);
1182
+ return false;
1183
+ }
1184
+ this._init = false;
1185
+ throw new Error(connect.errMsg);
1186
+ }, "attemptConnect");
1187
+ await attemptConnect();
1188
+ }
1189
+ async reconnect() {
1190
+ if (!this._init || !this.wsClient) {
1191
+ return;
1192
+ }
1193
+ const res = await this.wsClient.connect();
1194
+ if (!res.isSucc && this._init) {
1195
+ this.ctx.setTimeout(() => {
1196
+ void this.reconnect();
1197
+ }, 5e3);
1198
+ return;
1199
+ }
1200
+ if (res.isSucc) {
1201
+ this.ctx.logger.info("断线重连成功");
1202
+ }
1203
+ }
1204
+ async api(apiName, posData) {
1205
+ if (!this._init) {
1206
+ return;
1207
+ }
1208
+ const client = this.wsClient;
1209
+ const req = await client.callApi(apiName, posData);
1210
+ if (req.isSucc) {
1211
+ return req.res;
1212
+ }
1213
+ this.ctx.logger.warn("请求出错", apiName, req.err.message);
1214
+ }
1215
+ /** 缓存会话并把原始内容交给游戏服 **/
1216
+ uploadMessage(session) {
1217
+ const userId = session.userId;
1218
+ const channelId = session.channelId ?? session.userId;
1219
+ if (!userId || !channelId) {
1220
+ this.ctx.logger.warn("消息缺少 userId 或 channelId,已忽略");
1221
+ return;
1222
+ }
1223
+ sessions_default.set(sessionKey(userId, channelId), session);
1224
+ this.api("Message", {
1225
+ bot: {
1226
+ id: session.bot.userId,
1227
+ platform: session.bot.platform
1228
+ },
1229
+ user: {
1230
+ id: userId
1231
+ },
1232
+ channel: {
1233
+ id: channelId
1234
+ },
1235
+ content: session.content ?? ""
1236
+ }).catch((error) => {
1237
+ this.ctx.logger.error("发送消息到服务器失败:", error);
1238
+ });
1239
+ }
1240
+ };
1241
+ var server_default = new Server();
1242
+
1243
+ // src/inits.ts
1244
+ function apply(ctx, config) {
1245
+ messageQueue.init(ctx);
1246
+ sessions_default.init(ctx);
1247
+ server_default.init(ctx, config);
1248
+ server_default.onConnected(() => {
1249
+ server_default.listenMsg("Message", (data) => {
1250
+ messageQueue.addToQueue(data, ctx);
1251
+ });
1252
+ });
1253
+ ctx.on("message", (session) => {
1254
+ if (session.userId === session.selfId) {
1255
+ return;
1256
+ }
1257
+ server_default.uploadMessage(session);
1258
+ });
1259
+ }
1260
+ __name(apply, "apply");
1261
+
1262
+ // src/index.ts
1263
+ var inject = { optional: ["puppeteer"] };
1264
+ var name = "dew-bot";
1265
+ var Config = import_koishi2.Schema.object({
1266
+ 服务器地址: import_koishi2.Schema.string().default("ws://127.0.0.1:3021").description("游戏服 WebSocket 地址")
1267
+ });
1268
+ function apply2(ctx, config) {
1269
+ ctx.plugin(apply, config);
1270
+ }
1271
+ __name(apply2, "apply");
1272
+ // Annotate the CommonJS export names for ESM import in node:
1273
+ 0 && (module.exports = {
1274
+ Config,
1275
+ apply,
1276
+ inject,
1277
+ name
1278
+ });