kotonebot 0.4.0__py3-none-any.whl → 0.6.0__py3-none-any.whl
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.
- kotonebot/backend/context/context.py +1002 -1002
- kotonebot/backend/core.py +6 -49
- kotonebot/backend/image.py +36 -5
- kotonebot/backend/loop.py +222 -208
- kotonebot/backend/ocr.py +7 -1
- kotonebot/client/device.py +108 -243
- kotonebot/client/host/__init__.py +34 -3
- kotonebot/client/host/adb_common.py +7 -9
- kotonebot/client/host/custom.py +6 -2
- kotonebot/client/host/leidian_host.py +2 -7
- kotonebot/client/host/mumu12_host.py +2 -7
- kotonebot/client/host/protocol.py +4 -3
- kotonebot/client/implements/__init__.py +62 -11
- kotonebot/client/implements/adb.py +5 -1
- kotonebot/client/implements/nemu_ipc/__init__.py +4 -0
- kotonebot/client/implements/uiautomator2.py +6 -2
- kotonebot/client/implements/windows.py +7 -3
- kotonebot/client/registration.py +1 -1
- kotonebot/client/scaler.py +467 -0
- kotonebot/config/base_config.py +1 -1
- kotonebot/config/config.py +61 -0
- kotonebot/core/__init__.py +13 -0
- kotonebot/core/entities/base.py +182 -0
- kotonebot/core/entities/compound.py +75 -0
- kotonebot/core/entities/ocr.py +117 -0
- kotonebot/core/entities/template_match.py +198 -0
- kotonebot/devtools/__init__.py +42 -0
- kotonebot/devtools/cli/__init__.py +6 -0
- kotonebot/devtools/cli/main.py +53 -0
- kotonebot/devtools/project/project.py +41 -0
- kotonebot/devtools/project/scanner.py +202 -0
- kotonebot/devtools/project/schema.py +99 -0
- kotonebot/devtools/resgen/__init__.py +42 -0
- kotonebot/devtools/resgen/codegen.py +331 -0
- kotonebot/devtools/resgen/core.py +94 -0
- kotonebot/devtools/resgen/parsers.py +360 -0
- kotonebot/devtools/resgen/utils.py +158 -0
- kotonebot/devtools/resgen/validation.py +115 -0
- kotonebot/devtools/web/dist/assets/bootstrap-icons-BOrJxbIo.woff +0 -0
- kotonebot/devtools/web/dist/assets/bootstrap-icons-BtvjY1KL.woff2 +0 -0
- kotonebot/devtools/web/dist/assets/ext-language_tools-CD021WJ2.js +2577 -0
- kotonebot/devtools/web/dist/assets/index-B_m5f2LF.js +2836 -0
- kotonebot/devtools/web/dist/assets/index-BlEDyGGa.css +9 -0
- kotonebot/devtools/web/dist/assets/language-client-C9muzqaq.js +128 -0
- kotonebot/devtools/web/dist/assets/mode-python-CtHp76XS.js +476 -0
- kotonebot/devtools/web/dist/icons/symbol-class.svg +3 -0
- kotonebot/devtools/web/dist/icons/symbol-file.svg +3 -0
- kotonebot/devtools/web/dist/icons/symbol-method.svg +3 -0
- kotonebot/devtools/web/dist/index.html +25 -0
- kotonebot/devtools/web/server/__init__.py +0 -0
- kotonebot/devtools/web/server/rest_api.py +217 -0
- kotonebot/devtools/web/server/server.py +85 -0
- kotonebot/errors.py +7 -2
- kotonebot/interop/win/__init__.py +10 -1
- kotonebot/interop/win/_mouse.py +311 -0
- kotonebot/interop/win/shake_mouse.py +224 -0
- kotonebot/primitives/__init__.py +3 -1
- kotonebot/primitives/geometry.py +817 -40
- kotonebot/primitives/visual.py +81 -1
- kotonebot/ui/pushkit/image_host.py +2 -1
- kotonebot/ui/pushkit/wxpusher.py +2 -1
- {kotonebot-0.4.0.dist-info → kotonebot-0.6.0.dist-info}/METADATA +4 -1
- kotonebot-0.6.0.dist-info/RECORD +105 -0
- kotonebot-0.6.0.dist-info/entry_points.txt +2 -0
- kotonebot/client/implements/adb_raw.py +0 -159
- kotonebot-0.4.0.dist-info/RECORD +0 -70
- /kotonebot/{tools → devtools}/mirror.py +0 -0
- /kotonebot/{tools → devtools/project}/__init__.py +0 -0
- {kotonebot-0.4.0.dist-info → kotonebot-0.6.0.dist-info}/WHEEL +0 -0
- {kotonebot-0.4.0.dist-info → kotonebot-0.6.0.dist-info}/licenses/LICENSE +0 -0
- {kotonebot-0.4.0.dist-info → kotonebot-0.6.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import argparse
|
|
3
|
+
|
|
4
|
+
from ..web.server.server import start_devtools
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main():
|
|
8
|
+
"""KotoneBot CLI entry point."""
|
|
9
|
+
parser = argparse.ArgumentParser(
|
|
10
|
+
prog="kbot",
|
|
11
|
+
description="KotoneBot command-line interface"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
15
|
+
|
|
16
|
+
# devtools subcommand
|
|
17
|
+
devtools_parser = subparsers.add_parser(
|
|
18
|
+
"devtools",
|
|
19
|
+
help="Start the KotoneBot DevTools web server"
|
|
20
|
+
)
|
|
21
|
+
devtools_parser.add_argument(
|
|
22
|
+
"--port",
|
|
23
|
+
type=int,
|
|
24
|
+
default=1178,
|
|
25
|
+
help="Port to listen on (default: 1178)"
|
|
26
|
+
)
|
|
27
|
+
devtools_parser.add_argument(
|
|
28
|
+
"--host",
|
|
29
|
+
type=str,
|
|
30
|
+
default="127.0.0.1",
|
|
31
|
+
help="Host to listen on (default: 127.0.0.1)"
|
|
32
|
+
)
|
|
33
|
+
devtools_parser.add_argument(
|
|
34
|
+
"--no-browser",
|
|
35
|
+
action="store_true",
|
|
36
|
+
help="Do not automatically open browser"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
args = parser.parse_args()
|
|
40
|
+
|
|
41
|
+
if args.command == "devtools":
|
|
42
|
+
start_devtools(
|
|
43
|
+
host=args.host,
|
|
44
|
+
port=args.port,
|
|
45
|
+
open_browser=not args.no_browser
|
|
46
|
+
)
|
|
47
|
+
else:
|
|
48
|
+
parser.print_help()
|
|
49
|
+
sys.exit(0)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
main()
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
from tomllib import loads as toml_loader # py>=3.11 # type: ignore
|
|
5
|
+
except ModuleNotFoundError: # pragma: no cover
|
|
6
|
+
from tomli import loads as toml_loader # py<3.11
|
|
7
|
+
|
|
8
|
+
from kotonebot.devtools.project.schema import PyProjectData
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
PYPROJECT_PATH = './pyproject.toml'
|
|
12
|
+
|
|
13
|
+
class Project:
|
|
14
|
+
def __init__(self, *, conf_path: str = PYPROJECT_PATH) -> None:
|
|
15
|
+
self.conf_path: str = conf_path
|
|
16
|
+
self.conf: PyProjectData
|
|
17
|
+
|
|
18
|
+
self.load()
|
|
19
|
+
|
|
20
|
+
def load(self) -> None:
|
|
21
|
+
"""
|
|
22
|
+
载入项目的配置文件。
|
|
23
|
+
|
|
24
|
+
:raises FileNotFoundError: 如果配置文件不存在。
|
|
25
|
+
:raises toml.TomlDecodeError: 如果配置文件格式无效。
|
|
26
|
+
"""
|
|
27
|
+
conf_dict = toml_loader(Path(self.conf_path).read_text(encoding='utf-8'))
|
|
28
|
+
|
|
29
|
+
tool_conf = conf_dict.get('tool', {}).get('kotonebot', {})
|
|
30
|
+
if tool_conf:
|
|
31
|
+
self.conf = PyProjectData.model_validate(tool_conf)
|
|
32
|
+
else:
|
|
33
|
+
self.conf = PyProjectData()
|
|
34
|
+
|
|
35
|
+
if self.conf.editor and self.conf.editor.resource_path is not None:
|
|
36
|
+
self.conf.editor.resource_path = str(Path(self.conf.editor.resource_path).absolute())
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if __name__ == '__main__':
|
|
40
|
+
project = Project()
|
|
41
|
+
print(project.conf)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
import sys
|
|
4
|
+
import pkgutil
|
|
5
|
+
import inspect
|
|
6
|
+
import importlib
|
|
7
|
+
import subprocess
|
|
8
|
+
import contextlib
|
|
9
|
+
from typing import Any, Dict
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
|
|
13
|
+
# ==============================================================================
|
|
14
|
+
# Public API
|
|
15
|
+
# ==============================================================================
|
|
16
|
+
|
|
17
|
+
def scan_prefabs(package_name: str, python_executable: str = sys.executable) -> Dict[str, Any]:
|
|
18
|
+
"""
|
|
19
|
+
在一个隔离的子进程中扫描指定的 Python 包,先扫描默认包
|
|
20
|
+
`kotonebot.core.entities`,然后扫描传入的包(两次扫描在一次子进程内完成)。
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
package_name: 要扫描的包的点分名称 (例如 'my_app.components')。
|
|
24
|
+
python_executable: 用于运行子进程的 Python 解释器路径。
|
|
25
|
+
默认为当前正在运行的 Python 解释器。
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
一个字典,包含扫描结果;在错误情况下返回空字典。
|
|
29
|
+
"""
|
|
30
|
+
default_pkg = 'kotonebot.core.entities'
|
|
31
|
+
print(f"--- Main process (PID: {os.getpid()}) starting worker for packages: '{default_pkg}' and '{package_name}'... ---")
|
|
32
|
+
|
|
33
|
+
packages = [default_pkg]
|
|
34
|
+
if package_name and package_name != default_pkg:
|
|
35
|
+
packages.append(package_name)
|
|
36
|
+
|
|
37
|
+
# `__file__` 指向当前脚本文件,它将以工作模式被再次执行,传入要扫描的包列表
|
|
38
|
+
command = [python_executable, __file__, '--worker', *packages]
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
child_env = os.environ.copy()
|
|
42
|
+
child_env.setdefault('PYTHONUTF8', '1')
|
|
43
|
+
child_env.setdefault('PYTHONIOENCODING', 'utf-8:replace')
|
|
44
|
+
|
|
45
|
+
result = subprocess.run(
|
|
46
|
+
command,
|
|
47
|
+
capture_output=True,
|
|
48
|
+
text=True,
|
|
49
|
+
check=False, # 手动处理错误,不让它自动抛出异常
|
|
50
|
+
encoding='utf-8',
|
|
51
|
+
env=child_env,
|
|
52
|
+
cwd=os.getcwd()
|
|
53
|
+
)
|
|
54
|
+
except FileNotFoundError:
|
|
55
|
+
print(f"Error: Python executable not found at '{python_executable}'.", file=sys.stderr)
|
|
56
|
+
return {}
|
|
57
|
+
|
|
58
|
+
# 打印来自子进程的任何日志/调试信息
|
|
59
|
+
if result.stderr:
|
|
60
|
+
print("\n--- Logs/Errors from worker process ---", file=sys.stderr)
|
|
61
|
+
print(result.stderr.strip(), file=sys.stderr)
|
|
62
|
+
print("-------------------------------------\n", file=sys.stderr)
|
|
63
|
+
|
|
64
|
+
if result.returncode != 0:
|
|
65
|
+
print(f"Error: Worker process exited abnormally with return code: {result.returncode}", file=sys.stderr)
|
|
66
|
+
return {}
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
# 从子进程的标准输出解析 JSON 数据
|
|
70
|
+
return json.loads(result.stdout)
|
|
71
|
+
except json.JSONDecodeError:
|
|
72
|
+
print("Error: Failed to parse JSON from worker process output.", file=sys.stderr)
|
|
73
|
+
print("--- STDOUT from worker process ---", file=sys.stderr)
|
|
74
|
+
print(result.stdout, file=sys.stderr)
|
|
75
|
+
print("--------------------------------", file=sys.stderr)
|
|
76
|
+
return {}
|
|
77
|
+
|
|
78
|
+
# ==============================================================================
|
|
79
|
+
# Internal Worker Logic (在子进程中运行)
|
|
80
|
+
# ==============================================================================
|
|
81
|
+
|
|
82
|
+
def _get_class_properties(cls: type) -> Dict[str, Any]:
|
|
83
|
+
# Collect attributes from the class and its bases (inheritance),
|
|
84
|
+
# allowing subclass attributes to override base attributes.
|
|
85
|
+
properties: Dict[str, Any] = {}
|
|
86
|
+
for base in reversed(cls.__mro__):
|
|
87
|
+
# skip builtin object and EditorMetadata base to avoid copying framework internals
|
|
88
|
+
if base is object or base.__name__ == 'EditorMetadata':
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
for key, value in vars(base).items():
|
|
92
|
+
if key.startswith('__') or callable(value):
|
|
93
|
+
continue
|
|
94
|
+
|
|
95
|
+
properties[key] = value
|
|
96
|
+
|
|
97
|
+
return properties
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _json_default(obj: Any):
|
|
101
|
+
try:
|
|
102
|
+
if isinstance(obj, BaseModel):
|
|
103
|
+
return obj.model_dump()
|
|
104
|
+
except Exception:
|
|
105
|
+
pass
|
|
106
|
+
return str(obj)
|
|
107
|
+
|
|
108
|
+
@contextlib.contextmanager
|
|
109
|
+
def _redirect_stdout_to_stderr():
|
|
110
|
+
"""上下文管理器,临时将 stdout 重定向到 stderr 以隔离用户代码的输出。"""
|
|
111
|
+
original_stdout = sys.stdout
|
|
112
|
+
sys.stdout = sys.stderr
|
|
113
|
+
try:
|
|
114
|
+
yield
|
|
115
|
+
finally:
|
|
116
|
+
sys.stdout = original_stdout
|
|
117
|
+
|
|
118
|
+
def _worker_main(package_names):
|
|
119
|
+
"""
|
|
120
|
+
在隔离的子进程中执行的实际工作逻辑。
|
|
121
|
+
结果通过打印 JSON 到 stdout 来返回。
|
|
122
|
+
"""
|
|
123
|
+
# 确保子进程的 sys.path 包含项目根目录
|
|
124
|
+
sys.path.insert(0, os.getcwd())
|
|
125
|
+
|
|
126
|
+
final_results: dict[str, dict[str, Any]] = {}
|
|
127
|
+
try:
|
|
128
|
+
from kotonebot.devtools import EditorMetadata
|
|
129
|
+
|
|
130
|
+
# Normalize package_names to a list
|
|
131
|
+
if isinstance(package_names, str):
|
|
132
|
+
package_names = [package_names]
|
|
133
|
+
|
|
134
|
+
all_module_names: list[str] = []
|
|
135
|
+
for pkg_name in package_names:
|
|
136
|
+
try:
|
|
137
|
+
package = importlib.import_module(pkg_name)
|
|
138
|
+
except Exception as e:
|
|
139
|
+
print(f"[Worker] Failed to import package {pkg_name}: {e}", file=sys.stderr)
|
|
140
|
+
continue
|
|
141
|
+
|
|
142
|
+
if hasattr(package, '__path__'):
|
|
143
|
+
module_names = [
|
|
144
|
+
name for _, name, _ in pkgutil.walk_packages(
|
|
145
|
+
path=package.__path__, prefix=package.__name__ + '.'
|
|
146
|
+
)
|
|
147
|
+
]
|
|
148
|
+
else:
|
|
149
|
+
# package is actually a single module (no __path__), include it directly
|
|
150
|
+
module_names = [package.__name__]
|
|
151
|
+
|
|
152
|
+
# 保持顺序并去重(默认包先)
|
|
153
|
+
for name in module_names:
|
|
154
|
+
if name not in all_module_names:
|
|
155
|
+
all_module_names.append(name)
|
|
156
|
+
|
|
157
|
+
for module_name in all_module_names:
|
|
158
|
+
try:
|
|
159
|
+
# 隔离导入,防止用户代码的 print 污染 stdout
|
|
160
|
+
with _redirect_stdout_to_stderr():
|
|
161
|
+
module = importlib.import_module(module_name)
|
|
162
|
+
except Exception as e:
|
|
163
|
+
print(f"[Worker] Failed to import module {module_name}: {e}", file=sys.stderr)
|
|
164
|
+
continue
|
|
165
|
+
|
|
166
|
+
for _, outer_cls in inspect.getmembers(module, inspect.isclass):
|
|
167
|
+
if outer_cls.__module__ != module_name:
|
|
168
|
+
continue
|
|
169
|
+
|
|
170
|
+
for _, nested_cls in inspect.getmembers(outer_cls, inspect.isclass):
|
|
171
|
+
if nested_cls is not EditorMetadata and issubclass(nested_cls, EditorMetadata):
|
|
172
|
+
properties = _get_class_properties(nested_cls)
|
|
173
|
+
prefab_id = properties.get('id') or outer_cls.__name__
|
|
174
|
+
if prefab_id:
|
|
175
|
+
properties['id'] = prefab_id
|
|
176
|
+
final_results[prefab_id] = properties
|
|
177
|
+
break
|
|
178
|
+
except Exception as e:
|
|
179
|
+
# 将关键错误打印到 stderr,并以非零代码退出
|
|
180
|
+
print(f"[Worker] A critical error occurred: {e}", file=sys.stderr)
|
|
181
|
+
# 即使出错,也打印空 JSON 到 stdout,避免父进程解析失败
|
|
182
|
+
print(json.dumps({}, default=_json_default, ensure_ascii=False))
|
|
183
|
+
sys.exit(1)
|
|
184
|
+
|
|
185
|
+
output = {
|
|
186
|
+
"version": 1, # Schema version
|
|
187
|
+
"prefabs": final_results
|
|
188
|
+
}
|
|
189
|
+
print(json.dumps(output, default=_json_default, ensure_ascii=False))
|
|
190
|
+
sys.exit(0)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
if __name__ == "__main__":
|
|
194
|
+
if len(sys.argv) > 2 and sys.argv[1] == '--worker':
|
|
195
|
+
# Pass all package args (sys.argv[2:]) to the worker so it scans multiple packages in one run
|
|
196
|
+
_worker_main(sys.argv[2:])
|
|
197
|
+
else:
|
|
198
|
+
print("This is a library module and its own scanning worker.", file=sys.stderr)
|
|
199
|
+
print("Please do not run this file directly.", file=sys.stderr)
|
|
200
|
+
print("You should import and call the `scan_prefabs` function from your application.", file=sys.stderr)
|
|
201
|
+
sys.exit(1)
|
|
202
|
+
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from pydantic import BaseModel, Field
|
|
3
|
+
|
|
4
|
+
class EditorMetadata:
|
|
5
|
+
"""
|
|
6
|
+
## Prefab 元数据类
|
|
7
|
+
|
|
8
|
+
此类用于声明自定义 Prefab 的编辑器元数据,包括ID、名称、
|
|
9
|
+
描述、自定义字段等。只需要在你的 Prefab 类下声明一个
|
|
10
|
+
继承自此类的嵌套类(名称随意),Devtool 会自动扫描并识别
|
|
11
|
+
出你的自定义 Prefab,并按照元数据展示。
|
|
12
|
+
|
|
13
|
+
### 例
|
|
14
|
+
```python
|
|
15
|
+
class MyButtonPrefab(Prefab):
|
|
16
|
+
# 实际属性
|
|
17
|
+
type: Literal['primary' | 'secondary'] = 'primary'
|
|
18
|
+
region: Rect | None = None
|
|
19
|
+
match_text: str = ''
|
|
20
|
+
|
|
21
|
+
# 编辑器元数据
|
|
22
|
+
class Editor(EditorMetadata):
|
|
23
|
+
id = 'my_button'
|
|
24
|
+
name = '按钮'
|
|
25
|
+
description = '一个自定义按钮 Prefab'
|
|
26
|
+
props = {
|
|
27
|
+
'type': ChoiceProp(label='按钮类型', description='按钮的样式类型', default_value='primary', choices=[('主按钮', 'primary'), ('次按钮', 'secondary')]),
|
|
28
|
+
'region': RectProp(label='按钮区域', description='按钮在屏幕上的位置区域', default_value=None),
|
|
29
|
+
'match_text': StrProp(label='匹配文本', description='按钮上的文本内容', default_value=''),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
"""
|
|
34
|
+
id: str
|
|
35
|
+
name: str
|
|
36
|
+
description: str | None = None
|
|
37
|
+
primary_prop: str | None = None
|
|
38
|
+
shortcut: str | None = None
|
|
39
|
+
"""
|
|
40
|
+
用于切换到此工具的快捷键,可以为单按键。
|
|
41
|
+
"""
|
|
42
|
+
icon: str | None = None
|
|
43
|
+
"""展示在编辑器上的 icon 名称。"""
|
|
44
|
+
"""
|
|
45
|
+
主属性 key(例如 rect / anchor / image)。
|
|
46
|
+
"""
|
|
47
|
+
props: 'dict[str, EditorProp]' = {}
|
|
48
|
+
"""
|
|
49
|
+
此 Prefab 的属性,格式为 dict[属性键名, EditorProp]。
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class EditorProp(BaseModel):
|
|
54
|
+
kind: str
|
|
55
|
+
label: str
|
|
56
|
+
description: str | None = None
|
|
57
|
+
default_value: Any = None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class RectProp(EditorProp):
|
|
61
|
+
kind: str = 'rect'
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class PointProp(EditorProp):
|
|
65
|
+
kind: str = 'point'
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class ImageProp(EditorProp):
|
|
69
|
+
kind: str = 'image'
|
|
70
|
+
|
|
71
|
+
class BoolProp(EditorProp):
|
|
72
|
+
kind: str = 'bool'
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class FloatProp(EditorProp):
|
|
76
|
+
kind: str = 'float'
|
|
77
|
+
min: float | None = None
|
|
78
|
+
max: float | None = None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class IntProp(EditorProp):
|
|
82
|
+
kind: str = 'int'
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class StrProp(EditorProp):
|
|
86
|
+
kind: str = 'str'
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class ChoiceProp(EditorProp):
|
|
90
|
+
kind: str = 'choice'
|
|
91
|
+
choices: list[tuple[str, Any]] = Field(...)
|
|
92
|
+
|
|
93
|
+
class EditorData(BaseModel):
|
|
94
|
+
prefabs_module: str | None = None
|
|
95
|
+
resource_path: str | None = None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class PyProjectData(BaseModel):
|
|
99
|
+
editor: EditorData | None = None
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from .core import (
|
|
2
|
+
CodeWriter,
|
|
3
|
+
ResourceNode,
|
|
4
|
+
ClassNode,
|
|
5
|
+
SchemaParser,
|
|
6
|
+
)
|
|
7
|
+
from .codegen import (
|
|
8
|
+
StandardGenerator,
|
|
9
|
+
)
|
|
10
|
+
from .parsers import (
|
|
11
|
+
ParserRegistry,
|
|
12
|
+
KotoneV1Parser,
|
|
13
|
+
BasicSpriteParser,
|
|
14
|
+
)
|
|
15
|
+
from .utils import (
|
|
16
|
+
to_camel_case,
|
|
17
|
+
unify_path,
|
|
18
|
+
build_class_tree,
|
|
19
|
+
ImageProcessor,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
# core
|
|
24
|
+
"CodeWriter",
|
|
25
|
+
"ResourceNode",
|
|
26
|
+
"ClassNode",
|
|
27
|
+
"SchemaParser",
|
|
28
|
+
|
|
29
|
+
# generator
|
|
30
|
+
"StandardGenerator",
|
|
31
|
+
|
|
32
|
+
# parsers
|
|
33
|
+
"ParserRegistry",
|
|
34
|
+
"KotoneV1Parser",
|
|
35
|
+
"BasicSpriteParser",
|
|
36
|
+
|
|
37
|
+
# utils
|
|
38
|
+
"to_camel_case",
|
|
39
|
+
"unify_path",
|
|
40
|
+
"build_class_tree",
|
|
41
|
+
"ImageProcessor",
|
|
42
|
+
]
|