koishi-plugin-rocom 1.0.11 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/lib/client.d.ts +17 -1
  2. package/lib/client.js +121 -21
  3. package/lib/commands/merchant.js +409 -61
  4. package/lib/commands/query.js +95 -27
  5. package/lib/index.d.ts +4 -0
  6. package/lib/index.js +600 -127
  7. package/lib/render-templates/home/img/rocomuid/a_title.png +0 -0
  8. package/lib/render-templates/home/img/rocomuid/banner_bg.png +0 -0
  9. package/lib/render-templates/home/img/rocomuid/bg.jpg +0 -0
  10. package/lib/render-templates/home/img/rocomuid/img_head.png +0 -0
  11. package/lib/render-templates/home/img/rocomuid/jindu_bar.png +0 -0
  12. package/lib/render-templates/home/img/rocomuid/jindu_tc.png +0 -0
  13. package/lib/render-templates/home/img/rocomuid/level_icon.png +0 -0
  14. package/lib/render-templates/home/img/rocomuid/pet_bg.png +0 -0
  15. package/lib/render-templates/home/img/rocomuid/plant_bg.png +0 -0
  16. package/lib/render-templates/home/img/rocomuid/star_1.png +0 -0
  17. package/lib/render-templates/home/img/rocomuid/star_8.png +0 -0
  18. package/lib/render-templates/home/img/rocomuid/star_9.png +0 -0
  19. package/lib/render-templates/home/img/rocomuid/title_fg.png +0 -0
  20. package/lib/render-templates/home/img/rocomuid/top_bg.png +0 -0
  21. package/lib/render-templates/home/img/rocomuid/touxiang_mask.png +0 -0
  22. package/lib/render-templates/home/index.html +81 -97
  23. package/lib/render-templates/home/style.css +316 -375
  24. package/lib/render-templates/yuanxing-shangren/CHANGELOG.md +138 -0
  25. package/lib/render-templates/yuanxing-shangren/README.md +86 -0
  26. package/lib/render-templates/yuanxing-shangren/img/coin.png +0 -0
  27. package/lib/render-templates/yuanxing-shangren/img//345/272/225/351/203/250/344/277/241/346/201/257/346/241/206.png +0 -0
  28. package/lib/render-templates/yuanxing-shangren/img//346/240/207/351/242/230.png +0 -0
  29. package/lib/render-templates/yuanxing-shangren/img//347/203/255/351/224/200.png +0 -0
  30. package/lib/render-templates/yuanxing-shangren/img//347/274/226/345/217/267/350/203/214/346/231/257/346/241/206.png +0 -0
  31. package/lib/render-templates/yuanxing-shangren/index.html +233 -148
  32. package/lib/render-templates/yuanxing-shangren/index.html.backup +356 -0
  33. package/lib/render-templates/yuanxing-shangren/merchant.html +461 -0
  34. package/lib/render-templates/yuanxing-shangren/style.css +201 -256
  35. package/lib/render-templates/yuanxing-shangren/today.html +461 -0
  36. package/lib/render-templates/yuanxing-shangren/today.style.css +366 -0
  37. package/lib/render.js +11 -4
  38. package/lib/subscription-send.js +4 -5
  39. package/lib/ttf/rocom_skill_origin.ttf +0 -0
  40. package/lib/ttf//351/200/240/345/255/227/345/267/245/346/210/277/345/220/257/351/273/221/344/275/223.ttf +0 -0
  41. package/lib/types.d.ts +4 -0
  42. package/package.json +1 -1
@@ -258,16 +258,28 @@ function normalizeDurationSeconds(value) {
258
258
  function formatHomeRemaining(targetTs, nowTs = Math.floor(Date.now() / 1000)) {
259
259
  if (!targetTs)
260
260
  return '未开始';
261
- const remain = Math.max(0, targetTs - nowTs);
262
- if (remain <= 0)
261
+ if (nowTs >= targetTs)
263
262
  return '已完成';
264
- const hours = Math.floor(remain / 3600);
263
+ const remain = Math.max(0, targetTs - nowTs);
264
+ const days = Math.floor(remain / 86400);
265
+ const hours = Math.floor((remain % 86400) / 3600);
265
266
  const minutes = Math.floor((remain % 3600) / 60);
266
- if (hours >= 24)
267
- return `${Math.floor(hours / 24)}天${hours % 24}小时`;
267
+ const seconds = remain % 60;
268
+ if (days > 0)
269
+ return hours > 0 ? `${days}天${hours}小时` : `${days}天`;
268
270
  if (hours > 0)
269
271
  return `${hours}小时${minutes}分钟`;
270
- return `${minutes}分钟`;
272
+ if (minutes > 0)
273
+ return `${minutes}分${seconds}秒`;
274
+ return `${seconds}秒`;
275
+ }
276
+ function formatEggRemaining(targetTs, nowTs = Math.floor(Date.now() / 1000)) {
277
+ if (!targetTs || nowTs >= targetTs)
278
+ return '0分钟';
279
+ const remain = Math.max(0, targetTs - nowTs);
280
+ const totalHours = Math.floor(remain / 3600);
281
+ const minutes = Math.floor((remain % 3600) / 60);
282
+ return `${totalHours}小时${minutes}分钟`;
271
283
  }
272
284
  function homeInfoPayload(res) {
273
285
  const payload = res || {};
@@ -815,7 +827,7 @@ function panelPetDetailData(uid, pet, updatedAtText) {
815
827
  };
816
828
  }
817
829
  async function refreshPanelPets(deps, uid, userId = '') {
818
- const res = await deps.client.ingameHomeInfo(deps.ctx, uid, 20000);
830
+ const res = await deps.client.ingameHomeInfo(deps.ctx, uid, { waitMs: 20000, timeoutMs: 30000 });
819
831
  if (res) {
820
832
  const homeInfo = homeInfoPayload(res);
821
833
  const pets = buildPanelPetList(homeInfo);
@@ -848,7 +860,7 @@ function formatPanelUpdatedAt(ts) {
848
860
  return new Date().toLocaleString('zh-CN');
849
861
  return new Date(value * 1000).toLocaleString('zh-CN');
850
862
  }
851
- function extractHomePet(raw, index, guard = false) {
863
+ function extractHomePet(deps, raw, index, guard = false) {
852
864
  if (!raw || typeof raw !== 'object')
853
865
  return null;
854
866
  const homePet = raw.home_pet_info && typeof raw.home_pet_info === 'object' ? raw.home_pet_info : raw;
@@ -856,31 +868,64 @@ function extractHomePet(raw, index, guard = false) {
856
868
  const petId = homePet.pet_cfg_id || homePet.pet_id || homePet.pet_base_id || raw.pet_cfg_id || raw.pet_id || raw.id;
857
869
  if (['', '0'].includes(String(petId || '0')) && !guard)
858
870
  return null;
859
- const feedInfo = homePet.feed_info && typeof homePet.feed_info === 'object' ? homePet.feed_info : {};
860
- const beginTime = normalizeEpochSeconds(feedInfo.begin_time);
861
- const timeCost = normalizeDurationSeconds(feedInfo.time_cost);
862
- let readyAt = normalizeEpochSeconds(homePet.pet_rip_time || raw.pet_rip_time || raw.rip_time);
863
- if (!readyAt && beginTime && timeCost)
864
- readyAt = beginTime + timeCost;
865
871
  const nowTs = Math.floor(Date.now() / 1000);
866
- const hasInspiration = Boolean(readyAt);
867
- const inspireReady = hasInspiration && nowTs >= readyAt;
868
- const isGuard = guard || Boolean(raw.is_guard || raw.guard) || ['2', 'guard', '守卫'].includes(String(raw.status).toLowerCase());
869
- const statusText = isGuard && !hasInspiration ? '守卫中' : inspireReady ? '灵感已完成' : hasInspiration ? '灵感收集中' : '未喂食';
870
- const statusClass = isGuard && !hasInspiration ? 'guard' : inspireReady ? 'ready' : hasInspiration ? 'progress' : 'idle';
872
+ const hasEgg = Boolean(raw.have_egg);
873
+ const predictedEggTime = normalizeEpochSeconds(raw.predicted_egg_time);
874
+ const eggReady = hasEgg || (predictedEggTime > 0 && nowTs >= predictedEggTime);
875
+ const feedRound = Number(homePet.feed_round || raw.feed_round || 0) || 0;
876
+ const gender = Number(display.gender || raw.gender || 0) || 0;
877
+ const mutationType = Number(display.mutation_type || raw.mutation_type || homePet.mutation_type || 0) || 0;
878
+ const isMale = gender === 1;
879
+ const status = homePet.status ?? raw.status;
880
+ const isGuard = guard || Boolean(raw.is_guard || raw.guard) || ['2', 'guard', '守卫'].includes(String(status).toLowerCase());
881
+ const hasInspiration = feedRound > 0;
882
+ const inspireReady = hasInspiration;
883
+ const statusText = isGuard && !hasInspiration ? '守卫中'
884
+ : (inspireReady ? '可收取灵感'
885
+ : (hasInspiration ? '灵感收集中'
886
+ : '未喂食'));
887
+ const statusClass = isGuard && !hasInspiration ? 'guard'
888
+ : (eggReady ? 'ready'
889
+ : (inspireReady ? 'progress'
890
+ : (hasInspiration ? 'progress'
891
+ : 'idle')));
892
+ let note;
893
+ if (isGuard && String(petId) === '0') {
894
+ note = '家园守卫位';
895
+ }
896
+ else if (eggReady) {
897
+ note = '可收取';
898
+ }
899
+ else if (predictedEggTime > 0) {
900
+ note = `${formatEggRemaining(predictedEggTime, nowTs)}后生蛋`;
901
+ }
902
+ else if (feedRound > 0) {
903
+ note = isMale ? '' : '等待生蛋';
904
+ }
905
+ else if (isGuard) {
906
+ note = '家园守卫位';
907
+ }
908
+ else {
909
+ note = '未喂食';
910
+ }
871
911
  return {
872
912
  id: String(petId || ''),
873
913
  pos: raw.pos || raw.position || index + 1,
874
914
  name: String(homePet.name || homePet.pet_name || raw.name || raw.pet_name || `精灵 ${petId || ''}`),
875
915
  level: display.level || raw.level || homePet.level || '--',
876
916
  iconUrl: homePetIcon(petId, raw.icon_url || raw.pet_img_url || raw.petIcon || ''),
877
- badge: isGuard ? '守' : '',
917
+ starIconUrl: [1, 8, 9].includes(mutationType)
918
+ ? deps.renderer.resourceUrl(`render-templates/home/img/rocomuid/star_${mutationType}.png`)
919
+ : '',
920
+ badge: isGuard ? '守' : (hasEgg ? '蛋' : ''),
921
+ mutationType,
878
922
  isGuard,
879
923
  statusText,
880
924
  statusClass,
881
- note: hasInspiration ? formatHomeRemaining(readyAt, nowTs) : (isGuard ? '家园守卫位' : '暂无灵感倒计时'),
882
- inspireReady,
883
- readyAt,
925
+ note,
926
+ inspireReady: eggReady,
927
+ readyAt: predictedEggTime || 0,
928
+ gender,
884
929
  };
885
930
  }
886
931
  function homePetSources(homeInfo) {
@@ -998,7 +1043,7 @@ function buildHomeRenderData(deps, res, uid) {
998
1043
  const indoorPets = [];
999
1044
  const guardPets = [];
1000
1045
  indoorSources.forEach((raw, index) => {
1001
- const item = extractHomePet(raw, index);
1046
+ const item = extractHomePet(deps, raw, index);
1002
1047
  if (!item)
1003
1048
  return;
1004
1049
  if (item.isGuard)
@@ -1007,10 +1052,22 @@ function buildHomeRenderData(deps, res, uid) {
1007
1052
  indoorPets.push(item);
1008
1053
  });
1009
1054
  guardSources.forEach((raw, index) => {
1010
- const item = extractHomePet(raw, index, true);
1055
+ const item = extractHomePet(deps, raw, index, true);
1011
1056
  if (item)
1012
1057
  guardPets.push(item);
1013
1058
  });
1059
+ indoorPets.sort((a, b) => {
1060
+ if (a.gender === 2 && b.gender !== 2)
1061
+ return -1;
1062
+ if (a.gender !== 2 && b.gender === 2)
1063
+ return 1;
1064
+ if (a.gender === 2) {
1065
+ const ta = a.readyAt || Number.MAX_SAFE_INTEGER;
1066
+ const tb = b.readyAt || Number.MAX_SAFE_INTEGER;
1067
+ return ta - tb;
1068
+ }
1069
+ return 0;
1070
+ });
1014
1071
  const gardenPlots = extractHomePlants(deps, homeInfo);
1015
1072
  const createdAt = normalizeEpochSeconds(res?.meta?.created_at);
1016
1073
  return {
@@ -1268,7 +1325,7 @@ async function checkHomeSubscriptions(deps) {
1268
1325
  continue;
1269
1326
  checkedCount++;
1270
1327
  if (!cache.has(sub.uid)) {
1271
- cache.set(sub.uid, await deps.client.ingameHomeInfo(deps.ctx, sub.uid));
1328
+ cache.set(sub.uid, await deps.client.ingameHomeInfo(deps.ctx, sub.uid, { timeoutMs: 30000 }));
1272
1329
  }
1273
1330
  const res = cache.get(sub.uid);
1274
1331
  if (!res)
@@ -1757,7 +1814,18 @@ function register(deps) {
1757
1814
  }
1758
1815
  if (!targetUid)
1759
1816
  return '请提供玩家 UID,或先完成绑定后使用 洛克.家园。';
1760
- const res = await client.ingameHomeInfo(ctx, targetUid);
1817
+ let queuedNotified = false;
1818
+ const res = await client.ingameHomeInfo(ctx, targetUid, {
1819
+ waitMs: deps.config.homeQueryWaitMs,
1820
+ intervalMs: deps.config.homeQueryPollIntervalMs,
1821
+ timeoutMs: deps.config.homeQueryTimeoutMs,
1822
+ onQueued: async () => {
1823
+ if (queuedNotified)
1824
+ return;
1825
+ queuedNotified = true;
1826
+ await session?.send?.(`UID ${targetUid} 的家园查询已进入队列,正在等待游戏侧返回,请稍候…`);
1827
+ },
1828
+ });
1761
1829
  if (!res)
1762
1830
  return `家园查询失败:${client.getLastErrorBrief()}`;
1763
1831
  await sendImage(deps, session, 'home', buildHomeRenderData(deps, res, targetUid), `【洛克家园】UID ${targetUid}`);
package/lib/index.d.ts CHANGED
@@ -12,12 +12,16 @@ export interface Config {
12
12
  autoRefreshTime: string[];
13
13
  merchantSubscriptionEnabled: boolean;
14
14
  merchantSubscriptionItems: string[];
15
+ merchantUiStyle: 'new' | 'old';
15
16
  merchantPrivateSubscriptionEnabled: boolean;
16
17
  merchantCheckMode: 'interval' | 'times';
17
18
  merchantCheckInterval: number;
18
19
  merchantCheckTimes: string[];
19
20
  homeSubscriptionEnabled: boolean;
20
21
  homeSubscriptionIntervalMinutes: number;
22
+ homeQueryWaitMs: number;
23
+ homeQueryPollIntervalMs: number;
24
+ homeQueryTimeoutMs: number;
21
25
  imageCompressionEnabled: boolean;
22
26
  imageCompressionMinBytes: number;
23
27
  imageCompressionLevel: number;