koishi-plugin-rocom 1.0.18 → 1.0.24
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/announcement-service.d.ts +21 -0
- package/lib/announcement-service.js +63 -0
- package/lib/async-control.d.ts +3 -0
- package/lib/async-control.js +48 -0
- package/lib/atlas-service.js +1 -1
- package/lib/client.d.ts +58 -7
- package/lib/client.js +282 -127
- package/lib/commands/egg.js +66 -4
- package/lib/commands/merchant.d.ts +105 -0
- package/lib/commands/merchant.js +600 -182
- package/lib/commands/query.d.ts +18 -0
- package/lib/commands/query.js +585 -145
- package/lib/commands/ranking.d.ts +2 -0
- package/lib/commands/ranking.js +31 -0
- package/lib/commands/share-code.d.ts +2 -0
- package/lib/commands/share-code.js +111 -0
- package/lib/commands/tools.js +48 -60
- package/lib/commands/wiki.js +1 -1
- package/lib/egg-service.d.ts +82 -8
- package/lib/egg-service.js +235 -19
- package/lib/element-colors.d.ts +3 -0
- package/lib/element-colors.js +34 -0
- package/lib/icon-metrics.d.ts +32 -0
- package/lib/icon-metrics.js +255 -0
- package/lib/img//345/274/202/350/211/262.png +0 -0
- package/lib/img//347/202/253/345/275/251.png +0 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +11857 -175
- package/lib/merchant-catalog.d.ts +47 -0
- package/lib/merchant-catalog.js +193 -0
- package/lib/merchant-clock.d.ts +22 -0
- package/lib/merchant-clock.js +95 -0
- package/lib/merchant-price-log.d.ts +63 -0
- package/lib/merchant-price-log.js +187 -0
- package/lib/merchant-service.d.ts +38 -0
- package/lib/merchant-service.js +216 -0
- package/lib/permissions.d.ts +16 -0
- package/lib/permissions.js +66 -0
- package/lib/pet-data-service.d.ts +13 -0
- package/lib/pet-data-service.js +117 -10
- package/lib/pet-size.d.ts +13 -0
- package/lib/pet-size.js +54 -0
- package/lib/player-service.d.ts +37 -0
- package/lib/player-service.js +201 -0
- package/lib/ranking-service.d.ts +46 -0
- package/lib/ranking-service.js +137 -0
- package/lib/render-templates/announcement/detail.html +8 -0
- package/lib/render-templates/announcement/list.html +5 -0
- package/lib/render-templates/announcement/style.css +1 -0
- package/lib/render-templates/home/style.css +15 -14
- package/lib/render-templates/home-pets/index.html +80 -0
- package/lib/render-templates/home-pets/style.css +338 -0
- package/lib/render-templates/pet-detail-classic/index.html +151 -0
- package/lib/render-templates/pet-detail-classic/style.css +503 -0
- package/lib/render-templates/pet-detail-classic/texture2D/a_title.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/bg.jpg +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/footer.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/icon.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/img_head.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/jinhua_bg.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/level_icon.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/line.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/mask_bar.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/pet_bg.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/pet_rocom.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/pet_rocom_bg.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/poro_bar.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/right_jinhua.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/skill_bg.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/skill_mask.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/star.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/star_1.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/star_8.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/star_9.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/table.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/tags.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/title.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/top_bg.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/xuancai_overlay.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/yise_overlay.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D/ys_bar.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/10.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/11.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/12.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/13.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/14.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/15.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/16.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/17.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/18.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/19.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/2.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/20.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/23.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/3.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/4.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/5.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/6.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/8.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247/9.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//345/205/211.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//345/206/260.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//345/234/260.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//345/271/273.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//345/271/275.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//346/201/266.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//346/227/240.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//346/231/256/351/200/232.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//346/234/272/346/242/260.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//346/255/246.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//346/257/222.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//346/260/264.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//347/201/253.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//347/224/265.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//347/277/274.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//350/215/211.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//350/220/214.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//350/231/253.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//345/261/236/346/200/247//351/276/231.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/1.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/10.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/11.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/12.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/13.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/14.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/15.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/16.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/17.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/18.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/19.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/2.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/21.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/23.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/24.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/3.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/4.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/5.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/6.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/7.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/8.png +0 -0
- package/lib/render-templates/pet-detail-classic/texture2D//350/241/200/350/204/211/9.png +0 -0
- package/lib/render-templates/pet-ranking/index.html +99 -0
- package/lib/render-templates/pet-ranking/style.css +338 -0
- package/lib/render-templates/player-search/index.html +7 -0
- package/lib/render-templates/searcheggs/index.html +1 -1
- package/lib/render-templates/searcheggs/size.html +70 -68
- package/lib/render-templates/share-code-classic/assets/eit-logo.png +0 -0
- package/lib/render-templates/share-code-classic/assets/img_xingxingdi.png +0 -0
- package/lib/render-templates/share-code-classic/assets/roco_icon.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/255/227/344/275/223/Rocofontblack-Regular .ttf +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//345/205/211.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//345/206/260.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//345/234/260.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//345/271/273.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//345/271/275.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//346/201/266.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//346/227/240.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//346/231/256/351/200/232.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//346/234/272/346/242/260.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//346/255/246.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//346/257/222.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//346/260/264.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//347/201/253.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//347/224/265.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//347/277/274.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//350/215/211.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//350/220/214.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//350/231/253.png +0 -0
- package/lib/render-templates/share-code-classic/assets//345/256/240/347/211/251/345/261/236/346/200/247//351/276/231.png +0 -0
- package/lib/render-templates/share-code-classic/assets//347/201/253/346/274/206/345/215/260.png +0 -0
- package/lib/render-templates/share-code-classic/assets//347/253/213/347/273/230/350/203/214/346/231/257/346/241/206.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//345/205/211.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//345/206/260.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//345/234/260.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//345/245/207/345/274/202.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//345/271/273.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//345/271/275.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//346/201/266.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//346/231/256/351/200/232.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//346/234/272/346/242/260.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//346/255/246.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//346/257/222.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//346/260/264.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//346/261/241/346/237/223.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//347/201/253.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//347/224/265.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//347/277/274.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//350/215/211.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//350/220/214.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//350/231/253.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//351/246/226/351/242/206.png +0 -0
- package/lib/render-templates/share-code-classic/assets//350/241/200/350/204/211//351/276/231.png +0 -0
- package/lib/render-templates/share-code-classic/index.html +119 -0
- package/lib/render-templates/share-code-classic/style.css +646 -0
- package/lib/render-templates/share-code-team/index.html +105 -0
- package/lib/render-templates/share-code-team/style.css +345 -0
- package/lib/render-templates/yuanxing-shangren/merchant.html +479 -461
- package/lib/render-templates/yuanxing-shangren/today.html +407 -461
- package/lib/render.d.ts +18 -2
- package/lib/render.js +138 -39
- package/lib/send-image.d.ts +1 -1
- package/lib/send-image.js +22 -1
- package/lib/share-code-service.d.ts +68 -0
- package/lib/share-code-service.js +257 -0
- package/lib/subscription-runner.d.ts +6 -0
- package/lib/subscription-runner.js +21 -0
- package/lib/subscription-send.d.ts +4 -2
- package/lib/subscription-send.js +45 -20
- package/lib/ttf/rocom_origin.ttf +0 -0
- package/lib/types.d.ts +14 -1
- package/lib/user.d.ts +11 -0
- package/lib/wiki-catalog.js +1 -1
- package/lib/wiki-service.js +1 -1
- package/package.json +5 -1
- package/readme.md +125 -124
- package/lib/ttf/rocom_skill_origin.ttf +0 -0
package/lib/commands/query.js
CHANGED
|
@@ -3,69 +3,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.extractHomeEggStatus = extractHomeEggStatus;
|
|
6
7
|
exports.register = register;
|
|
7
8
|
const koishi_1 = require("koishi");
|
|
8
9
|
const account_1 = require("./account");
|
|
9
10
|
const send_image_1 = require("../send-image");
|
|
10
11
|
const subscription_send_1 = require("../subscription-send");
|
|
11
12
|
const pet_data_service_1 = require("../pet-data-service");
|
|
13
|
+
const player_service_1 = require("../player-service");
|
|
14
|
+
const merchant_service_1 = require("../merchant-service");
|
|
15
|
+
const permissions_1 = require("../permissions");
|
|
16
|
+
const render_1 = require("../render");
|
|
17
|
+
const subscription_runner_1 = require("../subscription-runner");
|
|
12
18
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
13
19
|
const node_path_1 = __importDefault(require("node:path"));
|
|
14
20
|
const logger = new koishi_1.Logger('rocom-query');
|
|
15
|
-
async function sendImage(deps, session, templateName, data, fallback) {
|
|
16
|
-
const png = await deps.renderer.
|
|
21
|
+
async function sendImage(deps, session, templateName, data, fallback, options) {
|
|
22
|
+
const png = await deps.renderer.renderPages(deps.ctx, templateName, data, options);
|
|
17
23
|
await (0, send_image_1.sendImageWithFallback)(session, png, fallback, `query:${templateName}`, deps.config);
|
|
18
24
|
}
|
|
19
|
-
function cleanPlayerFieldValue(field, value) {
|
|
20
|
-
const text = String(value ?? '').trim().replace(/^'+|'+$/g, '');
|
|
21
|
-
if (!text || ['<0B>', '<0b>', '<0B >', '<0b >'].includes(text))
|
|
22
|
-
return '未设置';
|
|
23
|
-
if (['is_online', 'online', 'chat_top_unlock', 'is_friend', 'is_black', 'is_black_role', 'is_chat_node_unlock'].includes(field)) {
|
|
24
|
-
return ['1', 'true', 'True', '是'].includes(text) ? '是' : '否';
|
|
25
|
-
}
|
|
26
|
-
if (['sex', 'gender'].includes(field)) {
|
|
27
|
-
return { '0': '未知', '1': '男', '2': '女' }[text] || text;
|
|
28
|
-
}
|
|
29
|
-
if (field === 'friend_type') {
|
|
30
|
-
return { '0': '默认', '1': '特殊' }[text] || text;
|
|
31
|
-
}
|
|
32
|
-
if (field === 'battle_state') {
|
|
33
|
-
return { '0': '空闲', '1': '对战中' }[text] || text;
|
|
34
|
-
}
|
|
35
|
-
return text;
|
|
36
|
-
}
|
|
37
|
-
function parseIngamePlayerPayload(payload, uid) {
|
|
38
|
-
const rows = payload?.rows || [];
|
|
39
|
-
const rowMap = {};
|
|
40
|
-
const labelMap = {};
|
|
41
|
-
for (const row of rows) {
|
|
42
|
-
const field = String(row.field || '');
|
|
43
|
-
if (!field)
|
|
44
|
-
continue;
|
|
45
|
-
rowMap[field] = String(row.value ?? '');
|
|
46
|
-
labelMap[field] = String(row.label || field);
|
|
47
|
-
}
|
|
48
|
-
const playerUid = cleanPlayerFieldValue('uin', rowMap.uin || uid);
|
|
49
|
-
const signature = cleanPlayerFieldValue('signature', rowMap.signature || '');
|
|
50
|
-
return {
|
|
51
|
-
title: String(payload?.title || '玩家搜索'),
|
|
52
|
-
nickname: cleanPlayerFieldValue('name', rowMap.name || '-'),
|
|
53
|
-
uid: playerUid,
|
|
54
|
-
level: cleanPlayerFieldValue('level', rowMap.level || '-'),
|
|
55
|
-
signature: signature === '未设置' ? '' : signature,
|
|
56
|
-
rowMap,
|
|
57
|
-
labelMap,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
function playerField(parsed, field, defaultValue = '未设置') {
|
|
61
|
-
if (!parsed)
|
|
62
|
-
return defaultValue;
|
|
63
|
-
const raw = parsed.rowMap[field];
|
|
64
|
-
if (raw == null || raw === '')
|
|
65
|
-
return defaultValue;
|
|
66
|
-
const value = cleanPlayerFieldValue(field, raw);
|
|
67
|
-
return value && value !== '-' && value !== '未设置' ? value : defaultValue;
|
|
68
|
-
}
|
|
69
25
|
function tryParseJson(text) {
|
|
70
26
|
try {
|
|
71
27
|
return JSON.parse(text);
|
|
@@ -876,7 +832,7 @@ function extractHomePet(deps, raw, index, guard = false) {
|
|
|
876
832
|
const feedRound = Number(homePet.feed_round || raw.feed_round || 0) || 0;
|
|
877
833
|
const gender = Number(display.gender || raw.gender || 0) || 0;
|
|
878
834
|
let mutationType = Number(display.mutation_type || raw.mutation_type || homePet.mutation_type || 0) || 0;
|
|
879
|
-
//
|
|
835
|
+
// mutation_type 缺失时按 real_speciality_ids 识别变体(103=异色、502=炫彩、两者兼有=异色炫彩)。
|
|
880
836
|
if (!mutationType) {
|
|
881
837
|
const specialityValues = [];
|
|
882
838
|
for (const value of [homePet.real_speciality_ids, raw.real_speciality_ids, homePet.speciality_id, raw.speciality_id]) {
|
|
@@ -1112,8 +1068,8 @@ function buildHomeRenderData(deps, res, uid) {
|
|
|
1112
1068
|
updatedAt: new Date(createdAt ? createdAt * 1000 : Date.now()).toLocaleString('zh-CN'),
|
|
1113
1069
|
};
|
|
1114
1070
|
}
|
|
1115
|
-
function buildPlayerSearchRenderData(payload, uid) {
|
|
1116
|
-
const parsed = parseIngamePlayerPayload(payload, uid);
|
|
1071
|
+
function buildPlayerSearchRenderData(payload, uid, cardImageUrl = '') {
|
|
1072
|
+
const parsed = (0, player_service_1.parseIngamePlayerPayload)(payload, uid);
|
|
1117
1073
|
const pack = (title, pairs) => {
|
|
1118
1074
|
const items = pairs
|
|
1119
1075
|
.filter(([, value]) => value && value !== '-' && value !== '未设置')
|
|
@@ -1123,27 +1079,27 @@ function buildPlayerSearchRenderData(payload, uid) {
|
|
|
1123
1079
|
const sections = [
|
|
1124
1080
|
pack('核心档案', [
|
|
1125
1081
|
['等级', parsed.level],
|
|
1126
|
-
['在线状态', playerField(parsed, 'online', playerField(parsed, 'is_online'))],
|
|
1127
|
-
['性别', playerField(parsed, 'gender', playerField(parsed, 'sex'))],
|
|
1128
|
-
['世界等级', playerField(parsed, 'world_level')],
|
|
1129
|
-
['图鉴收集', playerField(parsed, 'card_handbook_collect_num')],
|
|
1130
|
-
['最后离线', playerField(parsed, 'last_logout_time')],
|
|
1082
|
+
['在线状态', (0, player_service_1.playerField)(parsed, 'online', (0, player_service_1.playerField)(parsed, 'is_online'))],
|
|
1083
|
+
['性别', (0, player_service_1.playerField)(parsed, 'gender', (0, player_service_1.playerField)(parsed, 'sex'))],
|
|
1084
|
+
['世界等级', (0, player_service_1.playerField)(parsed, 'world_level')],
|
|
1085
|
+
['图鉴收集', (0, player_service_1.playerField)(parsed, 'card_handbook_collect_num')],
|
|
1086
|
+
['最后离线', (0, player_service_1.playerField)(parsed, 'last_logout_time')],
|
|
1131
1087
|
]),
|
|
1132
1088
|
pack('家园信息', [
|
|
1133
|
-
['家园名称', playerField(parsed, 'home_name')],
|
|
1134
|
-
['家园等级', playerField(parsed, 'home_level')],
|
|
1135
|
-
['家园经验', playerField(parsed, 'home_experience')],
|
|
1136
|
-
['舒适度', playerField(parsed, 'home_comfort_level')],
|
|
1137
|
-
['访客数量', playerField(parsed, 'visitor_num')],
|
|
1089
|
+
['家园名称', (0, player_service_1.playerField)(parsed, 'home_name')],
|
|
1090
|
+
['家园等级', (0, player_service_1.playerField)(parsed, 'home_level')],
|
|
1091
|
+
['家园经验', (0, player_service_1.playerField)(parsed, 'home_experience')],
|
|
1092
|
+
['舒适度', (0, player_service_1.playerField)(parsed, 'home_comfort_level')],
|
|
1093
|
+
['访客数量', (0, player_service_1.playerField)(parsed, 'visitor_num')],
|
|
1138
1094
|
]),
|
|
1139
1095
|
].filter(Boolean);
|
|
1140
1096
|
const summaryCards = [
|
|
1141
1097
|
{ label: '等级', value: parsed.level },
|
|
1142
|
-
{ label: '在线状态', value: playerField(parsed, 'online', playerField(parsed, 'is_online')) },
|
|
1143
|
-
{ label: '世界等级', value: playerField(parsed, 'world_level') },
|
|
1144
|
-
{ label: '图鉴收集', value: playerField(parsed, 'card_handbook_collect_num') },
|
|
1145
|
-
{ label: '家园等级', value: playerField(parsed, 'home_level') },
|
|
1146
|
-
{ label: '舒适度', value: playerField(parsed, 'home_comfort_level') },
|
|
1098
|
+
{ label: '在线状态', value: (0, player_service_1.playerField)(parsed, 'online', (0, player_service_1.playerField)(parsed, 'is_online')) },
|
|
1099
|
+
{ label: '世界等级', value: (0, player_service_1.playerField)(parsed, 'world_level') },
|
|
1100
|
+
{ label: '图鉴收集', value: (0, player_service_1.playerField)(parsed, 'card_handbook_collect_num') },
|
|
1101
|
+
{ label: '家园等级', value: (0, player_service_1.playerField)(parsed, 'home_level') },
|
|
1102
|
+
{ label: '舒适度', value: (0, player_service_1.playerField)(parsed, 'home_comfort_level') },
|
|
1147
1103
|
].filter(item => item.value && item.value !== '-');
|
|
1148
1104
|
const signature = parsed.signature && parsed.signature !== '未设置' ? parsed.signature : '';
|
|
1149
1105
|
return {
|
|
@@ -1155,15 +1111,38 @@ function buildPlayerSearchRenderData(payload, uid) {
|
|
|
1155
1111
|
signature,
|
|
1156
1112
|
showSignature: Boolean(signature),
|
|
1157
1113
|
sections,
|
|
1158
|
-
|
|
1114
|
+
cardImageUrl: cardImageUrl || '',
|
|
1115
|
+
collectedShining: (0, player_service_1.playerField)(parsed, 'collected_shining_pet_count', '未知'),
|
|
1116
|
+
collectedGlass: (0, player_service_1.playerField)(parsed, 'collected_glass_pet_count', '未知'),
|
|
1117
|
+
commandHint: '洛克.玩家 [UID]',
|
|
1159
1118
|
copyright: 'Koishi & WeGame Locke Kingdom Plugin',
|
|
1160
1119
|
};
|
|
1161
1120
|
}
|
|
1162
|
-
function buildShopRenderData(payload, shopId) {
|
|
1121
|
+
function buildShopRenderData(payload, shopId, options = {}) {
|
|
1163
1122
|
const sections = [];
|
|
1164
1123
|
const detailItems = [];
|
|
1165
1124
|
const summaryCards = [{ label: '商店 ID', value: shopId }];
|
|
1166
|
-
|
|
1125
|
+
const shop = payload?.shop || {};
|
|
1126
|
+
if (Array.isArray(payload?.goods)) {
|
|
1127
|
+
const items = (0, merchant_service_1.normalizeLiveMerchant)(payload, Date.now(), { assetBaseUrl: options.assetBaseUrl });
|
|
1128
|
+
summaryCards.push({ label: '商品数量', value: String(items.length) });
|
|
1129
|
+
const shopName = String(shop.name || shop.title || '').trim();
|
|
1130
|
+
if (shopName)
|
|
1131
|
+
summaryCards.push({ label: '商店名称', value: shopName });
|
|
1132
|
+
sections.push({
|
|
1133
|
+
title: '商品列表',
|
|
1134
|
+
cards: items.map((item) => ({
|
|
1135
|
+
title: item.name,
|
|
1136
|
+
image: item.icon,
|
|
1137
|
+
meta: [
|
|
1138
|
+
item.price !== null ? { label: '价格', value: String(item.price) } : null,
|
|
1139
|
+
item.limit !== null ? { label: '限购', value: String(item.limit) } : null,
|
|
1140
|
+
item.active ? null : { label: '状态', value: '非在售' },
|
|
1141
|
+
].filter(Boolean),
|
|
1142
|
+
})),
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
else if (Array.isArray(payload?.rows)) {
|
|
1167
1146
|
detailItems.push(...payload.rows.filter((row) => Number(row.level || 0) === 0).map((row) => ({
|
|
1168
1147
|
label: row.label || row.field || '-',
|
|
1169
1148
|
value: stringifyInspectValue(row.value),
|
|
@@ -1171,6 +1150,8 @@ function buildShopRenderData(payload, shopId) {
|
|
|
1171
1150
|
}
|
|
1172
1151
|
else {
|
|
1173
1152
|
for (const [key, value] of Object.entries(payload || {})) {
|
|
1153
|
+
if (['_source', 'goods', 'shop', 'meta', '_goods_mapping', 'goods_mapping'].includes(key))
|
|
1154
|
+
continue;
|
|
1174
1155
|
if (Array.isArray(value)) {
|
|
1175
1156
|
summaryCards.push({ label: key, value: String(value.length) });
|
|
1176
1157
|
sections.push({
|
|
@@ -1194,12 +1175,12 @@ function buildShopRenderData(payload, shopId) {
|
|
|
1194
1175
|
title: '洛克商店',
|
|
1195
1176
|
subtitle: `shop_id = ${shopId}`,
|
|
1196
1177
|
heroTitle: '商店查询',
|
|
1197
|
-
heroValue: detailItems.find(item => ['name', 'title', '名称', '标题'].includes(item.label))?.value || shopId,
|
|
1178
|
+
heroValue: String(shop.name || shop.title || '') || detailItems.find(item => ['name', 'title', '名称', '标题'].includes(item.label))?.value || shopId,
|
|
1198
1179
|
heroSubvalue: `shop_id = ${shopId}`,
|
|
1199
1180
|
summaryCards: summaryCards.slice(0, 3),
|
|
1200
1181
|
sections,
|
|
1201
1182
|
detailItems: detailItems.slice(0, 18),
|
|
1202
|
-
commandHint: '洛克.商店
|
|
1183
|
+
commandHint: '洛克.商店 [shop_id]',
|
|
1203
1184
|
copyright: 'Koishi & WeGame Locke Kingdom Plugin',
|
|
1204
1185
|
};
|
|
1205
1186
|
}
|
|
@@ -1274,7 +1255,7 @@ function sessionTarget(session) {
|
|
|
1274
1255
|
return {
|
|
1275
1256
|
platform: session?.platform || session?.bot?.platform || '',
|
|
1276
1257
|
channelId: session?.channelId || session?.guildId || '',
|
|
1277
|
-
userId: session
|
|
1258
|
+
userId: (0, permissions_1.isDirectSession)(session) ? (session?.userId || '') : '',
|
|
1278
1259
|
};
|
|
1279
1260
|
}
|
|
1280
1261
|
function homeSubscriptionKey(session, uid, kind) {
|
|
@@ -1284,6 +1265,9 @@ function homeSubscriptionKey(session, uid, kind) {
|
|
|
1284
1265
|
function isBotAdmin(session, adminUserIds) {
|
|
1285
1266
|
return adminUserIds.includes(session?.userId || '');
|
|
1286
1267
|
}
|
|
1268
|
+
function canManageGroupSubscription(deps, session) {
|
|
1269
|
+
return (0, permissions_1.canManageSubscription)(deps.config, session);
|
|
1270
|
+
}
|
|
1287
1271
|
async function resolveHomeUid(deps, session, uid = '') {
|
|
1288
1272
|
const targetUid = String(uid || '').trim();
|
|
1289
1273
|
if (targetUid)
|
|
@@ -1310,27 +1294,297 @@ const HOME_SUB_TEXT = {
|
|
|
1310
1294
|
needUidHint: '请提供玩家 UID,或先完成绑定后再订阅家园生蛋。',
|
|
1311
1295
|
},
|
|
1312
1296
|
};
|
|
1313
|
-
async function subscribeHome(deps, session, uid, kind) {
|
|
1297
|
+
async function subscribeHome(deps, session, uid, kind, mentionAll = null) {
|
|
1314
1298
|
const target = sessionTarget(session);
|
|
1315
|
-
if (!target.userId && !
|
|
1316
|
-
return '
|
|
1299
|
+
if (!target.userId && !canManageGroupSubscription(deps, session))
|
|
1300
|
+
return '此指令仅限群管理员或机器人管理员使用。';
|
|
1317
1301
|
const targetUid = await resolveHomeUid(deps, session, uid);
|
|
1318
1302
|
if (!targetUid)
|
|
1319
1303
|
return HOME_SUB_TEXT[kind].needUidHint;
|
|
1320
1304
|
const key = homeSubscriptionKey(session, targetUid, kind);
|
|
1305
|
+
const own = deps.userMgr.getUserBindings(session?.userId || '').find(binding => binding.role_id === targetUid);
|
|
1306
|
+
const existing = deps.homeSubMgr.getAll()[key];
|
|
1321
1307
|
deps.homeSubMgr.upsert(key, {
|
|
1322
1308
|
key,
|
|
1323
1309
|
kind,
|
|
1324
1310
|
uid: targetUid,
|
|
1311
|
+
notify_user_id: own ? session.userId : '',
|
|
1312
|
+
nickname: own?.nickname || '',
|
|
1325
1313
|
platform: target.platform,
|
|
1314
|
+
self_id: session?.selfId || session?.bot?.selfId || '',
|
|
1326
1315
|
channel_id: target.channelId,
|
|
1327
1316
|
guild_id: session?.guildId || '',
|
|
1328
1317
|
user_id: target.userId,
|
|
1329
1318
|
updated_by: session?.userId || '',
|
|
1330
|
-
|
|
1319
|
+
// 群订阅支持命中后 @全体;未显式指定时沿用上次设置。
|
|
1320
|
+
mention_all: target.userId ? false : (mentionAll ?? existing?.mention_all ?? false),
|
|
1321
|
+
notify_state: existing?.notify_state || {},
|
|
1331
1322
|
updated_at: Math.floor(Date.now() / 1000),
|
|
1332
1323
|
});
|
|
1333
|
-
|
|
1324
|
+
const finalMentionAll = target.userId ? false : (mentionAll ?? existing?.mention_all ?? false);
|
|
1325
|
+
const mentionHint = target.userId ? '' : (finalMentionAll ? '命中后会尝试 @全体。' : '命中后不会 @全体。');
|
|
1326
|
+
return [`已订阅 UID ${targetUid} ${HOME_SUB_TEXT[kind].subscribedHint}`, mentionHint].filter(Boolean).join('');
|
|
1327
|
+
}
|
|
1328
|
+
// 订阅家园 的 @全体 写法与 UID 解析。
|
|
1329
|
+
const HOME_MENTION_ALL_ALIASES = new Set(['@全体', '全体', '@所有人', 'at全体', 'at所有人']);
|
|
1330
|
+
function parseHomeSubscribeArgs(args) {
|
|
1331
|
+
const tokens = String(args || '').split(/\s+/).filter(Boolean);
|
|
1332
|
+
let mentionAll = null;
|
|
1333
|
+
const uids = [];
|
|
1334
|
+
for (const token of tokens) {
|
|
1335
|
+
if (HOME_MENTION_ALL_ALIASES.has(token.toLowerCase())) {
|
|
1336
|
+
mentionAll = true;
|
|
1337
|
+
continue;
|
|
1338
|
+
}
|
|
1339
|
+
uids.push(token);
|
|
1340
|
+
}
|
|
1341
|
+
return { mentionAll, uid: uids[0] || '' };
|
|
1342
|
+
}
|
|
1343
|
+
function pickEggStatusPayload(payload) {
|
|
1344
|
+
const candidates = [payload?.data, payload?.result, payload?.data?.data, payload?.result?.data, payload];
|
|
1345
|
+
for (const candidate of candidates) {
|
|
1346
|
+
if (candidate && typeof candidate === 'object' && !Array.isArray(candidate))
|
|
1347
|
+
return candidate;
|
|
1348
|
+
}
|
|
1349
|
+
return {};
|
|
1350
|
+
}
|
|
1351
|
+
function extractHomeEggPet(item, nowTs) {
|
|
1352
|
+
const petInfo = item?.home_pet_info && typeof item.home_pet_info === 'object' ? item.home_pet_info : item;
|
|
1353
|
+
const petId = petInfo?.pet_cfg_id || petInfo?.pet_id || item?.pet_cfg_id || item?.pet_id;
|
|
1354
|
+
const name = String(petInfo?.name || petInfo?.pet_name || item?.name || item?.pet_name || '').trim();
|
|
1355
|
+
if (!Number(petId) && !name)
|
|
1356
|
+
return null;
|
|
1357
|
+
const hasEgg = Boolean(item?.have_egg ?? petInfo?.have_egg);
|
|
1358
|
+
const predictedEggTime = normalizeEpochSeconds(item?.predicted_egg_time ?? petInfo?.predicted_egg_time ?? item?.egg_ready_time);
|
|
1359
|
+
const ready = hasEgg || (predictedEggTime > 0 && nowTs >= predictedEggTime);
|
|
1360
|
+
const remaining = ready ? '' : (predictedEggTime > 0 ? formatEggRemaining(predictedEggTime, nowTs) : '未知');
|
|
1361
|
+
return {
|
|
1362
|
+
petId: String(petId || ''),
|
|
1363
|
+
name: name || `精灵 ${petId || ''}`,
|
|
1364
|
+
ready,
|
|
1365
|
+
remaining,
|
|
1366
|
+
predictedEggTime,
|
|
1367
|
+
hasEgg,
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
/**
|
|
1371
|
+
* 从 home/eggs 轻量接口响应中提取蛋状态。
|
|
1372
|
+
* 接口仍在开发中,这里对多种可能的字段名做兼容。
|
|
1373
|
+
*/
|
|
1374
|
+
function extractHomeEggStatus(payload) {
|
|
1375
|
+
const data = pickEggStatusPayload(payload);
|
|
1376
|
+
const nowTs = Math.floor(Date.now() / 1000);
|
|
1377
|
+
const eggLists = [
|
|
1378
|
+
data?.eggs,
|
|
1379
|
+
data?.egg_list,
|
|
1380
|
+
data?.egg_info,
|
|
1381
|
+
data?.home_eggs,
|
|
1382
|
+
data?.home_egg_list,
|
|
1383
|
+
data?.home_pets,
|
|
1384
|
+
data?.pet_list,
|
|
1385
|
+
].filter(Array.isArray);
|
|
1386
|
+
const pets = [];
|
|
1387
|
+
for (const list of eggLists) {
|
|
1388
|
+
for (const item of list) {
|
|
1389
|
+
const pet = extractHomeEggPet(item, nowTs);
|
|
1390
|
+
if (pet)
|
|
1391
|
+
pets.push(pet);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
const readyCount = pets.length > 0
|
|
1395
|
+
? pets.filter(pet => pet.ready).length
|
|
1396
|
+
: Number(data?.ready_egg_count ?? data?.readyEggCount ?? data?.egg_ready_count ?? 0) || 0;
|
|
1397
|
+
const totalEggs = pets.length > 0
|
|
1398
|
+
? pets.length
|
|
1399
|
+
: Number(data?.total_egg_count ?? data?.totalEggCount ?? data?.egg_count ?? 0) || 0;
|
|
1400
|
+
return { readyCount, totalEggs, pets };
|
|
1401
|
+
}
|
|
1402
|
+
// 与全量家园信息的蛋状态口径一致:只统计参与生蛋的精灵(有蛋或已排期)。
|
|
1403
|
+
function homeEggSubscriptionState(payload) {
|
|
1404
|
+
const status = extractHomeEggStatus(payload);
|
|
1405
|
+
const items = status.pets.filter(pet => pet.hasEgg || pet.predictedEggTime > 0);
|
|
1406
|
+
const readyItems = items.filter(pet => pet.ready);
|
|
1407
|
+
return { items, readyItems, names: readyItems.map(pet => pet.name) };
|
|
1408
|
+
}
|
|
1409
|
+
function buildHomeEggStatusText(uid, status) {
|
|
1410
|
+
const lines = [
|
|
1411
|
+
`家园蛋状态 - UID ${uid}`,
|
|
1412
|
+
`可收蛋精灵:${status.readyCount} 只 / 共检测 ${status.totalEggs} 只`,
|
|
1413
|
+
];
|
|
1414
|
+
const tracked = status.pets.filter(pet => pet.hasEgg || pet.predictedEggTime > 0);
|
|
1415
|
+
if (tracked.length > 0) {
|
|
1416
|
+
lines.push('');
|
|
1417
|
+
for (const pet of tracked.slice(0, 30)) {
|
|
1418
|
+
lines.push(`${pet.name} ${pet.ready ? '✅ 可收蛋' : `⏳ ${pet.remaining}`}`);
|
|
1419
|
+
}
|
|
1420
|
+
if (tracked.length > 30)
|
|
1421
|
+
lines.push(`…等共 ${tracked.length} 只`);
|
|
1422
|
+
}
|
|
1423
|
+
lines.push('');
|
|
1424
|
+
lines.push(`更新时间:${new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}`);
|
|
1425
|
+
return lines.join('\n');
|
|
1426
|
+
}
|
|
1427
|
+
// 家园精灵一览(home/pet-data),汇总体重、声音、变异与生蛋状态。
|
|
1428
|
+
function collectHomePetsViewSources(homeInfo, payload) {
|
|
1429
|
+
const containers = [homeInfo?.friend_cell_home_brief_info, homeCellInfo(homeInfo), homeInfo?.cell_info, homeInfo, payload?.friend_cell_home_brief_info];
|
|
1430
|
+
const result = [];
|
|
1431
|
+
const seen = new Set();
|
|
1432
|
+
for (const container of containers) {
|
|
1433
|
+
if (!container || typeof container !== 'object' || !Array.isArray(container.home_pets))
|
|
1434
|
+
continue;
|
|
1435
|
+
for (const item of container.home_pets) {
|
|
1436
|
+
const info = item?.home_pet_info && typeof item.home_pet_info === 'object' ? item.home_pet_info : item;
|
|
1437
|
+
const key = String(info?.pet_gid || info?.furniture_guid || `${info?.pet_cfg_id || ''}:${info?.name || ''}`);
|
|
1438
|
+
if (key && seen.has(key))
|
|
1439
|
+
continue;
|
|
1440
|
+
if (key)
|
|
1441
|
+
seen.add(key);
|
|
1442
|
+
result.push(item);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
return result;
|
|
1446
|
+
}
|
|
1447
|
+
function homePetsViewPetFromNpc(raw) {
|
|
1448
|
+
const npcPet = raw?.npc_pet && typeof raw.npc_pet === 'object' ? raw.npc_pet : {};
|
|
1449
|
+
const pet = npcPet?.pet && typeof npcPet.pet === 'object' ? npcPet.pet : (raw?.pet && typeof raw.pet === 'object' ? raw.pet : raw?.display_info);
|
|
1450
|
+
const petId = raw?.pet_cfg_id || raw?.pet_id || pet?.base_conf_id || pet?.pet_id || pet?.id;
|
|
1451
|
+
return {
|
|
1452
|
+
home_pet_info: {
|
|
1453
|
+
pet_gid: raw?.pet_gid || pet?.pet_gid,
|
|
1454
|
+
npc_id: raw?.npc_id || raw?.npcId,
|
|
1455
|
+
pet_cfg_id: petId,
|
|
1456
|
+
furniture_guid: raw?.furniture_guid,
|
|
1457
|
+
name: raw?.name || pet?.name,
|
|
1458
|
+
speciality_id: raw?.speciality_id || pet?.speciality_id,
|
|
1459
|
+
real_speciality_ids: raw?.real_speciality_ids || pet?.real_speciality_ids || [],
|
|
1460
|
+
status: raw?.status,
|
|
1461
|
+
},
|
|
1462
|
+
display_info: pet,
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
function isHomePetsViewGuard(homePetInfo, displayInfo, pet) {
|
|
1466
|
+
const status = String(homePetInfo?.status ?? pet?.status ?? displayInfo?.status ?? '').toLowerCase();
|
|
1467
|
+
const zeroCfgWithName = String(homePetInfo?.pet_cfg_id || '0') === '0'
|
|
1468
|
+
&& Boolean(String(homePetInfo?.name || homePetInfo?.pet_name || '').trim());
|
|
1469
|
+
return zeroCfgWithName
|
|
1470
|
+
|| Boolean(homePetInfo?.is_guard || homePetInfo?.guard || pet?.is_guard || pet?.guard || displayInfo?.is_guard || displayInfo?.guard)
|
|
1471
|
+
|| status === '2' || status === 'guard';
|
|
1472
|
+
}
|
|
1473
|
+
// ingame 数据体重可能以克或千克记录:大数值按克换算成千克展示。
|
|
1474
|
+
function homePetsWeightText(value) {
|
|
1475
|
+
const num = Number(value);
|
|
1476
|
+
if (!Number.isFinite(num) || num <= 0)
|
|
1477
|
+
return '--';
|
|
1478
|
+
const kg = num >= 1000 ? num / 1000 : num;
|
|
1479
|
+
const text = kg.toFixed(2).replace(/0+$/, '').replace(/\.$/, '');
|
|
1480
|
+
return `${text}kg`;
|
|
1481
|
+
}
|
|
1482
|
+
function buildHomePetsViewData(deps, res, uid) {
|
|
1483
|
+
const raw = res || {};
|
|
1484
|
+
const payload = raw.result && typeof raw.result === 'object' ? raw.result : raw;
|
|
1485
|
+
const homeInfo = homeInfoPayload(raw);
|
|
1486
|
+
const homePets = collectHomePetsViewSources(homeInfo, payload);
|
|
1487
|
+
const npcPets = Array.isArray(payload.npc_pets) ? payload.npc_pets : [];
|
|
1488
|
+
const npcMap = new Map();
|
|
1489
|
+
for (const entry of npcPets) {
|
|
1490
|
+
const npcPet = entry?.npc_pet && typeof entry.npc_pet === 'object' ? entry.npc_pet : {};
|
|
1491
|
+
const pet = npcPet?.pet && typeof npcPet.pet === 'object' ? npcPet.pet : entry?.pet;
|
|
1492
|
+
const gid = String(entry?.pet_gid || entry?.petGid || npcPet?.pet_gid || pet?.pet_gid || '').trim();
|
|
1493
|
+
if (gid)
|
|
1494
|
+
npcMap.set(gid, entry);
|
|
1495
|
+
}
|
|
1496
|
+
const nowTs = Math.floor(Date.now() / 1000);
|
|
1497
|
+
const petSources = homePets.length > 0 ? homePets : npcPets.map(entry => homePetsViewPetFromNpc(entry));
|
|
1498
|
+
const pets = [];
|
|
1499
|
+
for (const hp of petSources) {
|
|
1500
|
+
const homePetInfo = hp?.home_pet_info && typeof hp.home_pet_info === 'object' ? hp.home_pet_info : hp;
|
|
1501
|
+
const displayInfo = hp?.display_info && typeof hp.display_info === 'object' ? hp.display_info : {};
|
|
1502
|
+
const petGid = String(homePetInfo?.pet_gid || displayInfo?.pet_gid || '').trim();
|
|
1503
|
+
const npcRaw = npcMap.get(petGid) || {};
|
|
1504
|
+
const npcPetObj = npcRaw?.npc_pet && typeof npcRaw.npc_pet === 'object' ? npcRaw.npc_pet : {};
|
|
1505
|
+
const npcFullPet = npcPetObj?.pet && typeof npcPetObj.pet === 'object' ? npcPetObj.pet
|
|
1506
|
+
: (npcRaw?.pet && typeof npcRaw.pet === 'object' ? npcRaw.pet : npcRaw?.display_info);
|
|
1507
|
+
const npcStatus = String(npcRaw?.status || '');
|
|
1508
|
+
const hasFull = npcFullPet && typeof npcFullPet === 'object' && Object.keys(npcFullPet).length > 0 && npcStatus !== 'error';
|
|
1509
|
+
const pet = hasFull ? npcFullPet : displayInfo;
|
|
1510
|
+
const petId = pet?.base_conf_id || pet?.pet_id || pet?.id || displayInfo?.base_conf_id || homePetInfo?.pet_cfg_id;
|
|
1511
|
+
if (isHomePetsViewGuard(homePetInfo, displayInfo, pet) || !Number(petId))
|
|
1512
|
+
continue;
|
|
1513
|
+
const name = String(pet?.name || homePetInfo?.name || homePetInfo?.pet_name || `精灵 ${petId}`).trim();
|
|
1514
|
+
const gender = Number(pet?.gender ?? displayInfo?.gender ?? 0) || 0;
|
|
1515
|
+
const genderText = gender === 1 ? '♂ 雄性' : gender === 2 ? '♀ 雌性' : '未知';
|
|
1516
|
+
let mutationType = Number(pet?.mutation_type ?? displayInfo?.mutation_type ?? 0) || 0;
|
|
1517
|
+
if (!mutationType) {
|
|
1518
|
+
// 与 extractHomePet 相同的变体兜底(real_speciality_ids 103=异色、502=炫彩)。
|
|
1519
|
+
const specialityValues = [];
|
|
1520
|
+
for (const value of [homePetInfo.real_speciality_ids, npcRaw.real_speciality_ids, homePetInfo.speciality_id, npcRaw.speciality_id]) {
|
|
1521
|
+
if (Array.isArray(value))
|
|
1522
|
+
specialityValues.push(...value);
|
|
1523
|
+
else if (value !== undefined && value !== null && value !== '')
|
|
1524
|
+
specialityValues.push(value);
|
|
1525
|
+
}
|
|
1526
|
+
const specialityIds = new Set(specialityValues.map(value => String(value).trim()).filter(Boolean));
|
|
1527
|
+
if (specialityIds.has('103') && specialityIds.has('502'))
|
|
1528
|
+
mutationType = 9;
|
|
1529
|
+
else if (specialityIds.has('103'))
|
|
1530
|
+
mutationType = 1;
|
|
1531
|
+
else if (specialityIds.has('502'))
|
|
1532
|
+
mutationType = 8;
|
|
1533
|
+
}
|
|
1534
|
+
const variantText = String(pet?.mutation_name || displayInfo?.mutation_name || '')
|
|
1535
|
+
|| (mutationType === 9 ? '异色炫彩' : mutationType === 1 ? '异色' : mutationType === 8 ? '炫彩' : '');
|
|
1536
|
+
const hasEgg = Boolean(hp?.have_egg ?? pet?.have_egg);
|
|
1537
|
+
const predictedEggTime = normalizeEpochSeconds(hp?.predicted_egg_time ?? pet?.predicted_egg_time);
|
|
1538
|
+
const eggReady = hasEgg || (predictedEggTime > 0 && nowTs >= predictedEggTime);
|
|
1539
|
+
const eggText = eggReady ? '可收蛋' : (predictedEggTime > 0 ? `${formatEggRemaining(predictedEggTime, nowTs)}后生蛋` : '');
|
|
1540
|
+
pets.push({
|
|
1541
|
+
id: String(petId || ''),
|
|
1542
|
+
name,
|
|
1543
|
+
level: pet?.level ?? displayInfo?.level ?? homePetInfo?.level ?? '--',
|
|
1544
|
+
genderText,
|
|
1545
|
+
weightText: homePetsWeightText(pet?.weight ?? displayInfo?.weight ?? homePetInfo?.weight ?? pet?.pet_weight),
|
|
1546
|
+
voiceText: (0, pet_data_service_1.petDataVoiceInfo)(pet?.voice ?? displayInfo?.voice).value,
|
|
1547
|
+
variantText,
|
|
1548
|
+
eggReady,
|
|
1549
|
+
eggText,
|
|
1550
|
+
iconUrl: homePetIcon(petId, pet?.pet_icon_url || displayInfo?.pet_icon_url || npcRaw?.icon_url || ''),
|
|
1551
|
+
starIconUrl: [1, 8, 9].includes(mutationType)
|
|
1552
|
+
? deps.renderer.resourceUrl(`render-templates/home/img/rocomuid/star_${mutationType}.png`)
|
|
1553
|
+
: '',
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
pets.sort((a, b) => (a.eggReady === b.eggReady ? 0 : (a.eggReady ? -1 : 1)));
|
|
1557
|
+
const brief = homeBriefInfo(homeInfo);
|
|
1558
|
+
const homeName = String(brief?.home_name || brief?.name || payload?.player_info?.name || '').trim() || '洛克玩家';
|
|
1559
|
+
return {
|
|
1560
|
+
title: '家园精灵',
|
|
1561
|
+
homeName,
|
|
1562
|
+
uid,
|
|
1563
|
+
pets,
|
|
1564
|
+
total: pets.length,
|
|
1565
|
+
eggCount: pets.filter(pet => pet.eggReady).length,
|
|
1566
|
+
emptyText: '未获取到家园精灵信息。请确认目标玩家在线、家园可访问,或稍后重试。',
|
|
1567
|
+
updatedAt: new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }),
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
function buildHomePetsViewText(data) {
|
|
1571
|
+
const lines = [
|
|
1572
|
+
`【家园精灵】UID ${data.uid}(${data.homeName})`,
|
|
1573
|
+
`共 ${data.total} 只精灵,可收蛋 ${data.eggCount} 只`,
|
|
1574
|
+
];
|
|
1575
|
+
for (const pet of (data.pets || []).slice(0, 12)) {
|
|
1576
|
+
const bits = [pet.name, `Lv.${pet.level}`, pet.genderText, pet.weightText, pet.voiceText];
|
|
1577
|
+
if (pet.variantText)
|
|
1578
|
+
bits.push(pet.variantText);
|
|
1579
|
+
if (pet.eggText)
|
|
1580
|
+
bits.push(pet.eggText);
|
|
1581
|
+
lines.push(`- ${bits.join(' ')}`);
|
|
1582
|
+
}
|
|
1583
|
+
if ((data.pets || []).length > 12)
|
|
1584
|
+
lines.push(`…等共 ${data.pets.length} 只`);
|
|
1585
|
+
if (!data.pets?.length)
|
|
1586
|
+
lines.push(data.emptyText);
|
|
1587
|
+
return lines.join('\n');
|
|
1334
1588
|
}
|
|
1335
1589
|
function homeSubscriptionState(data, kind) {
|
|
1336
1590
|
if (kind === 'garden') {
|
|
@@ -1359,27 +1613,55 @@ function homeSubscriptionMessage(uid, kind, level, totalCount, readyItems, names
|
|
|
1359
1613
|
names.length ? `已完成:${names.slice(0, 8).join('、')}` : '',
|
|
1360
1614
|
].filter(Boolean).join('\n');
|
|
1361
1615
|
}
|
|
1362
|
-
async function checkHomeSubscriptions(deps) {
|
|
1616
|
+
async function checkHomeSubscriptions(deps, signal) {
|
|
1363
1617
|
const subs = deps.homeSubMgr.getAll();
|
|
1364
|
-
const
|
|
1618
|
+
const fullCache = new Map();
|
|
1619
|
+
const eggsCache = new Map();
|
|
1620
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
1365
1621
|
let checkedCount = 0;
|
|
1366
1622
|
let pushedCount = 0;
|
|
1623
|
+
const fetchFull = async (uid) => {
|
|
1624
|
+
if (!fullCache.has(uid)) {
|
|
1625
|
+
fullCache.set(uid, await deps.client.ingameHomeInfo(deps.ctx, uid, { timeoutMs: 30000, signal }).catch(() => null));
|
|
1626
|
+
}
|
|
1627
|
+
return fullCache.get(uid);
|
|
1628
|
+
};
|
|
1367
1629
|
for (const [key, sub] of Object.entries(subs)) {
|
|
1630
|
+
if (signal?.aborted)
|
|
1631
|
+
break;
|
|
1368
1632
|
if (!sub.uid || !['garden', 'inspiration', 'egg'].includes(sub.kind))
|
|
1369
1633
|
continue;
|
|
1370
1634
|
checkedCount++;
|
|
1371
|
-
|
|
1372
|
-
|
|
1635
|
+
const modified = () => JSON.stringify(deps.homeSubMgr.getAll()[key]) !== JSON.stringify(sub);
|
|
1636
|
+
let state = null;
|
|
1637
|
+
if (sub.kind === 'egg') {
|
|
1638
|
+
// 蛋状态订阅走轻量 home/eggs 接口,降低轮询开销。
|
|
1639
|
+
if (!eggsCache.has(sub.uid)) {
|
|
1640
|
+
eggsCache.set(sub.uid, await deps.client.ingameHomeEggs(deps.ctx, sub.uid, { timeoutMs: 30000, signal }).catch(() => null));
|
|
1641
|
+
}
|
|
1642
|
+
if (signal?.aborted)
|
|
1643
|
+
break;
|
|
1644
|
+
if (modified())
|
|
1645
|
+
continue;
|
|
1646
|
+
const payload = eggsCache.get(sub.uid);
|
|
1647
|
+
if (payload)
|
|
1648
|
+
state = homeEggSubscriptionState(payload);
|
|
1373
1649
|
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1650
|
+
if (!state) {
|
|
1651
|
+
const res = await fetchFull(sub.uid);
|
|
1652
|
+
if (signal?.aborted)
|
|
1653
|
+
break;
|
|
1654
|
+
if (modified())
|
|
1655
|
+
continue;
|
|
1656
|
+
if (!res)
|
|
1657
|
+
continue;
|
|
1658
|
+
state = homeSubscriptionState(buildHomeRenderData(deps, res, sub.uid), sub.kind);
|
|
1659
|
+
}
|
|
1660
|
+
const { items, readyItems, names } = state;
|
|
1379
1661
|
const totalCount = items.length;
|
|
1380
1662
|
if (totalCount <= 0)
|
|
1381
1663
|
continue;
|
|
1382
|
-
const notifyState = sub.notify_state
|
|
1664
|
+
const notifyState = { ...sub.notify_state };
|
|
1383
1665
|
const pushLevels = [];
|
|
1384
1666
|
if (!readyItems.length) {
|
|
1385
1667
|
notifyState.first = false;
|
|
@@ -1394,18 +1676,27 @@ async function checkHomeSubscriptions(deps) {
|
|
|
1394
1676
|
notifyState.all = false;
|
|
1395
1677
|
}
|
|
1396
1678
|
if (!pushLevels.length) {
|
|
1397
|
-
deps.homeSubMgr.upsert(key, { ...sub, notify_state: notifyState });
|
|
1679
|
+
deps.homeSubMgr.upsert(key, { ...sub, notify_state: notifyState, last_check_time: nowSec });
|
|
1398
1680
|
continue;
|
|
1399
1681
|
}
|
|
1400
|
-
const
|
|
1682
|
+
const owned = deps.userMgr.getUserBindings(sub.updated_by).find(binding => binding.role_id === sub.uid);
|
|
1683
|
+
const label = owned?.nickname || sub.uid;
|
|
1684
|
+
const notifyUser = owned && sub.notify_user_id === sub.updated_by ? sub.notify_user_id : '';
|
|
1685
|
+
const messages = pushLevels.map(level => homeSubscriptionMessage(label, sub.kind, level, totalCount, readyItems, names));
|
|
1401
1686
|
try {
|
|
1687
|
+
const body = messages.join('\n\n');
|
|
1688
|
+
// 群订阅 mention_all 开启时命中后 @全体。
|
|
1689
|
+
const content = !sub.user_id && sub.mention_all
|
|
1690
|
+
? [(0, koishi_1.h)('at', { type: 'all' }), koishi_1.h.text('\n' + body)]
|
|
1691
|
+
: (!sub.user_id && notifyUser ? [koishi_1.h.at(notifyUser), koishi_1.h.text('\n' + body)] : body);
|
|
1402
1692
|
const sent = await (0, subscription_send_1.sendScheduledMessage)(deps.ctx, {
|
|
1403
1693
|
platform: sub.platform,
|
|
1404
1694
|
channelId: sub.channel_id || sub.guild_id || sub.user_id || '',
|
|
1405
1695
|
guildId: sub.guild_id || '',
|
|
1406
1696
|
userId: sub.user_id || '',
|
|
1407
|
-
|
|
1408
|
-
|
|
1697
|
+
selfId: sub.self_id || '',
|
|
1698
|
+
}, content, signal);
|
|
1699
|
+
if (!sent || signal?.aborted || JSON.stringify(deps.homeSubMgr.getAll()[key]) !== JSON.stringify(sub))
|
|
1409
1700
|
continue;
|
|
1410
1701
|
}
|
|
1411
1702
|
catch (e) {
|
|
@@ -1415,12 +1706,13 @@ async function checkHomeSubscriptions(deps) {
|
|
|
1415
1706
|
for (const level of pushLevels)
|
|
1416
1707
|
notifyState[level] = true;
|
|
1417
1708
|
pushedCount += pushLevels.length;
|
|
1418
|
-
deps.homeSubMgr.upsert(key, { ...sub, notify_state: notifyState, last_push_time: Math.floor(Date.now() / 1000) });
|
|
1709
|
+
deps.homeSubMgr.upsert(key, { ...sub, notify_state: notifyState, last_push_time: Math.floor(Date.now() / 1000), last_check_time: nowSec });
|
|
1419
1710
|
}
|
|
1420
1711
|
return { subscriptions: Object.keys(subs).length, checked: checkedCount, pushed: pushedCount };
|
|
1421
1712
|
}
|
|
1422
1713
|
function register(deps) {
|
|
1423
1714
|
const { ctx, client } = deps;
|
|
1715
|
+
const homeRunner = (0, subscription_runner_1.createRunner)(ctx);
|
|
1424
1716
|
ctx.command('洛克').subcommand('.档案', '查看个人档案')
|
|
1425
1717
|
.alias('洛克档案')
|
|
1426
1718
|
.action(async ({ session }) => {
|
|
@@ -1444,28 +1736,30 @@ function register(deps) {
|
|
|
1444
1736
|
const cl = collRes || {};
|
|
1445
1737
|
const bo = boRes || {};
|
|
1446
1738
|
const recentBattle = blRes?.battles?.[0];
|
|
1447
|
-
const
|
|
1448
|
-
const
|
|
1739
|
+
const auth = { fwToken, userIdentifier };
|
|
1740
|
+
const playerSearchRes = role?.id ? await client.ingamePlayerSearch(ctx, String(role.id), { auth }) : null;
|
|
1741
|
+
const playerCardRes = role?.id ? await client.ingamePlayerCard(ctx, String(role.id), { auth }).catch(() => null) : null;
|
|
1742
|
+
const playerSearchData = (0, player_service_1.parseIngamePlayerPayload)((0, player_service_1.mergePlayerPayloads)(playerSearchRes, playerCardRes), String(role.id || ''));
|
|
1449
1743
|
const profileSignature = playerSearchData?.signature || '';
|
|
1450
1744
|
const profileHeadTags = playerSearchData ? [
|
|
1451
|
-
{ label: '在线', value: playerField(playerSearchData, 'online', '未知') },
|
|
1452
|
-
{ label: '性别', value: playerField(playerSearchData, 'gender', playerField(playerSearchData, 'sex', '未知')) },
|
|
1453
|
-
{ label: '世界等级', value: playerField(playerSearchData, 'world_level') },
|
|
1454
|
-
{ label: '家园等级', value: playerField(playerSearchData, 'home_level') },
|
|
1745
|
+
{ label: '在线', value: (0, player_service_1.playerField)(playerSearchData, 'online', '未知') },
|
|
1746
|
+
{ label: '性别', value: (0, player_service_1.playerField)(playerSearchData, 'gender', (0, player_service_1.playerField)(playerSearchData, 'sex', '未知')) },
|
|
1747
|
+
{ label: '世界等级', value: (0, player_service_1.playerField)(playerSearchData, 'world_level') },
|
|
1748
|
+
{ label: '家园等级', value: (0, player_service_1.playerField)(playerSearchData, 'home_level') },
|
|
1455
1749
|
].filter((item) => item.value && item.value !== '-' && item.value !== '未设置').slice(0, 4) : [];
|
|
1456
1750
|
const profileHomeItems = playerSearchData ? [
|
|
1457
|
-
{ label: '家园名称', value: playerField(playerSearchData, 'home_name') },
|
|
1458
|
-
{ label: '家园等级', value: playerField(playerSearchData, 'home_level') },
|
|
1459
|
-
{ label: '家园经验', value: playerField(playerSearchData, 'home_experience') },
|
|
1460
|
-
{ label: '舒适度', value: playerField(playerSearchData, 'home_comfort_level') },
|
|
1461
|
-
{ label: '访客数量', value: playerField(playerSearchData, 'visitor_num') },
|
|
1751
|
+
{ label: '家园名称', value: (0, player_service_1.playerField)(playerSearchData, 'home_name') },
|
|
1752
|
+
{ label: '家园等级', value: (0, player_service_1.playerField)(playerSearchData, 'home_level') },
|
|
1753
|
+
{ label: '家园经验', value: (0, player_service_1.playerField)(playerSearchData, 'home_experience') },
|
|
1754
|
+
{ label: '舒适度', value: (0, player_service_1.playerField)(playerSearchData, 'home_comfort_level') },
|
|
1755
|
+
{ label: '访客数量', value: (0, player_service_1.playerField)(playerSearchData, 'visitor_num') },
|
|
1462
1756
|
].filter((item) => item.value && item.value !== '-' && item.value !== '未设置') : [];
|
|
1463
1757
|
const profileCardItems = playerSearchData ? [
|
|
1464
|
-
{ label: '名片皮肤', value: playerField(playerSearchData, 'card_skin_selected') },
|
|
1465
|
-
{ label: '名片头像', value: playerField(playerSearchData, 'card_icon_selected') },
|
|
1758
|
+
{ label: '名片皮肤', value: (0, player_service_1.playerField)(playerSearchData, 'card_skin_selected') },
|
|
1759
|
+
{ label: '名片头像', value: (0, player_service_1.playerField)(playerSearchData, 'card_icon_selected') },
|
|
1466
1760
|
].filter((item) => item.value && item.value !== '-' && item.value !== '未设置') : [];
|
|
1467
|
-
const profileCardImage = playerSearchData ? playerField(playerSearchData, 'card_bussiness_card_url', '') : '';
|
|
1468
|
-
const profileStatusText = playerSearchData ? playerField(playerSearchData, 'online', '未知') : '未知';
|
|
1761
|
+
const profileCardImage = playerSearchData ? (0, player_service_1.resourceUrl)((0, player_service_1.playerField)(playerSearchData, 'card_bussiness_card_url', ''), deps.config.apiBaseUrl) : '';
|
|
1762
|
+
const profileStatusText = playerSearchData ? (0, player_service_1.playerField)(playerSearchData, 'online', '未知') : '未知';
|
|
1469
1763
|
const hasExtraProfileData = Boolean(profileSignature || profileHomeItems.length || profileCardItems.length || profileCardImage);
|
|
1470
1764
|
let degraded = false;
|
|
1471
1765
|
if (!sm) {
|
|
@@ -1579,7 +1873,7 @@ function register(deps) {
|
|
|
1579
1873
|
profileStatusText,
|
|
1580
1874
|
profileStatusClass: profileStatusText === '是' ? 'online' : 'offline',
|
|
1581
1875
|
commandHint: '洛克.背包 <筛选> <页码> | 洛克.战绩 <页码> | 洛克 查看菜单',
|
|
1582
|
-
copyright: '
|
|
1876
|
+
copyright: 'Koishi & WeGame Roco Kingdom Plugin',
|
|
1583
1877
|
};
|
|
1584
1878
|
if (recentBattle) {
|
|
1585
1879
|
data.hasBattleData = true;
|
|
@@ -1593,7 +1887,7 @@ function register(deps) {
|
|
|
1593
1887
|
icon: pet.pet_img_url?.replace('/image.png', '/icon.png') || '',
|
|
1594
1888
|
}));
|
|
1595
1889
|
}
|
|
1596
|
-
const fallback = `【${role.name}的档案】Lv.${role.level} UID:${role.id}\n评分:${ev.score || '0'} 收藏:${cl.current_collection_count || 0}/${cl.total_collection_count || 0}`;
|
|
1890
|
+
const fallback = `【${role.name || '洛克玩家'}的档案】Lv.${role.level || '--'} UID:${role.id || '--'}\n评分:${ev.score || '0'} 收藏:${cl.current_collection_count || 0}/${cl.total_collection_count || 0}`;
|
|
1597
1891
|
await sendImage(deps, session, 'personal-card', data, fallback);
|
|
1598
1892
|
});
|
|
1599
1893
|
ctx.command('洛克').subcommand('.战绩 [page:number]', '查看对战战绩')
|
|
@@ -1633,7 +1927,7 @@ function register(deps) {
|
|
|
1633
1927
|
});
|
|
1634
1928
|
const data = {
|
|
1635
1929
|
userAvatarDisplay: role.avatar_url || '',
|
|
1636
|
-
userName: role.name,
|
|
1930
|
+
userName: role.name || '洛克玩家',
|
|
1637
1931
|
userLevel: role.level || 1,
|
|
1638
1932
|
userUid: role.id || '',
|
|
1639
1933
|
winRate: `${bo.win_rate || 0}%`,
|
|
@@ -1642,7 +1936,7 @@ function register(deps) {
|
|
|
1642
1936
|
commandHint: '洛克.战绩 <页码>',
|
|
1643
1937
|
copyright: 'Koishi & WeGame 洛克王国插件',
|
|
1644
1938
|
};
|
|
1645
|
-
await sendImage(deps, session, 'record', data, `【${role.name}的战绩】胜率:${bo.win_rate || 0}% 场次:${bo.total_match || 0}`);
|
|
1939
|
+
await sendImage(deps, session, 'record', data, `【${role.name || '洛克玩家'}的战绩】胜率:${bo.win_rate || 0}% 场次:${bo.total_match || 0}`);
|
|
1646
1940
|
});
|
|
1647
1941
|
ctx.command('洛克').subcommand('.背包 [arg1:string] [arg2:string]', '查看精灵背包')
|
|
1648
1942
|
.alias('洛克背包')
|
|
@@ -1838,15 +2132,33 @@ function register(deps) {
|
|
|
1838
2132
|
};
|
|
1839
2133
|
await sendImage(deps, session, 'exchange-hall', data, `【交换大厅】第${page}页`);
|
|
1840
2134
|
});
|
|
1841
|
-
ctx.command('洛克').subcommand('.玩家
|
|
2135
|
+
ctx.command('洛克').subcommand('.玩家 [uid:string]', '通过 ingame 接口查询玩家资料')
|
|
1842
2136
|
.alias('洛克玩家')
|
|
1843
|
-
.action(async ({ session }, uid) => {
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
const
|
|
1847
|
-
|
|
2137
|
+
.action(async ({ session }, uid = '') => {
|
|
2138
|
+
const userId = session.userId;
|
|
2139
|
+
const explicitUid = String(uid || '').trim();
|
|
2140
|
+
const binding = deps.userMgr.getPrimaryBinding(userId);
|
|
2141
|
+
const targetUid = explicitUid || String(binding?.role_id || '');
|
|
2142
|
+
const fwToken = await (0, account_1.getPrimaryToken)(deps, userId);
|
|
2143
|
+
if (!targetUid && !fwToken) {
|
|
2144
|
+
return '请提供玩家 UID,或先使用“洛克.QQ登录 / 洛克.微信登录”完成绑定。用法:洛克.玩家 [UID]';
|
|
2145
|
+
}
|
|
2146
|
+
const auth = { fwToken, userIdentifier: userId };
|
|
2147
|
+
const search = await client.ingamePlayerSearch(ctx, targetUid, { auth });
|
|
2148
|
+
if (!search)
|
|
1848
2149
|
return `玩家搜索失败:${client.getLastErrorBrief()}`;
|
|
1849
|
-
|
|
2150
|
+
// 显式 UID 与搜索返回 UID 不一致时不合并名片,避免混用两个角色数据。
|
|
2151
|
+
const returnedUid = String(search?.player_info?.uin ?? search?.player_info?.uid ?? search?.uin ?? search?.uid ?? '');
|
|
2152
|
+
const uidConsistent = !explicitUid || !returnedUid || returnedUid === explicitUid;
|
|
2153
|
+
let card = uidConsistent
|
|
2154
|
+
? await client.ingamePlayerCard(ctx, targetUid, { auth }).catch(() => null)
|
|
2155
|
+
: null;
|
|
2156
|
+
const cardUid = (0, player_service_1.playerPayloadUid)(card);
|
|
2157
|
+
if (cardUid && (targetUid || returnedUid) && cardUid !== (targetUid || returnedUid))
|
|
2158
|
+
card = null;
|
|
2159
|
+
const view = (0, player_service_1.buildPlayerView)(search, card, targetUid, deps.config.apiBaseUrl);
|
|
2160
|
+
const merged = (0, player_service_1.mergePlayerPayloads)(search, card);
|
|
2161
|
+
await sendImage(deps, session, 'player-search', buildPlayerSearchRenderData(merged, targetUid || view.parsed.uid, view.cardImageUrl), (0, player_service_1.buildPlayerText)(merged, targetUid || view.parsed.uid));
|
|
1850
2162
|
});
|
|
1851
2163
|
ctx.command('洛克').subcommand('.家园 [uid:string]', '通过 UID 查询家园菜园、守卫和室内精灵')
|
|
1852
2164
|
.alias('洛克家园')
|
|
@@ -1856,10 +2168,12 @@ function register(deps) {
|
|
|
1856
2168
|
const binding = deps.userMgr.getPrimaryBinding(session.userId);
|
|
1857
2169
|
targetUid = String(binding?.role_id || '');
|
|
1858
2170
|
}
|
|
1859
|
-
|
|
2171
|
+
const fwToken = await (0, account_1.getPrimaryToken)(deps, session.userId);
|
|
2172
|
+
if (!targetUid && !fwToken)
|
|
1860
2173
|
return '请提供玩家 UID,或先完成绑定后使用 洛克.家园。';
|
|
1861
2174
|
let queuedNotified = false;
|
|
1862
2175
|
const res = await client.ingameHomeInfo(ctx, targetUid, {
|
|
2176
|
+
auth: { fwToken, userIdentifier: session.userId },
|
|
1863
2177
|
waitMs: deps.config.homeQueryWaitMs,
|
|
1864
2178
|
intervalMs: deps.config.homeQueryPollIntervalMs,
|
|
1865
2179
|
timeoutMs: deps.config.homeQueryTimeoutMs,
|
|
@@ -1914,7 +2228,9 @@ function register(deps) {
|
|
|
1914
2228
|
].join('\n');
|
|
1915
2229
|
}
|
|
1916
2230
|
const lowBandwidth = Boolean(deps.config.lowBandwidthMode);
|
|
1917
|
-
//
|
|
2231
|
+
// classic 样式走 pet-detail-classic 模板(立绘 + 属性表 + 技能栏),
|
|
2232
|
+
// 不需要精灵体重范围(sizeLookup)。
|
|
2233
|
+
const useClassic = deps.config.homeDetailUiStyle !== 'panel';
|
|
1918
2234
|
const [optionsPayload, skillLookup, sizeLookup] = await Promise.all([
|
|
1919
2235
|
deps.wikiService.getOptionsPayload().catch(() => ({})),
|
|
1920
2236
|
(async () => {
|
|
@@ -1928,6 +2244,8 @@ function register(deps) {
|
|
|
1928
2244
|
return lookup;
|
|
1929
2245
|
})(),
|
|
1930
2246
|
(async () => {
|
|
2247
|
+
if (useClassic)
|
|
2248
|
+
return {};
|
|
1931
2249
|
const lookup = {};
|
|
1932
2250
|
const ids = (0, pet_data_service_1.petDataPetIdsFromPayload)(res);
|
|
1933
2251
|
await Promise.all(ids.map(async (id) => {
|
|
@@ -1938,7 +2256,16 @@ function register(deps) {
|
|
|
1938
2256
|
return lookup;
|
|
1939
2257
|
})(),
|
|
1940
2258
|
]);
|
|
1941
|
-
const
|
|
2259
|
+
const classicData = useClassic
|
|
2260
|
+
? (0, pet_data_service_1.buildPetDetailClassicView)(res, targetUid || '当前绑定', {
|
|
2261
|
+
optionsPayload,
|
|
2262
|
+
skillLookup,
|
|
2263
|
+
baseUrl: deps.config.apiBaseUrl.replace(/\/$/, ''),
|
|
2264
|
+
loadSkillIcons: !lowBandwidth,
|
|
2265
|
+
variantIconPath: mutationType => `render-templates/pet-detail-classic/texture2D/star_${mutationType}.png`,
|
|
2266
|
+
})
|
|
2267
|
+
: null;
|
|
2268
|
+
const data = classicData || (0, pet_data_service_1.buildPetDataRenderData)(res, targetUid || '当前绑定', {
|
|
1942
2269
|
optionsPayload,
|
|
1943
2270
|
skillLookup,
|
|
1944
2271
|
sizeLookup,
|
|
@@ -1947,18 +2274,94 @@ function register(deps) {
|
|
|
1947
2274
|
baseUrl: deps.config.apiBaseUrl.replace(/\/$/, ''),
|
|
1948
2275
|
});
|
|
1949
2276
|
const fallbackLines = [
|
|
1950
|
-
`家园详情 - UID ${data.uid}
|
|
1951
|
-
data.notice,
|
|
2277
|
+
`家园详情 - UID ${data.uid}${data.onlineText ? `(${data.onlineText})` : ''}`,
|
|
2278
|
+
data.notice || '',
|
|
1952
2279
|
];
|
|
1953
2280
|
for (const pet of (data.pets || []).slice(0, 8)) {
|
|
1954
|
-
|
|
2281
|
+
const bits = [
|
|
2282
|
+
pet.index ? `${pet.index}.` : '',
|
|
2283
|
+
`${pet.name} Lv.${pet.level}`,
|
|
2284
|
+
pet.variantText,
|
|
2285
|
+
`分贝 ${pet.voiceText || '--'}`,
|
|
2286
|
+
].filter(Boolean);
|
|
2287
|
+
fallbackLines.push(bits.join(' '));
|
|
1955
2288
|
}
|
|
1956
2289
|
if (!data.pets?.length)
|
|
1957
2290
|
fallbackLines.push(data.emptyText);
|
|
1958
2291
|
fallbackLines.push('');
|
|
1959
2292
|
fallbackLines.push('若服务器带宽过小导致生成超时,请在配置项打开低带宽模式。');
|
|
1960
2293
|
fallbackLines.push('低带宽模式开启后,家园详情将不再加载技能图标。');
|
|
1961
|
-
await sendImage(deps, session, 'pet-data', data, fallbackLines.join('\n')
|
|
2294
|
+
await sendImage(deps, session, classicData ? 'pet-detail-classic' : 'pet-data', data, fallbackLines.join('\n'), {
|
|
2295
|
+
...(lowBandwidth ? render_1.lowBandwidthRenderOptions : {}),
|
|
2296
|
+
timeoutMs: deps.config.renderTimeout || 30000,
|
|
2297
|
+
});
|
|
2298
|
+
});
|
|
2299
|
+
// 家园精灵一览(home/pet-data),体重、声音、变异与生蛋状态。
|
|
2300
|
+
ctx.command('洛克').subcommand('.家园精灵 [uid:string]', '查看家园精灵列表(体重、声音、生蛋状态)')
|
|
2301
|
+
.alias('洛克家园精灵')
|
|
2302
|
+
.alias('家园精灵')
|
|
2303
|
+
.action(async ({ session }, uid = '') => {
|
|
2304
|
+
let targetUid = String(uid || '').trim();
|
|
2305
|
+
if (!targetUid) {
|
|
2306
|
+
const binding = deps.userMgr.getPrimaryBinding(session.userId);
|
|
2307
|
+
targetUid = String(binding?.role_id || '');
|
|
2308
|
+
}
|
|
2309
|
+
const fwToken = await (0, account_1.getPrimaryToken)(deps, session.userId);
|
|
2310
|
+
if (!targetUid && !fwToken)
|
|
2311
|
+
return '请提供玩家 UID,或先完成绑定后使用 洛克.家园精灵。';
|
|
2312
|
+
let queuedNotified = false;
|
|
2313
|
+
const res = await client.ingameHomePetData(ctx, targetUid, {
|
|
2314
|
+
auth: { fwToken, userIdentifier: session.userId },
|
|
2315
|
+
waitMs: deps.config.homeQueryWaitMs,
|
|
2316
|
+
intervalMs: deps.config.homeQueryPollIntervalMs,
|
|
2317
|
+
timeoutMs: deps.config.homeQueryTimeoutMs,
|
|
2318
|
+
onQueued: async () => {
|
|
2319
|
+
if (queuedNotified)
|
|
2320
|
+
return;
|
|
2321
|
+
queuedNotified = true;
|
|
2322
|
+
await session?.send?.(`UID ${targetUid} 的家园精灵查询已进入队列,正在等待游戏侧返回,请稍候…`);
|
|
2323
|
+
},
|
|
2324
|
+
});
|
|
2325
|
+
if (!res) {
|
|
2326
|
+
return [
|
|
2327
|
+
`家园精灵查询失败:${client.getLastErrorBrief()}`,
|
|
2328
|
+
'提示:该接口需要目标玩家在线,且目标家园可访问。',
|
|
2329
|
+
].join('\n');
|
|
2330
|
+
}
|
|
2331
|
+
const data = buildHomePetsViewData(deps, res, targetUid || '当前绑定');
|
|
2332
|
+
await sendImage(deps, session, 'home-pets', data, buildHomePetsViewText(data), {
|
|
2333
|
+
timeoutMs: deps.config.renderTimeout || 30000,
|
|
2334
|
+
});
|
|
2335
|
+
});
|
|
2336
|
+
// 立即查询指定 UID 的家园蛋状态。
|
|
2337
|
+
ctx.command('洛克').subcommand('.家园状态 [uid:string]', '查询家园蛋状态(可收蛋精灵与倒计时)')
|
|
2338
|
+
.alias('洛克家园状态')
|
|
2339
|
+
.alias('家园状态')
|
|
2340
|
+
.action(async ({ session }, uid = '') => {
|
|
2341
|
+
let targetUid = String(uid || '').trim();
|
|
2342
|
+
if (!targetUid) {
|
|
2343
|
+
const binding = deps.userMgr.getPrimaryBinding(session.userId);
|
|
2344
|
+
targetUid = String(binding?.role_id || '');
|
|
2345
|
+
}
|
|
2346
|
+
const fwToken = await (0, account_1.getPrimaryToken)(deps, session.userId);
|
|
2347
|
+
if (!targetUid && !fwToken)
|
|
2348
|
+
return `请提供玩家 UID,或先完成绑定后使用 洛克.家园状态。`;
|
|
2349
|
+
let queuedNotified = false;
|
|
2350
|
+
const res = await client.ingameHomeEggs(ctx, targetUid, {
|
|
2351
|
+
auth: { fwToken, userIdentifier: session.userId },
|
|
2352
|
+
waitMs: deps.config.homeQueryWaitMs,
|
|
2353
|
+
intervalMs: deps.config.homeQueryPollIntervalMs,
|
|
2354
|
+
timeoutMs: deps.config.homeQueryTimeoutMs,
|
|
2355
|
+
onQueued: async () => {
|
|
2356
|
+
if (queuedNotified)
|
|
2357
|
+
return;
|
|
2358
|
+
queuedNotified = true;
|
|
2359
|
+
await session?.send?.(`UID ${targetUid} 的家园蛋状态查询已进入队列,正在等待游戏侧返回,请稍候…`);
|
|
2360
|
+
},
|
|
2361
|
+
});
|
|
2362
|
+
if (!res)
|
|
2363
|
+
return `家园蛋状态查询失败:${client.getLastErrorBrief()}`;
|
|
2364
|
+
return buildHomeEggStatusText(targetUid, extractHomeEggStatus(res));
|
|
1962
2365
|
});
|
|
1963
2366
|
ctx.command('洛克').subcommand('.刷新面板 [uid:string]', '刷新指定 UID 的精灵面板缓存')
|
|
1964
2367
|
.alias('洛克刷新面板')
|
|
@@ -2041,15 +2444,16 @@ function register(deps) {
|
|
|
2041
2444
|
const fallback = panelPetDetailFallback(targetUid, selected, updatedAtText);
|
|
2042
2445
|
await sendImage(deps, session, 'pet-panel-detail', data, fallback);
|
|
2043
2446
|
});
|
|
2044
|
-
ctx.command('洛克').subcommand('.商店
|
|
2447
|
+
ctx.command('洛克').subcommand('.商店 [shopId:string]', '通过 ingame 接口查询商店信息,默认商店 3009')
|
|
2045
2448
|
.alias('洛克商店')
|
|
2046
|
-
.action(async ({ session }, shopId) => {
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2449
|
+
.action(async ({ session }, shopId = '3009') => {
|
|
2450
|
+
const targetShopId = String(shopId || '3009').trim() || '3009';
|
|
2451
|
+
if (!/^\d+$/.test(targetShopId))
|
|
2452
|
+
return '商店 ID 必须是数字。用法:洛克.商店 [shop_id],默认 3009';
|
|
2453
|
+
const res = await client.ingameMerchantInfo(ctx, targetShopId);
|
|
2050
2454
|
if (!res)
|
|
2051
2455
|
return `商店查询失败:${client.getLastErrorBrief()}`;
|
|
2052
|
-
await sendImage(deps, session, 'ingame-shop', buildShopRenderData(res,
|
|
2456
|
+
await sendImage(deps, session, 'ingame-shop', buildShopRenderData(res, targetShopId, { assetBaseUrl: client.wikiAssetBaseUrl }), `【洛克商店】shop_id=${targetShopId}`);
|
|
2053
2457
|
});
|
|
2054
2458
|
ctx.command('洛克').subcommand('.好友关系 <userIds:string>', '查询好友关系')
|
|
2055
2459
|
.alias('洛克好友关系')
|
|
@@ -2064,17 +2468,51 @@ function register(deps) {
|
|
|
2064
2468
|
return `好友关系查询失败:${client.getLastErrorBrief()}`;
|
|
2065
2469
|
await sendImage(deps, session, 'friendship', buildFriendshipRenderData(res, userIds), `【好友关系】${userIds}`);
|
|
2066
2470
|
});
|
|
2067
|
-
ctx.command('订阅家园菜园 [
|
|
2068
|
-
.
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2471
|
+
ctx.command('订阅家园菜园 [args:text]', '订阅指定 UID 的家园菜园成熟提醒')
|
|
2472
|
+
.userFields(['authority'])
|
|
2473
|
+
.action(async ({ session }, args = '') => {
|
|
2474
|
+
const parsed = parseHomeSubscribeArgs(args);
|
|
2475
|
+
return subscribeHome(deps, session, parsed.uid, 'garden', parsed.mentionAll);
|
|
2476
|
+
});
|
|
2477
|
+
ctx.command('订阅家园灵感 [args:text]', '订阅指定 UID 的家园精灵灵感完成提醒')
|
|
2478
|
+
.userFields(['authority'])
|
|
2479
|
+
.action(async ({ session }, args = '') => {
|
|
2480
|
+
const parsed = parseHomeSubscribeArgs(args);
|
|
2481
|
+
return subscribeHome(deps, session, parsed.uid, 'inspiration', parsed.mentionAll);
|
|
2482
|
+
});
|
|
2483
|
+
ctx.command('订阅家园生蛋 [args:text]', '订阅指定 UID 的家园精灵生蛋提醒')
|
|
2484
|
+
.userFields(['authority'])
|
|
2485
|
+
.action(async ({ session }, args = '') => {
|
|
2486
|
+
const parsed = parseHomeSubscribeArgs(args);
|
|
2487
|
+
return subscribeHome(deps, session, parsed.uid, 'egg', parsed.mentionAll);
|
|
2488
|
+
});
|
|
2489
|
+
// 查看当前会话的家园订阅列表。
|
|
2490
|
+
ctx.command('我的家园订阅', '查看当前会话的家园订阅列表')
|
|
2491
|
+
.userFields(['authority'])
|
|
2492
|
+
.action(async ({ session }) => {
|
|
2493
|
+
const target = sessionTarget(session);
|
|
2494
|
+
const kindLabel = { garden: '菜园', inspiration: '灵感', egg: '生蛋' };
|
|
2495
|
+
const subs = Object.values(deps.homeSubMgr.getAll()).filter(sub => sub.platform === target.platform
|
|
2496
|
+
&& (sub.channel_id || '') === (target.channelId || '')
|
|
2497
|
+
&& (sub.user_id || '') === (target.userId || ''));
|
|
2498
|
+
if (!subs.length)
|
|
2499
|
+
return (0, permissions_1.isDirectSession)(session) ? '你当前没有家园订阅。' : '本群当前没有家园订阅。';
|
|
2500
|
+
const formatTime = (ts) => (ts ? new Date(ts * 1000).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }) : '从未');
|
|
2501
|
+
const lines = [`当前家园订阅(共 ${subs.length} 个):`, ''];
|
|
2502
|
+
for (const sub of subs) {
|
|
2503
|
+
const mentionText = sub.mention_all && !sub.user_id ? ',命中后 @全体' : '';
|
|
2504
|
+
lines.push(`UID ${sub.uid}(${kindLabel[sub.kind] || sub.kind}${mentionText}):上次检查 ${formatTime(sub.last_check_time)},上次推送 ${formatTime(sub.last_push_time)}`);
|
|
2505
|
+
}
|
|
2506
|
+
lines.push('');
|
|
2507
|
+
lines.push('发送 取消订阅家园 [菜园/灵感/生蛋] [UID] 取消订阅');
|
|
2508
|
+
return lines.join('\n');
|
|
2509
|
+
});
|
|
2073
2510
|
ctx.command('取消订阅家园 [kind:string] [uid:string]', '取消当前会话的家园订阅')
|
|
2511
|
+
.userFields(['authority'])
|
|
2074
2512
|
.action(async ({ session }, kind = '全部', uid = '') => {
|
|
2075
2513
|
const target = sessionTarget(session);
|
|
2076
|
-
if (!target.userId && !
|
|
2077
|
-
return '
|
|
2514
|
+
if (!target.userId && !canManageGroupSubscription(deps, session))
|
|
2515
|
+
return '此指令仅限群管理员或机器人管理员使用。';
|
|
2078
2516
|
const kindMap = { '菜园': 'garden', '灵感': 'inspiration', '生蛋': 'egg', '全部': '', all: '', garden: 'garden', inspiration: 'inspiration', egg: 'egg' };
|
|
2079
2517
|
const deleted = deps.homeSubMgr.deleteMatching(target, kindMap[String(kind || '全部')] ?? '', String(uid || '').trim());
|
|
2080
2518
|
return deleted ? `已取消 ${deleted} 条家园订阅。` : '当前会话没有匹配的家园订阅。';
|
|
@@ -2084,10 +2522,12 @@ function register(deps) {
|
|
|
2084
2522
|
.action(async ({ session }) => {
|
|
2085
2523
|
if (!isBotAdmin(session, deps.config.adminUserIds))
|
|
2086
2524
|
return '此指令仅限管理员使用。';
|
|
2087
|
-
const result = await checkHomeSubscriptions(deps);
|
|
2525
|
+
const result = await homeRunner(signal => checkHomeSubscriptions(deps, signal));
|
|
2526
|
+
if (!result)
|
|
2527
|
+
return '订阅检查正在运行或插件已停止。';
|
|
2088
2528
|
return `家园订阅检查完成:订阅 ${result.subscriptions} 条,检查 ${result.checked} 条,推送 ${result.pushed} 档提醒。`;
|
|
2089
2529
|
});
|
|
2090
2530
|
if (deps.config.homeSubscriptionEnabled) {
|
|
2091
|
-
ctx.setInterval(() => checkHomeSubscriptions(deps).catch(err => logger.warn(`家园订阅检查失败: ${err}`)), Math.max(1, deps.config.homeSubscriptionIntervalMinutes || 5) * 60000);
|
|
2531
|
+
ctx.setInterval(() => homeRunner(signal => checkHomeSubscriptions(deps, signal)).catch(err => logger.warn(`家园订阅检查失败: ${err}`)), Math.max(1, deps.config.homeSubscriptionIntervalMinutes || 5) * 60000);
|
|
2092
2532
|
}
|
|
2093
2533
|
}
|