create-genshin-ts 0.1.0

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 ADDED
@@ -0,0 +1,9 @@
1
+ # create-genshin-ts
2
+
3
+ Scaffold a Genshin-TS project.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npm create genshin-ts
9
+ ```
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs/promises'
3
+ import path from 'node:path'
4
+ import readline from 'node:readline'
5
+ import { fileURLToPath } from 'node:url'
6
+
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
8
+
9
+ const args = process.argv.slice(2)
10
+ const flags = new Set(args.filter((arg) => arg.startsWith('--')))
11
+ const nameArg = args.find((arg) => !arg.startsWith('--')) ?? ''
12
+ const force = flags.has('--force')
13
+
14
+ const toPackageName = (input) => {
15
+ const base = input.trim().toLowerCase()
16
+ const sanitized = base
17
+ .replace(/\s+/g, '-')
18
+ .replace(/[^a-z0-9-._]/g, '-')
19
+ .replace(/^-+/g, '')
20
+ .replace(/-+/g, '-')
21
+ .replace(/^[_\.]+/g, '')
22
+ return sanitized || 'gsts-project'
23
+ }
24
+
25
+ const prompt = async (question) => {
26
+ const rl = readline.createInterface({
27
+ input: process.stdin,
28
+ output: process.stdout
29
+ })
30
+ return new Promise((resolve) => {
31
+ rl.question(question, (answer) => {
32
+ rl.close()
33
+ resolve(answer)
34
+ })
35
+ })
36
+ }
37
+
38
+ const resolveTargetDir = async () => {
39
+ if (nameArg) return nameArg
40
+ const answer = await prompt('Project name: ')
41
+ return answer.trim()
42
+ }
43
+
44
+ const replacePlaceholders = (content, values) => {
45
+ return content
46
+ .replace(/__PROJECT_NAME__/g, values.projectName)
47
+ .replace(/__PACKAGE_NAME__/g, values.packageName)
48
+ }
49
+
50
+ const copyDir = async (sourceDir, targetDir, values) => {
51
+ await fs.mkdir(targetDir, { recursive: true })
52
+ const entries = await fs.readdir(sourceDir, { withFileTypes: true })
53
+ for (const entry of entries) {
54
+ const srcPath = path.join(sourceDir, entry.name)
55
+ const targetName = entry.name === '_gitignore' ? '.gitignore' : entry.name
56
+ const destPath = path.join(targetDir, targetName)
57
+ if (entry.isDirectory()) {
58
+ await copyDir(srcPath, destPath, values)
59
+ } else {
60
+ const raw = await fs.readFile(srcPath, 'utf8')
61
+ const content = replacePlaceholders(raw, values)
62
+ await fs.writeFile(destPath, content, 'utf8')
63
+ }
64
+ }
65
+ }
66
+
67
+ const run = async () => {
68
+ const projectName = await resolveTargetDir()
69
+ if (!projectName) {
70
+ console.error('Project name is required.')
71
+ process.exit(1)
72
+ }
73
+
74
+ const targetDir = path.resolve(process.cwd(), projectName)
75
+ try {
76
+ const stat = await fs.stat(targetDir)
77
+ if (stat.isDirectory()) {
78
+ const existing = await fs.readdir(targetDir)
79
+ if (existing.length > 0 && !force) {
80
+ console.error('Target directory is not empty. Use --force to overwrite.')
81
+ process.exit(1)
82
+ }
83
+ }
84
+ } catch (err) {
85
+ if (err?.code !== 'ENOENT') throw err
86
+ }
87
+
88
+ const values = {
89
+ projectName,
90
+ packageName: toPackageName(path.basename(projectName))
91
+ }
92
+
93
+ const templateDir = path.resolve(__dirname, '../templates/start')
94
+ await copyDir(templateDir, targetDir, values)
95
+
96
+ console.log(`\nCreated ${values.projectName}`)
97
+ console.log('\nNext steps:')
98
+ console.log(` cd ${values.projectName}`)
99
+ console.log(' npm install')
100
+ console.log(' npm run dev')
101
+ }
102
+
103
+ run().catch((err) => {
104
+ console.error(err)
105
+ process.exit(1)
106
+ })
package/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "create-genshin-ts",
3
+ "version": "0.1.0",
4
+ "description": "Create a Genshin-TS project",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-genshin-ts": "bin/create-genshin-ts.mjs"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "templates",
12
+ "README.md"
13
+ ]
14
+ }
@@ -0,0 +1,9 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ indent_style = space
7
+ indent_size = 2
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = true
@@ -0,0 +1,12 @@
1
+ export default {
2
+ singleQuote: true,
3
+ semi: false,
4
+ printWidth: 100,
5
+ trailingComma: 'none',
6
+ endOfLine: 'lf',
7
+ tabWidth: 2,
8
+ importOrder: ['', '<BUILTIN_MODULES>', '', '<THIRD_PARTY_MODULES>', '', '^[./]'],
9
+ importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'],
10
+ importOrderTypeScriptVersion: '5.0.0',
11
+ plugins: ['@ianvs/prettier-plugin-sort-imports']
12
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
3
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "editor.formatOnSave": true,
3
+ "[typescript]": {
4
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
5
+ },
6
+ "[javascript]": {
7
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
8
+ },
9
+ "[json]": {
10
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
11
+ },
12
+ "[typescriptreact]": {
13
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
14
+ },
15
+ "[javascriptreact]": {
16
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
17
+ },
18
+ "search.exclude": {
19
+ "package-lock.json": true
20
+ },
21
+ "files.eol": "\n"
22
+ }
@@ -0,0 +1,48 @@
1
+ # Repository Guidelines
2
+
3
+ This template bootstraps a Genshin-TS project. Maintain it with user workflow and compile outputs in mind.
4
+
5
+ ## Read First
6
+ - `README.md`: full usage flow, constraints, and global function cheat sheet.
7
+
8
+ ## Layout
9
+ - `src/main.ts`: default entry example
10
+ - `gsts.config.ts`: compile config (entries/outDir/inject)
11
+ - `dist/`: build outputs (generated)
12
+ - `README.md`: user guide
13
+ - `CLAUDE.md`: AI rules
14
+
15
+ ## Typical Workflow
16
+ 1. Update the NodeGraph ID in `src/main.ts`
17
+ 2. Add `inject` in `gsts.config.ts` when needed
18
+ 3. Run `npm run dev` for incremental compile
19
+
20
+ ## Coding and Maintenance Rules
21
+ - Update `entries` when adding new entry files.
22
+ - Entry events use `g.server({ id }).on(...)`; same ID entries merge automatically.
23
+ - `gstsServer*` must be top-level and only allow a single trailing `return`.
24
+ - Avoid Promise/async/recursion/JSON/Object in graph scope.
25
+ - Conditions must be `boolean`; use `bool(...)` when needed.
26
+ - Use `bigint` for integer ops; avoid modulo/bitwise on `number`.
27
+ - `while(true)` is capped; use timers or explicit counters.
28
+ - Empty arrays must have inferable element types.
29
+ - Logging: use `print(str(...))` or `console.log(x)` (single argument).
30
+ - Use type helpers when needed: `int/float/str/bool/vec3/configId/prefabId/entity`.
31
+
32
+ ## Node Graph Variables
33
+ - Declare with `g.server({ variables: { ... } })`.
34
+ - Read/write via `f.get` / `f.set`, keep types aligned.
35
+
36
+ ## Debugging Outputs
37
+ - `.gs.ts`: verify compiled node calls
38
+ - `.json`: verify connections and types
39
+ - `.gia`: final injectable output
40
+
41
+ ## Common Scripts
42
+ - `npm run dev`
43
+ - `npm run build`
44
+ - `npm run maps`
45
+ - `npm run backup`
46
+
47
+ ## Reference Definitions
48
+ - Search function/event comments in `node_modules/genshin-ts/dist/src/definitions/`.
@@ -0,0 +1,66 @@
1
+ # CLAUDE.md
2
+
3
+ This file guides AI to write/modify code and docs in this template. Focus on a compileable, injectable, and verifiable user workflow.
4
+
5
+ ## Read First
6
+ - `README.md`: complete usage flow, constraints, and global function cheat sheet.
7
+
8
+ ## Compilation Flow (Debugging)
9
+ 1. TS -> `.gs.ts` (node function call form)
10
+ 2. `.gs.ts` -> IR `.json` (nodes and connections)
11
+ 3. IR -> `.gia` (injectable output)
12
+
13
+ If something is wrong, compare `.gs.ts` and `.json` first.
14
+
15
+ ## Scope and Principles
16
+ - Focus on user-facing steps; explain why when needed.
17
+ - Provide alternatives for edge semantics (e.g., explicit conversions).
18
+ - Do not edit `dist/` outputs by hand.
19
+
20
+ ## Scope Rules (Critical)
21
+ - Top-level scope: OK to use npm/local files for precompute; do not call `g.server` or `gsts` runtime APIs here.
22
+ - Node graph scope (`g.server().on(...)` / `gstsServer*`): only a supported TS subset.
23
+ - Common APIs have type hints (events, entities, Math/Vector3, etc).
24
+ - If string concat/native objects fail, move to top-level precompute.
25
+
26
+ ## gstsServer Constraints
27
+ - Only top-level `gstsServer*` functions are recognized.
28
+ - Params must be identifiers (no destructuring/default/rest).
29
+ - Only a single trailing `return <expr>` is allowed.
30
+ - Calls only inside `g.server().on(...)` or another `gstsServer*`.
31
+
32
+ ## Syntax and Type Guidance
33
+ - Conditions must be `boolean`; use `bool(...)` if needed.
34
+ - `number` is float, `bigint` is int; use `bigint` for integer ops.
35
+ - Lists/dicts must be homogeneous; mixed types will fail.
36
+ - Empty arrays may not infer a type; add a typed placeholder.
37
+ - `dict(...)` is read-only; use graph variables for mutable dicts (`f.get` / `f.set`).
38
+ - `Object.*` / `JSON.*` are usually unsupported in graph scope; precompute or use `raw(...)` (compiler ignores, JS semantics).
39
+ - No Promise/async/await or recursion (errors or ESLint warnings).
40
+ - `while(true)` is capped; use timers or explicit counters.
41
+
42
+ ## Timers
43
+ - Use `setTimeout` / `setInterval` (milliseconds).
44
+ - Compiler builds timer pools; override with `// @gsts:timerPool=4`.
45
+ - `setInterval` <= 100ms triggers a performance warning.
46
+ - Timer callbacks support by-value captures; dict captures are not supported.
47
+
48
+ ## Global Function Preferences
49
+ - Logging: prefer `print(str(...))` or `console.log(x)` (single argument only).
50
+ - Type helpers: `int/float/str/bool/vec3/configId/prefabId/guid/faction/entity`.
51
+ - Collections: `list('int', [...])`, `dict(...)` (read-only).
52
+ - Unity-style APIs: `Math` / `Mathf` / `Vector3` / `Random` / `GameObject`.
53
+ - Global entities: `player(1)` / `stage` / `level` / `self`.
54
+
55
+ ## Variables and Language Hints
56
+ - `g.server({ variables: { ... } })` declares graph variables with typed `f.get` / `f.set`.
57
+ - `g.server({ lang: 'zh' })` enables Chinese event names and function aliases.
58
+
59
+ ## Common Commands
60
+ - `npm run dev`: incremental compile (auto inject if configured)
61
+ - `npm run build`: full compile
62
+ - `npm run maps`: list maps
63
+
64
+ ## Look Up Function/Event Notes
65
+ - Search `node_modules/genshin-ts/dist/src/definitions/` with keywords.
66
+ - Chinese and English alias keywords are supported.
@@ -0,0 +1,248 @@
1
+ # __PROJECT_NAME__
2
+
3
+ This is a Genshin-TS project template. You can write logic in TypeScript, compile it into a node graph, and inject it into a map.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npm install
9
+ npm run dev
10
+ ```
11
+
12
+ Docs: `https://gsts.moe`
13
+
14
+ ## Project Layout
15
+
16
+ - `src/main.ts`: entry example (`g.server(...).on(...)`)
17
+ - `gsts.config.ts`: compile/output configuration
18
+ - `dist/`: build outputs (`.gs.ts` / `.json` / `.gia`)
19
+ - `CLAUDE.md` / `AGENTS.md`: AI collaboration notes (read first)
20
+
21
+ ## Injection Config Example (Optional)
22
+
23
+ ```ts
24
+ import type { GstsConfig } from 'genshin-ts'
25
+
26
+ const config: GstsConfig = {
27
+ compileRoot: '.',
28
+ entries: ['./src'],
29
+ outDir: './dist',
30
+ inject: {
31
+ gameRegion: 'China',
32
+ playerId: 1,
33
+ mapId: 1073741849,
34
+ nodeGraphId: 1073741825
35
+ }
36
+ }
37
+
38
+ export default config
39
+ ```
40
+
41
+ Notes:
42
+ - `npm run maps` lists recently saved maps to help locate `mapId`.
43
+ - Fill `gameRegion` / `playerId` when you have multiple regions/accounts.
44
+ - Injection automatically creates backups for rollback.
45
+
46
+ ## Entry and Event Style
47
+
48
+ ```ts
49
+ import { g } from 'genshin-ts/runtime/core'
50
+
51
+ g.server({ id: 1073741825 }).on('whenEntityIsCreated', (_evt, f) => {
52
+ const p = player(1)
53
+ f.printString(str(p.guid))
54
+ })
55
+ ```
56
+
57
+ Key points:
58
+ - `id` is the target NodeGraph ID; entries with the same ID are merged.
59
+ - Event names use string literals (Chinese aliases are supported).
60
+ - `f` is the node graph function entry; use it for output and variables.
61
+ - You can chain multiple events: `g.server(...).on(...).onSignal(...)`.
62
+
63
+ ## g.server Options (Injection Safety)
64
+
65
+ Common options:
66
+ - `id`: target NodeGraph ID (injection must match this ID).
67
+ - `name`: graph display name; defaults to entry filename.
68
+ - `prefix`: auto add `_GSTS_` prefix (default true).
69
+ - `type`: graph type (default server/entity).
70
+ - `variables`: declare graph variables and enable `f.get` / `f.set`.
71
+ - `lang`: set `'zh'` to enable Chinese event names and function aliases.
72
+
73
+ Injection safety rules:
74
+ - The target `id` must exist in the map.
75
+ - The target graph must be empty or its name must start with `_GSTS`, otherwise injection is blocked.
76
+ - If you know what you are doing, set `inject.skipSafeCheck = true` in `gsts.config.ts`.
77
+ - After creating a new graph, you must save the map for the injector to detect the `id`.
78
+ - Recommended: create and save a batch of graphs first, then compile/inject once.
79
+
80
+ ## gsts.config Optimize Options (Enabled by Default)
81
+
82
+ `gsts.config.ts` uses `options.optimize` with all defaults on:
83
+ - `precompileExpression`: precompute literal-only expressions.
84
+ - `removeUnusedNodes`: remove unused exec/data nodes.
85
+ - `timerPool`: name pool size for `setTimeout` / `setInterval`.
86
+ - `timerDispatchAggregate`: aggregate timer dispatch to reduce complexity.
87
+
88
+ Disable an option temporarily if you need to debug or compare graphs.
89
+
90
+ ## Typical Usage and Constraints (AI Must Read)
91
+
92
+ ### Scope Split
93
+
94
+ - **Top-level scope (compile-time)**: OK to read files, use npm libs, precompute data; do not call `g.server` or `gsts` runtime APIs here.
95
+ - **Node graph scope (runtime)**: only a supported TS subset; logic is compiled into node graphs.
96
+
97
+ ### Control Flow and Returns
98
+
99
+ - `if/while/switch` conditions must be `boolean`; use `bool(...)` if needed.
100
+ - `gstsServer*` functions allow only a **single trailing `return <expr>`**.
101
+ - Recursion, `async/await`, and Promise are not supported in node graph scope.
102
+ - `while(true)` is limited by a loop cap; use timers or explicit counters instead.
103
+ - `!` and ternary require boolean conditions.
104
+
105
+ ### Numbers and Types
106
+
107
+ - `number` is **float**; `bigint` is **int**.
108
+ - Use `bigint` for modulo/bitwise operations.
109
+ - Lists/dicts must be homogeneous; mixed types will fail.
110
+ - Empty arrays may not infer a type; add a typed placeholder or use `list(...)`.
111
+ - Prefer explicit helpers: `int`, `float`, `vec3`, `configId`, `prefabId`, `entity`, etc.
112
+ - `dict(...)` creates a read-only dict; use graph variables for mutable dicts.
113
+ - Use `let` to force a local variable node; `const` may be optimized into direct wiring.
114
+
115
+ ### Global Functions and Variables Cheat Sheet (Preferred for AI)
116
+
117
+ Logging and debug:
118
+ - `print(str(...))`: most stable logging.
119
+ - `console.log(x)`: **single argument only**, auto-rewritten to `print(str(...))`.
120
+ - `f.printString(...)`: explicit node call for strict graph alignment.
121
+
122
+ Type helpers:
123
+ - `bool(...)` / `int(...)` / `float(...)` / `str(...)`
124
+ - `vec3(...)` / `guid(...)` / `prefabId(...)` / `configId(...)` / `faction(...)` / `entity(...)`
125
+ - `list('int', items)`: explicit list typing (critical for empty arrays).
126
+ - `dict(...)`: read-only dict.
127
+ - `raw(...)`: compiler ignores it; JS native semantics apply.
128
+
129
+ Entities and scene:
130
+ - `player(1)`: player entity (starts from 1).
131
+ - `stage` / `level`: stage entity aliases.
132
+ - `self`: current graph entity.
133
+ - `GameObject.Find(...)` / `FindWithTag(...)` / `FindByPrefabId(...)`
134
+
135
+ Math and vectors:
136
+ - `Math.*`: compiled to node graph equivalents in server scope.
137
+ - `Mathf.*` / `Vector3.*` / `Random.*`: Unity-style APIs.
138
+
139
+ Signals and events:
140
+ - `send('signalName')` with `g.server().onSignal(...)`.
141
+
142
+ Timers:
143
+ - `setTimeout` / `setInterval` / `clearTimeout` / `clearInterval`.
144
+
145
+ Common methods:
146
+ - Many array/string methods (`map`/`filter`/`find`/`length`) are supported; rely on type hints.
147
+
148
+ ### Node Graph Variables (Writable)
149
+
150
+ ```ts
151
+ g.server({
152
+ id: 1073741825,
153
+ variables: { counter: 0n },
154
+ lang: 'zh'
155
+ }).on('whenEntityIsCreated', (_evt, f) => {
156
+ const v = f.get('counter')
157
+ f.set('counter', v + 1n)
158
+ })
159
+ ```
160
+
161
+ Notes:
162
+ - `variables` defines graph variables and enables typed `f.get` / `f.set`.
163
+ - Entity variables are type declarations only (use `entity(0)`).
164
+ - `entity(0)` can also be used as a placeholder to keep entity params empty in the editor.
165
+
166
+ ### Timers
167
+
168
+ - Use `setTimeout` / `setInterval` (milliseconds).
169
+ - The compiler builds timer name pools to avoid name collisions.
170
+ - Use `// @gsts:timerPool=4` to override pool size (advanced).
171
+ - `setInterval` <= 100ms triggers a performance warning.
172
+ - Timer callbacks support value-based captures; dict captures are not supported.
173
+
174
+ ### Native JS Object Limits
175
+
176
+ - `Object.*` and `JSON.*` are typically not supported in node graph scope.
177
+ - Move them to top-level precompute, or use `raw(...)`.
178
+ - If string concatenation fails, precompute at top-level or use `str(...)`.
179
+
180
+ ## Reusable Functions (gstsServer)
181
+
182
+ ```ts
183
+ function gstsServerSum(a: bigint, b: bigint) {
184
+ const total = a + b
185
+ return total
186
+ }
187
+
188
+ g.server({ id: 1073741825 }).on('whenEntityIsCreated', (_evt, f) => {
189
+ const v = gstsServerSum(1n, 2n)
190
+ f.printString(str(v))
191
+ })
192
+ ```
193
+
194
+ Rules:
195
+ - Must be top-level; params must be identifiers (no destructuring/default/rest).
196
+ - Only a trailing single `return` is allowed.
197
+ - Calls only allowed inside `g.server().on(...)` or another `gstsServer*`.
198
+ - Inside `gstsServer*`, you can use `gsts.f` directly (no need to pass `f`).
199
+
200
+ ## Multi-Entry and Merging
201
+
202
+ - `entries` in `gsts.config.ts` determines which files compile.
203
+ - Each entry builds a graph; same ID entries are merged.
204
+ - In dev mode, dependency changes recompile affected entries.
205
+
206
+ ## Outputs and Debugging
207
+
208
+ - `.gs.ts`: expanded node function calls for semantic checking.
209
+ - `.json`: IR for node connections and type checks.
210
+ - `.gia`: final graph output for inject/import.
211
+
212
+ ## Compile-Time Execution Notes
213
+
214
+ - The compiler scans all entries and compiles `g.server().on(...)` points.
215
+ - Top-level code may execute once or multiple times (incremental builds, multi-entry).
216
+ - Be careful with file I/O or randomness in top-level scope.
217
+ - To temporarily disable a graph injection, set `id` to a non-existent value.
218
+ - Top-level scope is suitable for file loading, precompute, or procedural generation.
219
+ - `stage.set` can be used as a global variable (runtime).
220
+
221
+ ## Scripts
222
+
223
+ - `npm run build`: full compile
224
+ - `npm run dev`: incremental compile (auto inject if configured)
225
+ - `npm run maps`: list recent maps
226
+ - `npm run backup`: open backup directory
227
+ - `npm run typecheck`: TypeScript type check
228
+ - `npm run lint`: ESLint
229
+
230
+ Notes:
231
+ - The project includes custom ESLint rules; run `npm run lint` often to catch hidden constraints.
232
+ - `npm run typecheck` helps catch type issues before compile errors.
233
+ - `npm run dev` runs `gsts dev` watch mode only.
234
+ - After injection, reload the map to see changes.
235
+ - Use a temporary empty map to quickly swap and reload.
236
+ - Saving the map before reload can overwrite injected content; re-inject if needed.
237
+
238
+ ## FAQ
239
+
240
+ - `npm run maps` is empty: save the map in the editor once, then retry.
241
+ - Injection failed: verify `mapId` / `nodeGraphId` and graph type.
242
+ - Type errors: check `.value` usage and pin type alignment first.
243
+
244
+ ## Looking Up Function Notes (AI Friendly)
245
+
246
+ When type hints are not enough, search in `node_modules/genshin-ts`:
247
+ - Node functions and event definitions: `node_modules/genshin-ts/dist/src/definitions/`
248
+ - Use keywords (event name, function name, Chinese alias) to locate comments and params.
@@ -0,0 +1,262 @@
1
+ # __PROJECT_NAME__
2
+
3
+ 这是一个基于 genshin-ts 的千星奇遇项目模板。你可以用 TypeScript 写逻辑,编译为节点图并注入到地图。
4
+
5
+ ## 快速开始
6
+
7
+ ```bash
8
+ npm install
9
+ npm run dev
10
+ ```
11
+
12
+ 文档站:`https://gsts.moe`
13
+
14
+ ## 项目结构
15
+
16
+ - `src/main.ts`:入口示例(`g.server(...).on(...)`)
17
+ - `gsts.config.ts`:编译与输出配置
18
+ - `dist/`:编译产物(`.gs.ts` / `.json` / `.gia`)
19
+ - `CLAUDE.md` / `AGENTS.md`:AI 协作指引(建议先读)
20
+
21
+ ## 注入配置示例(可选)
22
+
23
+ ```ts
24
+ import type { GstsConfig } from 'genshin-ts'
25
+
26
+ const config: GstsConfig = {
27
+ compileRoot: '.',
28
+ entries: ['./src'],
29
+ outDir: './dist',
30
+ inject: {
31
+ gameRegion: 'China',
32
+ playerId: 1,
33
+ mapId: 1073741849,
34
+ nodeGraphId: 1073741825
35
+ }
36
+ }
37
+
38
+ export default config
39
+ ```
40
+
41
+ 提示:
42
+
43
+ - `npm run maps` 可列出最近保存的地图,帮助确定 `mapId`。
44
+ - 多账号/多服务器时填写 `gameRegion` / `playerId` 以定位地图目录。
45
+ - 注入会自动做备份,便于回滚。
46
+
47
+ ## 入口与事件写法
48
+
49
+ ```ts
50
+ import { g } from 'genshin-ts/runtime/core'
51
+
52
+ g.server({ id: 1073741825 }).on('whenEntityIsCreated', (_evt, f) => {
53
+ const p = player(1)
54
+ f.printString(str(p.guid))
55
+ })
56
+ ```
57
+
58
+ 要点:
59
+
60
+ - `id` 是目标节点图 ID;同 ID 的多个入口会自动合并到同一图。
61
+ - 事件名使用字符串字面量(支持中英文名称)。
62
+ - 回调参数中 `f` 是节点图函数入口,优先用它做输出、变量操作等。
63
+ - 可链式注册多个事件:`g.server(...).on(...).onSignal(...)`。
64
+
65
+ ## g.server 参数说明(与注入安全相关)
66
+
67
+ 常用参数:
68
+
69
+ - `id`:目标节点图 ID(注入必须匹配该 ID)。
70
+ - `name`:节点图显示名称;未指定时默认使用入口文件名。
71
+ - `prefix`:是否自动添加 `_GSTS_` 前缀(默认 true)。
72
+ - `type`:节点图类型(默认 server/entity)。
73
+ - `variables`:声明节点图变量并启用 `f.get` / `f.set`。
74
+ - `lang`:`'zh'` 时启用中文事件名与中文函数别名。
75
+
76
+ 注入安全检查要点:
77
+
78
+ - 目标 `id` 必须在地图里存在对应节点图。
79
+ - 目标节点图需要是 **空图** 或 **名称以 `_GSTS` 开头**,否则注入会被拦截。
80
+ - 若你明确知道自己在做什么,可在 `gsts.config.ts` 中设置 `inject.skipSafeCheck = true` 跳过检查。
81
+ - 新建节点图后必须 **保存地图**,注入器才能识别该 `id`。
82
+ - 建议先创建好一批节点图并保存,再一次性编译注入;否则可能出现“注入 -> 新建 -> 保存”导致注入内容被覆盖的问题。
83
+
84
+ ## gsts.config 优化配置(默认启用)
85
+
86
+ `gsts.config.ts` 的 `options.optimize` 默认全开,常见项:
87
+ - `precompileExpression`:预编译纯字面量表达式,减少运行期节点计算。
88
+ - `removeUnusedNodes`:清理未接入事件或未被使用的节点。
89
+ - `timerPool`:控制 `setTimeout` / `setInterval` 的定时器名称池大小。
90
+ - `timerDispatchAggregate`:合并定时器事件分发,减少图复杂度。
91
+
92
+ 如需调试或对比节点图,可临时关闭单项优化。
93
+
94
+ ## 典型用法与限制(AI 必看)
95
+
96
+ ### 作用域划分
97
+
98
+ - **顶层作用域(编译期)**:可以读取文件、使用 npm 库、做预计算,但不要调用 `g.server` 或 `gsts` 相关 API。
99
+ - **节点图作用域(运行期)**:仅支持可编译的 TS 子集,语义会转换为节点图。
100
+
101
+ ### 控制流与返回值
102
+
103
+ - `if/while/switch` 条件必须是 `boolean`,需要时用 `bool(...)` 转换。
104
+ - `gstsServer*` 函数只允许 **末尾单一 `return <expr>`**,不能在分支或循环里 `return`。
105
+ - 递归、`async/await`、Promise 在节点图作用域内不支持(会报错或被 ESLint 提示)。
106
+ - `while(true)` 会受循环上限影响,建议改用定时器或显式计数。
107
+ - `!`/三目运算需要布尔条件,避免对非 bool 取反。
108
+
109
+ ### 数值与类型
110
+
111
+ - `number` 会视为 **float**,`bigint` 会视为 **int**。
112
+ - 取余、位运算等整数运算请使用 `bigint`。
113
+ - 列表/字典元素类型必须一致,混合类型会报错。
114
+ - 空数组可能无法推断类型,建议先放一个同类型占位值。
115
+ - 建议使用辅助函数明确类型:`int`、`float`、`vec3`、`configId`、`prefabId`、`entity` 等。
116
+ - `dict(...)` 用于创建只读字典;需要可写字典时请改用节点图变量(`f.get` / `f.set`)。
117
+ - 需要强制生成节点图局部变量时,用 `let` 声明;`const` 可能会被优化为直接连线。
118
+
119
+ ### 全局函数与变量速查(建议 AI 优先使用)
120
+
121
+ 日志与调试:
122
+
123
+ - `print(str(...))`:最稳定的日志输出方式。
124
+ - `console.log(x)`:仅支持 **单一参数**,会自动转成 `print(str(...))`。
125
+ - `f.printString(...)`:显式节点调用,适合需要严格对齐节点图时使用。
126
+
127
+ 类型与构造:
128
+
129
+ - `bool(...)` / `int(...)` / `float(...)` / `str(...)`:显式类型转换。
130
+ - `vec3(...)` / `guid(...)` / `prefabId(...)` / `configId(...)` / `faction(...)` / `entity(...)`:常用类型构造。
131
+ - `list('int', items)`:显式声明列表类型(空数组时尤为重要)。
132
+ - `dict(...)`:声明只读字典(节点图变量字典需用 `f.get` / `f.set`)。
133
+ - `raw(...)`:编译器不处理,按 JS 原生语义执行(仅在必要时使用)。
134
+
135
+ 实体与场景:
136
+
137
+ - `player(1)`:获取玩家实体(从 1 开始)。
138
+ - `stage` / `level`:关卡实体别名。
139
+ - `self`:当前节点图关联实体。
140
+ - `GameObject.Find(...)` / `FindWithTag(...)` / `FindByPrefabId(...)`:实体查询。
141
+
142
+ 数学与向量:
143
+
144
+ - `Math.*`:会编译为节点图等价实现(server 作用域内)。
145
+ - `Mathf.*` / `Vector3.*` / `Random.*`:Unity 风格 API。
146
+
147
+ 信号与事件:
148
+
149
+ - `send('signalName')` 发送信号,配合 `g.server().onSignal(...)` 监听。
150
+
151
+ 定时器:
152
+
153
+ - `setTimeout` / `setInterval` / `clearTimeout` / `clearInterval`。
154
+
155
+ 常用方法支持:
156
+
157
+ - 数组/字符串的常用方法(`map`/`filter`/`find`/`length` 等)有编译支持,以类型提示为准。
158
+
159
+ ### 节点图变量(可写变量)
160
+
161
+ ```ts
162
+ g.server({
163
+ id: 1073741825,
164
+ variables: { counter: 0n },
165
+ lang: 'zh'
166
+ }).on('whenEntityIsCreated', (_evt, f) => {
167
+ const v = f.get('counter')
168
+ f.set('counter', v + 1n)
169
+ })
170
+ ```
171
+
172
+ 提示:
173
+
174
+ - `variables` 会生成节点图变量,并提供类型化的 `f.get` / `f.set`。
175
+ - 实体类型变量通常只用于声明类型(常用 `entity(0)` 作为占位)。
176
+ - `entity(0)` 也可用于部分节点调用的实体参数占位,让编辑器中该参数保持为空。
177
+
178
+ ### 定时器
179
+
180
+ - 直接使用 `setTimeout` / `setInterval`(单位为毫秒)。
181
+ - 编译器会自动生成定时器池以避免同名冲突。
182
+ - 可用注释 `// @gsts:timerPool=4` 覆盖池大小(高阶用法)。
183
+ - `setInterval` 间隔过小(<=100ms)会有性能警告。
184
+ - 定时器回调支持闭包捕获(按值),但不支持捕获字典类型。
185
+
186
+ ### JS 原生对象的限制
187
+
188
+ - `Object.*`、`JSON.*` 等原生对象在节点图作用域内通常不可编译。
189
+ - 若必须使用,请在顶层预处理,或用 `raw(...)` 让编译器忽略该表达式。
190
+ - 字符串拼接若报错,建议在顶层预计算或用 `str(...)` 显式转换。
191
+
192
+ ## 复用函数(gstsServer)
193
+
194
+ ```ts
195
+ function gstsServerSum(a: bigint, b: bigint) {
196
+ const total = a + b
197
+ return total
198
+ }
199
+
200
+ g.server({ id: 1073741825 }).on('whenEntityIsCreated', (_evt, f) => {
201
+ const v = gstsServerSum(1n, 2n)
202
+ f.printString(str(v))
203
+ })
204
+ ```
205
+
206
+ 规则:
207
+
208
+ - 必须是顶层声明,参数只能是标识符(不支持解构/默认值/rest)。
209
+ - 只允许末尾单一 `return`,且调用必须发生在 `g.server().on(...)` 或另一个 `gstsServer*` 中。
210
+ - 在 `gstsServer*` 内可直接使用 `gsts.f` 访问节点图 API(不强制传 `f` 参数)。
211
+
212
+ ## 多入口与合并
213
+
214
+ - `gsts.config.ts` 的 `entries` 决定哪些文件被编译。
215
+ - 每个入口文件默认生成一个节点图;同 ID 会自动合并。
216
+ - 增量编译下,依赖变更会触发相关入口重编译。
217
+
218
+ ## 输出与调试
219
+
220
+ - `.gs.ts`:TS 被展开成节点函数调用的中间文件,便于定位语义差异。
221
+ - `.json`:节点图 IR,用来排查连接和类型匹配问题。
222
+ - `.gia`:最终节点图产物,可注入或手动导入。
223
+
224
+ ## 编译执行注意事项
225
+
226
+ - 编译器会扫描所有入口文件并找到 `g.server().on(...)` 入口进行编译。
227
+ - 顶层代码会在编译期执行一次或多次(例如增量编译/多入口场景)。
228
+ - 若顶层代码涉及本地文件读写或随机数,请注意副作用与一致性问题。
229
+ - 需要临时禁用某个节点图注入时,可把 `id` 设置为一个不存在的值。
230
+ - 顶层作用域适合做本地文件读取/预计算/程序化生成(例如伪随机场景)。
231
+ - `stage.set` 可当作全局变量使用(节点图运行期)。
232
+
233
+ ## Scripts
234
+
235
+ - `npm run build`:完整编译
236
+ - `npm run dev`:增量编译(配置 inject 后会自动注入)
237
+ - `npm run maps`:列出最近编辑的地图
238
+ - `npm run backup`:打开注入备份目录
239
+ - `npm run typecheck`:TypeScript 类型检查
240
+ - `npm run lint`:ESLint
241
+
242
+ 补充说明:
243
+
244
+ - 本项目内置定制化 ESLint 规则,能提示编译器的隐含约束,建议经常运行 `npm run lint`。
245
+ - `npm run typecheck` 可提前发现类型不匹配问题,避免编译期报错。
246
+ - `npm run dev` 实际调用的是 `gsts dev`,仅进入监控变更的编译模式。
247
+ - 注入后需要重新加载地图,节点图变更才会生效。
248
+ - 可准备一个临时空地图,注入后快速切换以触发重载。
249
+ - 注入后如果在加载前使用编辑器保存地图,注入内容会被覆盖,需要重新注入。
250
+
251
+ ## 常见问题
252
+
253
+ - `npm run maps` 为空:先在编辑器里保存一次地图,再重试。
254
+ - 注入失败:检查 `mapId` / `nodeGraphId` 是否正确,图类型是否匹配。
255
+ - 类型报错:优先检查 `.value` 的使用与引脚类型是否一致。
256
+
257
+ ## 需要查函数说明时(AI 可用)
258
+
259
+ 当类型提示不足时,可以直接在 `node_modules/genshin-ts` 中搜索函数/事件注释:
260
+
261
+ - 节点函数与事件定义:`node_modules/genshin-ts/dist/src/definitions/`
262
+ - 建议用关键词搜索(事件名、函数名、中文别名)定位注释与参数说明。
@@ -0,0 +1,8 @@
1
+ node_modules
2
+ dist
3
+ out
4
+ *.log
5
+ .env
6
+ .DS_Store
7
+ *.gia
8
+ .idea
@@ -0,0 +1 @@
1
+ export { default } from 'genshin-ts/configs/eslint/full.mjs'
@@ -0,0 +1,9 @@
1
+ import type { GstsConfig } from 'genshin-ts'
2
+
3
+ const config: GstsConfig = {
4
+ compileRoot: '.',
5
+ entries: ['./src'],
6
+ outDir: './dist'
7
+ }
8
+
9
+ export default config
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "__PACKAGE_NAME__",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "typecheck": "tsc -p tsconfig.json --noEmit",
8
+ "lint": "eslint .",
9
+ "build": "gsts",
10
+ "dev": "gsts dev",
11
+ "maps": "gsts maps",
12
+ "backup": "gsts open backup"
13
+ },
14
+ "dependencies": {
15
+ "genshin-ts": "^0.1.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^24.10.1",
19
+ "@ianvs/prettier-plugin-sort-imports": "^4.3.1",
20
+ "@typescript-eslint/eslint-plugin": "^8.47.0",
21
+ "@typescript-eslint/parser": "^8.47.0",
22
+ "eslint": "^9.39.1",
23
+ "eslint-config-prettier": "^10.1.8",
24
+ "eslint-plugin-prettier": "^5.5.4",
25
+ "prettier": "^3.6.2",
26
+ "typescript": "^5.9.3"
27
+ }
28
+ }
@@ -0,0 +1,7 @@
1
+ import { g } from 'genshin-ts/runtime/core'
2
+
3
+ g.server({
4
+ id: 1073741825
5
+ }).on('whenEntityIsCreated', (_evt, f) => {
6
+ console.log('hello world')
7
+ })
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "genshin-ts/tsconfig/base.json",
3
+ "compilerOptions": {
4
+ "rootDir": ".",
5
+ "outDir": "dist",
6
+ "typeRoots": ["./node_modules/genshin-ts/types", "./node_modules/@types"],
7
+ "types": ["gsts", "node"]
8
+ },
9
+ "include": ["src", "gsts.config.ts"]
10
+ }