@bettergi/utils 0.0.1 → 0.0.3

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
@@ -1,21 +1,81 @@
1
- Utils for [Better Genshin Impact](https://github.com/babalae/better-genshin-impact) JavaScript development.
1
+ 本项目是一个为[Better Genshin Impact](https://github.com/babalae/better-genshin-impact) 设计的 JavaScript 开发工具函数,旨在帮助开发者简化代码。
2
2
 
3
- ## Installation
3
+ ## 安装
4
4
 
5
5
  ```shell
6
6
  npm install @bettergi/utils
7
7
  ```
8
8
 
9
- ## Example
9
+ ## 函数清单
10
+
11
+ ### 图文识别
12
+
13
+ > 对 RecognitionObject 代码的封装,对于简单的 OCR 操作,无需写复杂的代码。
10
14
 
11
15
  ```ts
12
- import { findImage } from "@bettergi/utils";
16
+ import {
17
+ findImage,
18
+ findImageInDirection,
19
+ findImageWithinBounds,
20
+ findText,
21
+ findTextInDirection,
22
+ findTextWithinBounds
23
+ } from "@bettergi/utils";
24
+
25
+ // 在整个画面内搜索图片,找不到返回 undefined
26
+ const f1 = findImage("assets/关闭.png");
27
+
28
+ // 在指定方向上搜索图片,找不到返回 undefined
29
+ const f2 = findImageInDirection("assets/关闭.png", "north-east");
30
+
31
+ // 在指定区域内搜索图片,找不到返回 undefined
32
+ const f3 = findImageWithinBounds("assets/关闭.png", 960, 0, 960, 1080);
33
+
34
+ // 在整个画面内搜索文本(不包含、忽略大小写),找不到返回 undefined
35
+ const t1 = findText("购买", false, true);
36
+
37
+ // 在指定方向上搜索文本(包含、忽略大小写),找不到返回 undefined
38
+ const t2 = findTextInDirection("师傅", true, true, "east");
39
+
40
+ // 在指定区域内搜索文本(不包含、忽略大小写),找不到返回 undefined
41
+ const t3 = findTextWithinBounds("确认", false, true, 960, 540, 960, 540);
42
+ ```
43
+
44
+ ### 行为
13
45
 
14
- const mailIcon = findImage("./assets/mail.png");
46
+ > 对脚本工作流中常见行为的抽象,例如:等待 XXX 完成/出现/消失。
47
+
48
+ ```ts
49
+ import { findImageInDirection, waitUntil } from "@bettergi/utils";
15
50
 
16
- mailIcon?.click();
51
+ // 等待直到找不到[关闭按钮] 或 5秒后超时,每隔1秒检查一次,期间按 Esc 键
52
+ const done = await waitUntil(
53
+ () => findImageInDirection("assets/关闭.png", "north-east") !== undefined,
54
+ 5000,
55
+ 1000,
56
+ () => keyPress("ESCAPE")
57
+ );
58
+ if (!done) throw new Error("关闭页面");
17
59
  ```
18
60
 
19
- ## Related Tools
61
+ ### 存储
20
62
 
21
- [@bettergi/create-script](https://www.npmjs.com/package/@bettergi/create-script)
63
+ > 对象数据持久化,通过代理实现自动存储。可以无感知地读取/更新数据,而无需考虑如何持久化。
64
+
65
+ ```ts
66
+ import { useStore } from "@bettergi/utils";
67
+
68
+ // 创建/读取存储对象,保存到存储文件 store/state.json 中
69
+ // 通过Proxy来实现:对存储对象的操作会同步保存到存储文件
70
+ const state = useStore<{ lastUsedTime?: number; count: number }>("state");
71
+ if (state?.lastUsedTime) {
72
+ log.info(`欢迎回来!上次使用时间:${state.lastUsedTime},计数器已累计至:${state.count}`);
73
+ }
74
+ try {
75
+ for (let i = 0; i < Math.floor(Math.random() * 100); i++) {
76
+ state.count = (state.count || 0) + 1; // 同步保存到文件
77
+ }
78
+ } finally {
79
+ state.lastUsedTime = Date.now(); // 同步保存到文件
80
+ }
81
+ ```
package/dist/action.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * @param timeout 超时时间(毫秒),默认 5000 毫秒
5
5
  * @param interval 等待间隔(毫秒),默认 200 毫秒
6
6
  * @param action 每次等待循环中执行的操作(可选)
7
- * @returns - true 在超时前条件已满足
7
+ * @returns - true 在超时前条件已满足
8
8
  * - false 在超时后条件仍未满足
9
9
  */
10
- export declare const waitUntil: (condition: () => boolean, timeout?: number, interval?: number, action?: () => void) => Promise<boolean>;
10
+ export declare const waitUntil: (condition: (context: Record<string, any>) => boolean, timeout?: number, interval?: number, action?: (context: Record<string, any>) => void) => Promise<boolean>;
package/dist/action.js CHANGED
@@ -4,15 +4,16 @@
4
4
  * @param timeout 超时时间(毫秒),默认 5000 毫秒
5
5
  * @param interval 等待间隔(毫秒),默认 200 毫秒
6
6
  * @param action 每次等待循环中执行的操作(可选)
7
- * @returns - true 在超时前条件已满足
7
+ * @returns - true 在超时前条件已满足
8
8
  * - false 在超时后条件仍未满足
9
9
  */
10
10
  export const waitUntil = async (condition, timeout, interval, action) => {
11
+ const context = {};
11
12
  const deadline = Date.now() + (timeout ?? 5 * 1000);
12
13
  while (Date.now() < deadline) {
13
- if (condition())
14
+ if (condition(context))
14
15
  return true;
15
- action?.();
16
+ action?.(context);
16
17
  await sleep(interval ?? 200);
17
18
  }
18
19
  return false;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./action";
2
2
  export * from "./mouse";
3
3
  export * from "./ocr";
4
+ export * from "./store";
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./action";
2
2
  export * from "./mouse";
3
3
  export * from "./ocr";
4
+ export * from "./store";
package/dist/ocr.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { type Region } from "@bettergi/types/csharp/BetterGenshinImpact/GameTask/Model/Area/Region";
2
+ type Direction = "north" | "north-east" | "east" | "south-east" | "south" | "south-west" | "west" | "north-west";
2
3
  /**
3
- * 搜索图片
4
+ * 在整个画面内搜索图片
4
5
  * @param path 图片路径
5
6
  * @returns 如果找到匹配的图片区域,则返回该区域,否则返回 undefined
6
7
  */
@@ -8,15 +9,22 @@ export declare const findImage: (path: string) => Region | undefined;
8
9
  /**
9
10
  * 在指定区域内搜索图片
10
11
  * @param path 图片路径
11
- * @param x - 水平移动偏移量(像素)
12
- * @param y - 垂直移动偏移量(像素)
12
+ * @param x - 水平方向偏移量(像素)
13
+ * @param y - 垂直方向偏移量(像素)
13
14
  * @param w 宽度
14
15
  * @param h 高度
15
16
  * @returns 如果找到匹配的图片区域,则返回该区域,否则返回 undefined
16
17
  */
17
18
  export declare const findImageWithinBounds: (path: string, x: number, y: number, w: number, h: number) => Region | undefined;
18
19
  /**
19
- * 搜索文本
20
+ * 在指定方向上搜索图片
21
+ * @param path 图片路径
22
+ * @param direction 搜索方向
23
+ * @returns 如果找到匹配的图片区域,则返回该区域,否则返回 undefined
24
+ */
25
+ export declare const findImageInDirection: (path: string, direction: Direction) => Region | undefined;
26
+ /**
27
+ * 在整个画面内搜索文本
20
28
  * @param text 待搜索文本
21
29
  * @param contains 是否包含
22
30
  * @param ignoreCase 是否忽略大小写
@@ -28,11 +36,21 @@ export declare const findText: (text: string, contains: boolean, ignoreCase: boo
28
36
  * @param text 待搜索文本
29
37
  * @param contains 是否包含
30
38
  * @param ignoreCase 是否忽略大小写
31
- * @param x 水平移动偏移量(像素)
32
- * @param x - 水平移动偏移量(像素)
33
- * @param y - 垂直移动偏移量(像素)
39
+ * @param x 水平方向偏移量(像素)
40
+ * @param x - 水平方向偏移量(像素)
41
+ * @param y - 垂直方向偏移量(像素)
34
42
  * @param w 宽度
35
43
  * @param h 高度
36
44
  * @returns 如果找到匹配的文本区域,则返回该区域,否则返回 undefined
37
45
  */
38
46
  export declare const findTextWithinBounds: (text: string, contains: boolean, ignoreCase: boolean, x: number, y: number, w: number, h: number) => Region | undefined;
47
+ /**
48
+ * 在指定方向上搜索文本
49
+ * @param text 待搜索文本
50
+ * @param contains 是否包含
51
+ * @param ignoreCase 是否忽略大小写
52
+ * @param direction 搜索方向
53
+ * @returns 如果找到匹配的文本区域,则返回该区域,否则返回 undefined
54
+ */
55
+ export declare const findTextInDirection: (text: string, contains: boolean, ignoreCase: boolean, direction: Direction) => Region | undefined;
56
+ export {};
package/dist/ocr.js CHANGED
@@ -1,22 +1,28 @@
1
- const findFirst = (im, ro, predicate) => {
2
- const candidates = im.findMulti(ro);
1
+ const findFirst = (ir, ro, predicate) => {
2
+ const candidates = ir.findMulti(ro);
3
3
  for (let i = 0; i < candidates.count; i++) {
4
- if (predicate(candidates[i])) {
4
+ if (predicate(candidates[i]))
5
5
  return candidates[i];
6
- }
7
6
  }
8
7
  return undefined;
9
8
  };
9
+ const directionToBounds = (direction) => {
10
+ const x = direction.includes("east") ? genshin.width / 2 : 0;
11
+ const y = direction.includes("south") ? genshin.height / 2 : 0;
12
+ const w = direction === "north" || direction === "south" ? genshin.width : genshin.width / 2;
13
+ const h = direction === "west" || direction === "east" ? genshin.height : genshin.height / 2;
14
+ return { x, y, w, h };
15
+ };
10
16
  /**
11
- * 搜索图片
17
+ * 在整个画面内搜索图片
12
18
  * @param path 图片路径
13
19
  * @returns 如果找到匹配的图片区域,则返回该区域,否则返回 undefined
14
20
  */
15
21
  export const findImage = (path) => {
16
22
  try {
17
- const im = captureGameRegion();
23
+ const ir = captureGameRegion();
18
24
  const ro = RecognitionObject.templateMatch(file.readImageMatSync(path));
19
- return findFirst(im, ro, region => region.isExist());
25
+ return findFirst(ir, ro, region => region.isExist());
20
26
  }
21
27
  catch (err) {
22
28
  err?.message && log.warn(`${err.message}`);
@@ -25,24 +31,34 @@ export const findImage = (path) => {
25
31
  /**
26
32
  * 在指定区域内搜索图片
27
33
  * @param path 图片路径
28
- * @param x - 水平移动偏移量(像素)
29
- * @param y - 垂直移动偏移量(像素)
34
+ * @param x - 水平方向偏移量(像素)
35
+ * @param y - 垂直方向偏移量(像素)
30
36
  * @param w 宽度
31
37
  * @param h 高度
32
38
  * @returns 如果找到匹配的图片区域,则返回该区域,否则返回 undefined
33
39
  */
34
40
  export const findImageWithinBounds = (path, x, y, w, h) => {
35
41
  try {
36
- const im = captureGameRegion();
42
+ const ir = captureGameRegion();
37
43
  const ro = RecognitionObject.templateMatch(file.readImageMatSync(path), x, y, w, h);
38
- return findFirst(im, ro, region => region.isExist());
44
+ return findFirst(ir, ro, region => region.isExist());
39
45
  }
40
46
  catch (err) {
41
47
  err?.message && log.warn(`${err.message}`);
42
48
  }
43
49
  };
44
50
  /**
45
- * 搜索文本
51
+ * 在指定方向上搜索图片
52
+ * @param path 图片路径
53
+ * @param direction 搜索方向
54
+ * @returns 如果找到匹配的图片区域,则返回该区域,否则返回 undefined
55
+ */
56
+ export const findImageInDirection = (path, direction) => {
57
+ const { x, y, w, h } = directionToBounds(direction);
58
+ return findImageWithinBounds(path, x, y, w, h);
59
+ };
60
+ /**
61
+ * 在整个画面内搜索文本
46
62
  * @param text 待搜索文本
47
63
  * @param contains 是否包含
48
64
  * @param ignoreCase 是否忽略大小写
@@ -50,9 +66,9 @@ export const findImageWithinBounds = (path, x, y, w, h) => {
50
66
  */
51
67
  export const findText = (text, contains, ignoreCase) => {
52
68
  const searchText = ignoreCase ? text.toLowerCase() : text;
53
- const im = captureGameRegion();
69
+ const ir = captureGameRegion();
54
70
  const ro = RecognitionObject.ocrThis;
55
- return findFirst(im, ro, region => {
71
+ return findFirst(ir, ro, region => {
56
72
  const itemText = ignoreCase ? region.text.toLowerCase() : region.text;
57
73
  const isMatch = contains ? itemText.includes(searchText) : itemText === searchText;
58
74
  return isMatch && region.isExist();
@@ -63,20 +79,32 @@ export const findText = (text, contains, ignoreCase) => {
63
79
  * @param text 待搜索文本
64
80
  * @param contains 是否包含
65
81
  * @param ignoreCase 是否忽略大小写
66
- * @param x 水平移动偏移量(像素)
67
- * @param x - 水平移动偏移量(像素)
68
- * @param y - 垂直移动偏移量(像素)
82
+ * @param x 水平方向偏移量(像素)
83
+ * @param x - 水平方向偏移量(像素)
84
+ * @param y - 垂直方向偏移量(像素)
69
85
  * @param w 宽度
70
86
  * @param h 高度
71
87
  * @returns 如果找到匹配的文本区域,则返回该区域,否则返回 undefined
72
88
  */
73
89
  export const findTextWithinBounds = (text, contains, ignoreCase, x, y, w, h) => {
74
90
  const searchText = ignoreCase ? text.toLowerCase() : text;
75
- const im = captureGameRegion();
91
+ const ir = captureGameRegion();
76
92
  const ro = RecognitionObject.ocr(x, y, w, h);
77
- return findFirst(im, ro, region => {
93
+ return findFirst(ir, ro, region => {
78
94
  const itemText = ignoreCase ? region.text.toLowerCase() : region.text;
79
95
  const isMatch = contains ? itemText.includes(searchText) : itemText === searchText;
80
96
  return isMatch && region.isExist();
81
97
  });
82
98
  };
99
+ /**
100
+ * 在指定方向上搜索文本
101
+ * @param text 待搜索文本
102
+ * @param contains 是否包含
103
+ * @param ignoreCase 是否忽略大小写
104
+ * @param direction 搜索方向
105
+ * @returns 如果找到匹配的文本区域,则返回该区域,否则返回 undefined
106
+ */
107
+ export const findTextInDirection = (text, contains, ignoreCase, direction) => {
108
+ const { x, y, w, h } = directionToBounds(direction);
109
+ return findTextWithinBounds(text, contains, ignoreCase, x, y, w, h);
110
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 创建一个持久化存储对象,用于管理应用状态数据
3
+ * 该函数会创建一个代理对象,对该对象的所有属性的修改都会自动同步到相应的JSON文件(脚本的 `store` 目录下)中。
4
+ * @param name 存储对象的名称,将作为文件名(不包扩展名)
5
+ */
6
+ export declare const useStore: <T extends Record<string, any>>(name: string) => T;
package/dist/store.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 创建一个持久化存储对象,用于管理应用状态数据
3
+ * 该函数会创建一个代理对象,对该对象的所有属性的修改都会自动同步到相应的JSON文件(脚本的 `store` 目录下)中。
4
+ * @param name 存储对象的名称,将作为文件名(不包扩展名)
5
+ */
6
+ export const useStore = (name) => {
7
+ const path = `store/${name}.json`;
8
+ const obj = (() => {
9
+ try {
10
+ const text = file.readTextSync(path);
11
+ return JSON.parse(text);
12
+ }
13
+ catch {
14
+ return {};
15
+ }
16
+ })();
17
+ return new Proxy(obj, {
18
+ set: (target, key, value) => Reflect.set(target, key, value) && file.writeTextSync(path, JSON.stringify(target, null, 2))
19
+ });
20
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettergi/utils",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Utils for BetterGI JavaScript Development",
5
5
  "type": "module",
6
6
  "author": "Bread Grocery<https://github.com/breadgrocery>",
@@ -1 +0,0 @@
1
- export declare const verticalScroll: (scrollAmountInClicks: number) => void;
package/dist/polyfill.js DELETED
@@ -1,10 +0,0 @@
1
- import { _simulateScroll } from "./mouse";
2
- export const verticalScroll = (scrollAmountInClicks) => {
3
- // @ts-ignore
4
- if (globalThis.verticalScroll) {
5
- globalThis.verticalScroll(scrollAmountInClicks);
6
- }
7
- else {
8
- _simulateScroll(scrollAmountInClicks, 1);
9
- }
10
- };