@bettergi/utils 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -62,7 +62,7 @@ const t3 = findTextWithinBounds("确认", 960, 540, 960, 540);
62
62
 
63
63
  ### 行为流程
64
64
 
65
- > 对脚本开发过程中常见工作流的抽象,例如:等待 XXX 完成/出现/消失。
65
+ > 对脚本开发过程中常见工作流的抽象,例如: 等待/断言 操作/元素/区域 完成/出现/消失。
66
66
 
67
67
  ```ts
68
68
  // 等待直到找不到[关闭按钮] 或 5秒后超时,每隔1秒检查一次,期间按 Esc 键
@@ -106,10 +106,10 @@ await mouseScrollUp(175);
106
106
  // 鼠标滚轮向下滚动 175 像素
107
107
  await mouseScrollDown(175);
108
108
 
109
- // 鼠标滚轮向上滚动 99 行,行高 175(默认:背包物品行高)
109
+ // 鼠标滚轮向上滚动 99 行,行高 175(默认: 背包物品行高)
110
110
  await mouseScrollUpLines(99);
111
111
 
112
- // 鼠标滚轮向下滚动 1 行,行高 115(自定义:商店物品行高)
112
+ // 鼠标滚轮向下滚动 1 行,行高 115(自定义: 商店物品行高)
113
113
  await mouseScrollDownLines(1, 115);
114
114
  ```
115
115
 
@@ -123,7 +123,7 @@ import { useStore } from "@bettergi/utils";
123
123
  // 创建/读取存储对象,保存到存储文件 store/state.json 中
124
124
  const state = useStore<{ lastUsedTime?: number; count: number }>("state");
125
125
  if (state?.lastUsedTime) {
126
- log.info(`欢迎回来!上次使用时间:${state.lastUsedTime},计数器已累计至:${state.count}`);
126
+ log.info(`欢迎回来!上次使用时间: ${state.lastUsedTime},计数器已累计至: ${state.count}`);
127
127
  }
128
128
  try {
129
129
  // 模拟脚本运行期间状态的变化
@@ -143,7 +143,7 @@ try {
143
143
  import { getForBody, postForBody } from "@bettergi/utils";
144
144
 
145
145
  // 发送 GET 请求获取响应体内容
146
- // 提示:需要在 `manifest.json` 文件中配置 `http_allowed_urls`,并在 调度器 -> 修改通用配置 中启用
146
+ // 提示: 需要在 `manifest.json` 文件中配置 `http_allowed_urls`,并在 调度器 -> 修改通用配置 中启用
147
147
  const body1 = await getForBody("https://example.com/", undefined, { "User-Agent": "BetterGI" });
148
148
  const body2 = await postForBody("https://example.com/", undefined, { "User-Agent": "BetterGI" });
149
149
  log.info(`GET 请求响应体内容${body1}`);
package/dist/game.d.ts CHANGED
@@ -3,11 +3,11 @@ import { ListView } from "./ocr";
3
3
  * 临时设置游戏分辨率和DPI缩放比例,执行指定动作后恢复
4
4
  * 适用于使用了鼠标移动的操作,保证在不同的分辨率和DPI下都能正确地复现鼠标操作
5
5
  * @param w 游戏宽度
6
- * @param y 游戏高度
6
+ * @param h 游戏高度
7
7
  * @param dpi 系统屏幕的DPI缩放比例
8
8
  * @param action 执行动作
9
9
  */
10
- export declare const withGameMetrics: <T>(w: number, y: number, dpi: number, action: () => Promise<T> | T) => Promise<T>;
10
+ export declare const withGameMetrics: <T>(w: number, h: number, dpi: number, action: () => Promise<T> | T) => Promise<T>;
11
11
  /**
12
12
  * 打开派蒙菜单
13
13
  */
@@ -27,12 +27,17 @@ export declare const openMenu: (name: "\u62CD\u7167" | "\u516C\u544A" | "\u90AE\
27
27
  * @param name 菜单页面名称
28
28
  * @param listView 菜单页面视图参数
29
29
  */
30
- export declare const openMenuPage: (name: string, listView?: ListView) => Promise<void>;
30
+ export declare const openMenuPage: (name: "\u5546\u57CE" | "\u961F\u4F0D\u914D\u7F6E" | "\u597D\u53CB" | "\u6210\u5C31" | "\u56FE\u9274" | "\u89D2\u8272\u56FE\u9274" | "\u89D2\u8272" | "\u63D0\u5347\u6307\u5357" | "\u80CC\u5305" | "\u4EFB\u52A1" | "\u5730\u56FE" | "\u6D3B\u52A8" | "\u5192\u9669\u4E4B\u8BC1" | "\u7948\u613F" | "\u7EAA\u884C" | "\u591A\u4EBA\u6E38\u620F" | "\u5343\u661F\u5546\u57CE" | "\u4EBA\u6C14\u5947\u57DF" | "\u5947\u57DF\u6536\u85CF" | "\u6211\u7684\u5947\u57DF" | "\u5927\u5385" | "\u88C5\u626E\u642D\u914D" | "\u9882\u613F" | "\u7EAA\u6E38" | (string & {}), listView?: ListView) => Promise<void>;
31
31
  type ClockOptions = {
32
+ /** 时钟中心X坐标 */
32
33
  centerX?: number;
34
+ /** 时钟中心Y坐标 */
33
35
  centerY?: number;
36
+ /** 偏移小时数(默认: 6) */
34
37
  offsetHours?: number;
38
+ /** 时钟半径(默认: 154) */
35
39
  radius?: number;
40
+ /** 平滑度(默认: 3) */
36
41
  smooth?: number;
37
42
  };
38
43
  /**
package/dist/game.js CHANGED
@@ -5,14 +5,14 @@ import { findTextInDirection, findTextWithinBounds, findTextWithinListView } fro
5
5
  * 临时设置游戏分辨率和DPI缩放比例,执行指定动作后恢复
6
6
  * 适用于使用了鼠标移动的操作,保证在不同的分辨率和DPI下都能正确地复现鼠标操作
7
7
  * @param w 游戏宽度
8
- * @param y 游戏高度
8
+ * @param h 游戏高度
9
9
  * @param dpi 系统屏幕的DPI缩放比例
10
10
  * @param action 执行动作
11
11
  */
12
- export const withGameMetrics = async (w, y, dpi, action) => {
12
+ export const withGameMetrics = async (w, h, dpi, action) => {
13
13
  const { width, height, screenDpiScale } = genshin;
14
14
  try {
15
- setGameMetrics(w, y, dpi);
15
+ setGameMetrics(w, h, dpi);
16
16
  return await action();
17
17
  }
18
18
  finally {
@@ -26,7 +26,7 @@ export const openPaimonMenu = async () => {
26
26
  // 1.返回主界面
27
27
  await genshin.returnMainUi();
28
28
  // 2.打开派蒙菜单
29
- await assertRegionAppearing(() => findTextWithinBounds("世界等级", 300, 230, 440, 100), "打开派蒙菜单超时", () => keyPress("ESCAPE"));
29
+ await assertRegionAppearing(() => findTextWithinBounds("生日", 300, 230, 440, 100), "打开派蒙菜单超时", () => keyPress("ESCAPE"));
30
30
  };
31
31
  /**
32
32
  * 打开游戏菜单(左侧按钮)
package/dist/mouse.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  type MouseWaypointsOptions = {
2
+ /** 是否按住鼠标左键拖动 */
2
3
  shouldDrag?: boolean;
4
+ /** 超时时间(毫秒,默认: 不超时) */
3
5
  timeout?: number;
4
6
  };
5
7
  /**
@@ -21,13 +23,13 @@ export declare const mouseMoveAlongWaypoints: (waypoints: {
21
23
  */
22
24
  export declare const mouseDrag: (x1: number, y1: number, x2: number, y2: number) => Promise<boolean>;
23
25
  type NaturalMouseMoveOptions = {
24
- /** 移动持续时间(毫秒) */
26
+ /** 移动持续时间(毫秒,默认: 800) */
25
27
  duration: number;
26
- /** 摆动幅度(像素) */
28
+ /** 摆动幅度(默认: 30) */
27
29
  wiggle?: number;
28
- /** 随机种子 */
30
+ /** 随机种子(可选) */
29
31
  seed?: number;
30
- /** 缓动函数 */
32
+ /** 缓动函数(默认: ease-out-cubic) */
31
33
  easing?: (progress: number) => number;
32
34
  };
33
35
  /** 贝塞尔曲线生成鼠标移动路径点 */
package/dist/ocr.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RetryOptions } from "./workflow";
2
- type MatchDirection = "north" | "north-east" | "east" | "south-east" | "south" | "south-west" | "west" | "north-west";
2
+ type MatchDirection = "north" /** 上半边 */ | "north-east" /** 右上四分之一 */ | "east" /** 右半边 */ | "south-east" /** 右下四分之一 */ | "south" /** 下半边 */ | "south-west" /** 左下四分之一 */ | "west" /** 左半边 */ | "north-west"; /** 左上四分之一 */
3
3
  /**
4
4
  * 在整个画面内搜索图片
5
5
  * @param path 图片路径
@@ -25,9 +25,9 @@ export declare const findImageWithinBounds: (path: string, x: number, y: number,
25
25
  export declare const findImageInDirection: (path: string, direction: MatchDirection) => Region | undefined;
26
26
  /** 文本搜索选项 */
27
27
  type TextMatchOptions = {
28
- /** 是否忽略大小写(默认:是) */
28
+ /** 是否忽略大小写(默认: 是) */
29
29
  ignoreCase?: boolean;
30
- /** 是否非完全匹配(默认:否) */
30
+ /** 是否非完全匹配(默认: 否) */
31
31
  contains?: boolean;
32
32
  };
33
33
  /**
@@ -64,11 +64,11 @@ export type ListView = {
64
64
  h: number;
65
65
  /** 列表项高度 */
66
66
  lineHeight: number;
67
- /** 每次滚动的行数 */
67
+ /** 每次滚动的行数(默认: 1) */
68
68
  scrollLines?: number;
69
- /** 横向内边距 */
69
+ /** 横向内边距 (默认: 10) */
70
70
  paddingX?: number;
71
- /** 纵向内边距 */
71
+ /** 纵向内边距 (默认: 10) */
72
72
  paddingY?: number;
73
73
  };
74
74
  /**
package/dist/ocr.js CHANGED
@@ -135,7 +135,7 @@ export const findTextWithinListView = async (text, listView, matchOptions, retry
135
135
  return false;
136
136
  }
137
137
  }
138
- // 异常情况:找不到任何文本
138
+ // 异常情况: 找不到任何文本
139
139
  return true;
140
140
  };
141
141
  const isTextFoundOrBottomReached = await waitForAction(() => findTargetText() != undefined || isReachedBottom(), async () => {
@@ -1,8 +1,8 @@
1
1
  export type Action = () => Promise<void> | void;
2
2
  export type RetryOptions = {
3
- /** 重试次数 */
3
+ /** 重试次数(默认: 5) */
4
4
  maxAttempts?: number;
5
- /** 重试间隔(毫秒) */
5
+ /** 重试间隔(毫秒,默认: 1000) */
6
6
  retryInterval?: number;
7
7
  };
8
8
  /**
package/dist/workflow.js CHANGED
@@ -13,10 +13,12 @@ const defaultRetryInterval = 1000;
13
13
  export const waitForAction = async (condition, retryAction, options) => {
14
14
  const { maxAttempts = defaultMaxAttempts, retryInterval = defaultRetryInterval } = options || {};
15
15
  for (let i = 0; i < maxAttempts; i++) {
16
- if (condition())
17
- return true;
16
+ if (i === 0 && condition())
17
+ return true; // fast path
18
18
  await retryAction?.();
19
19
  await sleep(retryInterval);
20
+ if (condition())
21
+ return true;
20
22
  }
21
23
  return false;
22
24
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettergi/utils",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "开发 BetterGI 脚本常用工具集",
5
5
  "type": "module",
6
6
  "author": "Bread Grocery<https://github.com/breadgrocery>",
package/dist/flow.d.ts DELETED
@@ -1,30 +0,0 @@
1
- /**
2
- * 等待直到条件满足或超时
3
- * @param condition 等待的条件判断函数,返回 true 表示条件满足
4
- * @param timeout 超时时间(毫秒),默认 3000 毫秒
5
- * @param interval 等待间隔(毫秒),默认 300 毫秒
6
- * @param action 每次等待循环中执行的操作(可选)
7
- * @returns - true 在超时前条件已满足
8
- * - false 在超时后条件仍未满足
9
- */
10
- export declare const waitUntil: (condition: (context: Record<string, any>) => boolean, timeout?: number, interval?: number, action?: (context: Record<string, any>) => Promise<void> | void) => Promise<boolean>;
11
- /**
12
- * 断言区域存在
13
- * @param 获取区域的函数
14
- * @param message 错误信息
15
- * @param timeout 超时时间(毫秒),默认 3000 毫秒
16
- * @param interval 等待间隔(毫秒),默认 300 毫秒
17
- * @param action 每次等待循环中执行的操作(可选)
18
- * @throws 如果区域在超时时间内未找到则抛出错误
19
- */
20
- export declare const assertExists: (regionProvider: () => Region | undefined, message?: string, timeout?: number, interval?: number, action?: (context: Record<string, any>) => Promise<void> | void) => Promise<void>;
21
- /**
22
- * 断言区域不存在
23
- * @param 获取区域的函数
24
- * @param message 错误信息
25
- * @param timeout 超时时间(毫秒),默认 3000 毫秒
26
- * @param interval 等待间隔(毫秒),默认 300 毫秒
27
- * @param action 每次等待循环中执行的操作(可选)
28
- * @throws 如果区域在超时时间内仍然存在则抛出错误
29
- */
30
- export declare const assertNotExists: (regionProvider: () => Region | undefined, message?: string, timeout?: number, interval?: number, action?: (context: Record<string, any>) => Promise<void> | void) => Promise<void>;
package/dist/flow.js DELETED
@@ -1,52 +0,0 @@
1
- /** 默认超时时间(毫秒) */
2
- const defaultTimeout = 3 * 1000;
3
- /** 默认等待间隔(毫秒) */
4
- const defaultInterval = 300;
5
- /**
6
- * 等待直到条件满足或超时
7
- * @param condition 等待的条件判断函数,返回 true 表示条件满足
8
- * @param timeout 超时时间(毫秒),默认 3000 毫秒
9
- * @param interval 等待间隔(毫秒),默认 300 毫秒
10
- * @param action 每次等待循环中执行的操作(可选)
11
- * @returns - true 在超时前条件已满足
12
- * - false 在超时后条件仍未满足
13
- */
14
- export const waitUntil = async (condition, timeout = defaultTimeout, interval = defaultInterval, action) => {
15
- const context = {};
16
- const deadline = Date.now() + timeout;
17
- while (Date.now() < deadline) {
18
- if (condition(context))
19
- return true;
20
- await action?.(context);
21
- await sleep(interval);
22
- }
23
- return false;
24
- };
25
- /**
26
- * 断言区域存在
27
- * @param 获取区域的函数
28
- * @param message 错误信息
29
- * @param timeout 超时时间(毫秒),默认 3000 毫秒
30
- * @param interval 等待间隔(毫秒),默认 300 毫秒
31
- * @param action 每次等待循环中执行的操作(可选)
32
- * @throws 如果区域在超时时间内未找到则抛出错误
33
- */
34
- export const assertExists = async (regionProvider, message = "断言区域存在失败", timeout = defaultTimeout, interval = defaultInterval, action) => {
35
- const ok = await waitUntil(() => regionProvider() !== undefined, timeout, interval, action);
36
- if (!ok)
37
- throw new Error(message);
38
- };
39
- /**
40
- * 断言区域不存在
41
- * @param 获取区域的函数
42
- * @param message 错误信息
43
- * @param timeout 超时时间(毫秒),默认 3000 毫秒
44
- * @param interval 等待间隔(毫秒),默认 300 毫秒
45
- * @param action 每次等待循环中执行的操作(可选)
46
- * @throws 如果区域在超时时间内仍然存在则抛出错误
47
- */
48
- export const assertNotExists = async (regionProvider, message = "断言区域不存在失败", timeout = defaultTimeout, interval = defaultInterval, action) => {
49
- const ok = await waitUntil(() => regionProvider() === undefined, timeout, interval, action);
50
- if (!ok)
51
- throw new Error(message);
52
- };