mcpywrap 0.1.0__tar.gz

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 (43) hide show
  1. mcpywrap-0.1.0/PKG-INFO +97 -0
  2. mcpywrap-0.1.0/README.md +75 -0
  3. mcpywrap-0.1.0/mcpywrap/__init__.py +4 -0
  4. mcpywrap-0.1.0/mcpywrap/__main__.py +13 -0
  5. mcpywrap-0.1.0/mcpywrap/builders/AddonsPack.py +226 -0
  6. mcpywrap-0.1.0/mcpywrap/builders/__init__.py +10 -0
  7. mcpywrap-0.1.0/mcpywrap/builders/file_handler.py +112 -0
  8. mcpywrap-0.1.0/mcpywrap/builders/file_merge.py +49 -0
  9. mcpywrap-0.1.0/mcpywrap/builders/project_builder.py +157 -0
  10. mcpywrap-0.1.0/mcpywrap/builders/watcher.py +107 -0
  11. mcpywrap-0.1.0/mcpywrap/cli.py +34 -0
  12. mcpywrap-0.1.0/mcpywrap/commands/__init__.py +25 -0
  13. mcpywrap-0.1.0/mcpywrap/commands/add_cmd.py +39 -0
  14. mcpywrap-0.1.0/mcpywrap/commands/build_cmd.py +58 -0
  15. mcpywrap-0.1.0/mcpywrap/commands/default_cmd.py +70 -0
  16. mcpywrap-0.1.0/mcpywrap/commands/dev_cmd.py +111 -0
  17. mcpywrap-0.1.0/mcpywrap/commands/init_cmd.py +202 -0
  18. mcpywrap-0.1.0/mcpywrap/commands/mod_cmd.py +24 -0
  19. mcpywrap-0.1.0/mcpywrap/commands/modsdk_cmd.py +65 -0
  20. mcpywrap-0.1.0/mcpywrap/commands/publish_cmd.py +45 -0
  21. mcpywrap-0.1.0/mcpywrap/commands/remove_cmd.py +42 -0
  22. mcpywrap-0.1.0/mcpywrap/config.py +109 -0
  23. mcpywrap-0.1.0/mcpywrap/custom_packaging.py +41 -0
  24. mcpywrap-0.1.0/mcpywrap/minecraft/__init__.py +1 -0
  25. mcpywrap-0.1.0/mcpywrap/minecraft/addons.py +157 -0
  26. mcpywrap-0.1.0/mcpywrap/minecraft/config.py +6 -0
  27. mcpywrap-0.1.0/mcpywrap/minecraft/mod_template.py +52 -0
  28. mcpywrap-0.1.0/mcpywrap/minecraft/netease_modsdk.py +269 -0
  29. mcpywrap-0.1.0/mcpywrap/minecraft/template/generate_mod_files.py +114 -0
  30. mcpywrap-0.1.0/mcpywrap/minecraft/template/mod_template.py +459 -0
  31. mcpywrap-0.1.0/mcpywrap/utils/__init__.py +6 -0
  32. mcpywrap-0.1.0/mcpywrap/utils/print_guide.py +21 -0
  33. mcpywrap-0.1.0/mcpywrap/utils/project_setup.py +112 -0
  34. mcpywrap-0.1.0/mcpywrap/utils/py3to2_util.py +53 -0
  35. mcpywrap-0.1.0/mcpywrap/utils/utils.py +34 -0
  36. mcpywrap-0.1.0/mcpywrap.egg-info/PKG-INFO +97 -0
  37. mcpywrap-0.1.0/mcpywrap.egg-info/SOURCES.txt +41 -0
  38. mcpywrap-0.1.0/mcpywrap.egg-info/dependency_links.txt +1 -0
  39. mcpywrap-0.1.0/mcpywrap.egg-info/entry_points.txt +3 -0
  40. mcpywrap-0.1.0/mcpywrap.egg-info/requires.txt +8 -0
  41. mcpywrap-0.1.0/mcpywrap.egg-info/top_level.txt +1 -0
  42. mcpywrap-0.1.0/pyproject.toml +35 -0
  43. mcpywrap-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,97 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcpywrap
3
+ Version: 0.1.0
4
+ Summary: A wrapper for Minecraft China Edition Addons management
5
+ Author-email: boybook <boybook@easecation.net>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/EaseCation/mcpywrap
8
+ Project-URL: Bug Tracker, https://github.com/EaseCation/mcpywrap/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.6
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: click>=8.0.0
15
+ Requires-Dist: 3to2>=1.1.1
16
+ Requires-Dist: watchdog>=2.0.0
17
+ Requires-Dist: twine>=3.4.0
18
+ Requires-Dist: tomli
19
+ Requires-Dist: tomli-w
20
+ Requires-Dist: setuptools
21
+ Requires-Dist: PyQt5>=5.15.0
22
+
23
+ # 🧰 mcpywrap
24
+
25
+ **《我的世界》中国版 ModSDK 与资源包的全周期管理工具**
26
+
27
+ [![PyPI Version](https://img.shields.io/pypi/v/mcpywrap)](https://pypi.org/project/mcpywrap/)
28
+ [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
29
+
30
+ mcpywrap 是基于 Python 生态的《我的世界》中国版 ModSDK/资源包全周期管理工具,支持依赖管理、语法转换和自动化构建,助力开发者实现高效协作与代码复用。
31
+
32
+ ## 🌟 核心特性
33
+
34
+ - 🧩 **模块化开发** - 基于 Addons 维度的依赖管理
35
+ - 🔄 **语法无忧** - 开发阶段支持 Python3 语法,构建时自动转换为 Python2
36
+ - 📦 **生态兼容** - 无缝对接 PyPI 生态,支持标准 `pyproject.toml` 配置
37
+ - 🚀 **智能构建** - 一键打包符合 MCStudio 规范的成品 Addons
38
+ - 🔥 **热重载开发** - 实时监控代码变更,支持 MCStudio 热更新
39
+
40
+ ## 📖 为何选择此工具?
41
+
42
+ ### 传统开发痛点
43
+ - 📜 **代码复用困难** - 通过 **文件拷贝** 导致版本管理混乱
44
+ - 🚧 **协作效率低下** - 多项目 **重复代码** 维护成本高
45
+ - ⚠️ **语法限制** - 中国版仅支持 Python2,缺乏现代语法支持
46
+
47
+ ### mcpywrap 解决方案
48
+ 1. **标准化开发**
49
+ 通过 `pyproject.toml` 声明项目元数据和依赖关系,实现真正的模块化开发
50
+
51
+ 2. **现代开发体验**
52
+ 开发阶段使用 Python3 语法,构建时通过 3to2 自动转换,兼顾开发效率与运行兼容
53
+
54
+ 3. **生态集成**
55
+ 依托 pip 包管理体系,支持依赖的版本锁定和自动解析
56
+
57
+
58
+ ## 🚀 快速开始
59
+
60
+ ### 前置要求
61
+ - Python ≥ 3.8
62
+ - pip ≥ 21.0
63
+
64
+ ### 安装
65
+ ```bash
66
+ pip install mcpywrap
67
+ ```
68
+
69
+ ### 初始化项目
70
+ ```bash
71
+ mcpy init
72
+ ```
73
+ 交互式创建项目结构,自动生成标准的 Mod 框架。
74
+
75
+ ## 🛠 工作流指南
76
+
77
+ ### 依赖管理
78
+ | 命令 | 说明 |
79
+ |-------------------------------|---------------------|
80
+ | `mcpy` | 维护项目,将项目安装到系统 site-package 环境 |
81
+ | `mcpy add <package> [version]` | 添加指定版本依赖 |
82
+ | `mcpy remove <package>` | 移除依赖 |
83
+
84
+ ### 构建与开发
85
+ ```bash
86
+ # 生产构建(输出到配置的 build 目录)
87
+ mcpy build
88
+
89
+ # 开发模式(热重载 + 实时构建)
90
+ mcpy dev
91
+ ```
92
+
93
+ ## 🤝 参与贡献
94
+ 欢迎提交 Issue 和 PR!请先阅读 [贡献指南](CONTRIBUTING.md)。
95
+
96
+ ## 开源协议
97
+ [MIT License](LICENSE) © 2025 EaseCation
@@ -0,0 +1,75 @@
1
+ # 🧰 mcpywrap
2
+
3
+ **《我的世界》中国版 ModSDK 与资源包的全周期管理工具**
4
+
5
+ [![PyPI Version](https://img.shields.io/pypi/v/mcpywrap)](https://pypi.org/project/mcpywrap/)
6
+ [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
+
8
+ mcpywrap 是基于 Python 生态的《我的世界》中国版 ModSDK/资源包全周期管理工具,支持依赖管理、语法转换和自动化构建,助力开发者实现高效协作与代码复用。
9
+
10
+ ## 🌟 核心特性
11
+
12
+ - 🧩 **模块化开发** - 基于 Addons 维度的依赖管理
13
+ - 🔄 **语法无忧** - 开发阶段支持 Python3 语法,构建时自动转换为 Python2
14
+ - 📦 **生态兼容** - 无缝对接 PyPI 生态,支持标准 `pyproject.toml` 配置
15
+ - 🚀 **智能构建** - 一键打包符合 MCStudio 规范的成品 Addons
16
+ - 🔥 **热重载开发** - 实时监控代码变更,支持 MCStudio 热更新
17
+
18
+ ## 📖 为何选择此工具?
19
+
20
+ ### 传统开发痛点
21
+ - 📜 **代码复用困难** - 通过 **文件拷贝** 导致版本管理混乱
22
+ - 🚧 **协作效率低下** - 多项目 **重复代码** 维护成本高
23
+ - ⚠️ **语法限制** - 中国版仅支持 Python2,缺乏现代语法支持
24
+
25
+ ### mcpywrap 解决方案
26
+ 1. **标准化开发**
27
+ 通过 `pyproject.toml` 声明项目元数据和依赖关系,实现真正的模块化开发
28
+
29
+ 2. **现代开发体验**
30
+ 开发阶段使用 Python3 语法,构建时通过 3to2 自动转换,兼顾开发效率与运行兼容
31
+
32
+ 3. **生态集成**
33
+ 依托 pip 包管理体系,支持依赖的版本锁定和自动解析
34
+
35
+
36
+ ## 🚀 快速开始
37
+
38
+ ### 前置要求
39
+ - Python ≥ 3.8
40
+ - pip ≥ 21.0
41
+
42
+ ### 安装
43
+ ```bash
44
+ pip install mcpywrap
45
+ ```
46
+
47
+ ### 初始化项目
48
+ ```bash
49
+ mcpy init
50
+ ```
51
+ 交互式创建项目结构,自动生成标准的 Mod 框架。
52
+
53
+ ## 🛠 工作流指南
54
+
55
+ ### 依赖管理
56
+ | 命令 | 说明 |
57
+ |-------------------------------|---------------------|
58
+ | `mcpy` | 维护项目,将项目安装到系统 site-package 环境 |
59
+ | `mcpy add <package> [version]` | 添加指定版本依赖 |
60
+ | `mcpy remove <package>` | 移除依赖 |
61
+
62
+ ### 构建与开发
63
+ ```bash
64
+ # 生产构建(输出到配置的 build 目录)
65
+ mcpy build
66
+
67
+ # 开发模式(热重载 + 实时构建)
68
+ mcpy dev
69
+ ```
70
+
71
+ ## 🤝 参与贡献
72
+ 欢迎提交 Issue 和 PR!请先阅读 [贡献指南](CONTRIBUTING.md)。
73
+
74
+ ## 开源协议
75
+ [MIT License](LICENSE) © 2025 EaseCation
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+ """mcpywrap - 将 Python 3 代码转换为 Python 2 代码的工具"""
3
+
4
+ __version__ = '0.1.0'
@@ -0,0 +1,13 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ mcpywrap 命令行工具的入口点
4
+ """
5
+
6
+ from .cli import cli
7
+
8
+ def main():
9
+ """主函数,作为 CLI 入口点"""
10
+ cli()
11
+
12
+ if __name__ == "__main__":
13
+ main()
@@ -0,0 +1,226 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import os
4
+ import shutil
5
+ import click
6
+ from .file_handler import ensure_dir, try_merge_file
7
+
8
+
9
+ # Python 包管理和其他应该忽略的文件和目录
10
+ EXCLUDED_PATTERNS = [
11
+ # Python 包管理
12
+ ".egg-info",
13
+ "__pycache__",
14
+ ".pyc",
15
+ ".pyo",
16
+ ".pyd",
17
+ ".so",
18
+ ".dll",
19
+ ".eggs",
20
+ ".pytest_cache",
21
+ ".tox",
22
+ ".coverage",
23
+ ".coverage.*",
24
+ "htmlcov",
25
+ # 版本控制
26
+ ".git",
27
+ ".hg",
28
+ ".svn",
29
+ ".bzr",
30
+ # 其他临时文件
31
+ ".DS_Store",
32
+ "Thumbs.db"
33
+ ]
34
+
35
+ MANIFEST_FILES = [
36
+ "manifest.json",
37
+ "pack_manifest.json"
38
+ ]
39
+
40
+
41
+ class AddonsPack(object):
42
+
43
+ pkg_name: str
44
+ path: str
45
+ is_origin: bool
46
+ behavior_pack_dir: str
47
+ resource_pack_dir: str
48
+
49
+ def __init__(self, pkg_name, path, is_origin=False):
50
+ self.pkg_name = pkg_name
51
+ self.path = path
52
+ self.is_origin = is_origin
53
+ self.behavior_pack_dir = None
54
+ self.resource_pack_dir = None
55
+ # 进入此目录,查找内部的行为包和资源包的路径
56
+ os.chdir(self.path)
57
+ for item in os.listdir(self.path):
58
+ item_path = os.path.join(self.path, item)
59
+ if os.path.isdir(item_path):
60
+ if item.startswith("behavior_pack") or item.startswith("BehaviorPack"):
61
+ self.behavior_pack_dir = item_path
62
+ elif item.startswith("resource_pack") or item.startswith("ResourcePack"):
63
+ self.resource_pack_dir = item_path
64
+ if not self.behavior_pack_dir:
65
+ self.behavior_pack_dir = os.path.join(self.path, "behavior_pack")
66
+ if not self.resource_pack_dir:
67
+ self.resource_pack_dir = os.path.join(self.path, "resource_pack")
68
+
69
+ def should_exclude(self, path):
70
+ """判断文件或目录是否应该被排除"""
71
+ for pattern in EXCLUDED_PATTERNS:
72
+ if pattern in path:
73
+ return True
74
+ # 得到文件名
75
+ filename = os.path.basename(path)
76
+ if not self.is_origin and filename in MANIFEST_FILES:
77
+ return True
78
+ return False
79
+
80
+ def copy_behavior_to(self, target_dir: str):
81
+ """复制行为包和资源包到目标目录"""
82
+ if self.behavior_pack_dir:
83
+ target_path = os.path.join(target_dir, os.path.basename(self.behavior_pack_dir))
84
+ os.makedirs(target_path, exist_ok=True)
85
+
86
+ # 使用自定义复制函数而不是shutil.copytree
87
+ for root, dirs, files in os.walk(self.behavior_pack_dir):
88
+ # 过滤掉应该排除的目录
89
+ dirs[:] = [d for d in dirs if not self.should_exclude(os.path.join(root, d))]
90
+
91
+ # 计算相对路径
92
+ rel_path = os.path.relpath(root, self.behavior_pack_dir)
93
+ # 计算目标目录
94
+ target_root = os.path.join(target_path, rel_path) if rel_path != '.' else target_path
95
+ ensure_dir(target_root)
96
+
97
+ # 复制文件
98
+ for file in files:
99
+ src_file = os.path.join(root, file)
100
+ if not self.should_exclude(src_file):
101
+ dest_file = os.path.join(target_root, file)
102
+ # 如果是Python文件,检查并添加编码声明
103
+ if file.endswith('.py'):
104
+ self._copy_with_encoding_check(src_file, dest_file)
105
+ else:
106
+ shutil.copy2(src_file, dest_file)
107
+
108
+ def copy_resource_to(self, target_dir: str):
109
+ """复制资源包到目标目录"""
110
+ if self.resource_pack_dir:
111
+ target_path = os.path.join(target_dir, os.path.basename(self.resource_pack_dir))
112
+ os.makedirs(target_path, exist_ok=True)
113
+
114
+ # 使用自定义复制函数而不是shutil.copytree
115
+ for root, dirs, files in os.walk(self.resource_pack_dir):
116
+ # 过滤掉应该排除的目录
117
+ dirs[:] = [d for d in dirs if not self.should_exclude(os.path.join(root, d))]
118
+
119
+ # 计算相对路径
120
+ rel_path = os.path.relpath(root, self.resource_pack_dir)
121
+ # 计算目标目录
122
+ target_root = os.path.join(target_path, rel_path) if rel_path != '.' else target_path
123
+ ensure_dir(target_root)
124
+
125
+ # 复制文件
126
+ for file in files:
127
+ src_file = os.path.join(root, file)
128
+ if not self.should_exclude(src_file):
129
+ dest_file = os.path.join(target_root, file)
130
+ # 如果是Python文件,检查并添加编码声明
131
+ if file.endswith('.py'):
132
+ self._copy_with_encoding_check(src_file, dest_file)
133
+ else:
134
+ shutil.copy2(src_file, dest_file)
135
+
136
+ def merge_behavior_into(self, target_behavior_dir: str):
137
+ """合并行为包到目标行为包目录"""
138
+ if self.behavior_pack_dir:
139
+ for root, dirs, files in os.walk(self.behavior_pack_dir):
140
+ # 过滤掉应该排除的目录
141
+ dirs[:] = [d for d in dirs if not self.should_exclude(os.path.join(root, d))]
142
+
143
+ # 计算相对路径
144
+ rel_path = os.path.relpath(root, self.behavior_pack_dir)
145
+ # 计算目标目录
146
+ target_root = os.path.join(target_behavior_dir, rel_path) if rel_path != '.' else target_behavior_dir
147
+ ensure_dir(target_root)
148
+
149
+ # 复制文件
150
+ for file in files:
151
+ src_file = os.path.join(root, file)
152
+ if self.should_exclude(src_file):
153
+ continue
154
+
155
+ dest_file = os.path.join(target_root, file)
156
+
157
+ if file.endswith('.py'): # 如果是Python文件,直接无脑覆盖
158
+ self._copy_with_encoding_check(src_file, dest_file)
159
+ elif os.path.exists(dest_file): # 如果文件已存在,尝试合并
160
+ suc, reason = try_merge_file(src_file, dest_file)
161
+ if not suc:
162
+ click.secho(f"❌ 未处理的文件冲突: {src_file} -> {dest_file} {reason}", fg="red")
163
+ else:
164
+ shutil.copy2(src_file, dest_file)
165
+
166
+ def merge_resource_into(self, target_resource_dir: str):
167
+ """合并资源包到目标资源包目录"""
168
+ if self.resource_pack_dir:
169
+ for root, dirs, files in os.walk(self.resource_pack_dir):
170
+ # 过滤掉应该排除的目录
171
+ dirs[:] = [d for d in dirs if not self.should_exclude(os.path.join(root, d))]
172
+
173
+ # 计算相对路径
174
+ rel_path = os.path.relpath(root, self.resource_pack_dir)
175
+ # 计算目标目录
176
+ target_root = os.path.join(target_resource_dir, rel_path) if rel_path != '.' else target_resource_dir
177
+ ensure_dir(target_root)
178
+
179
+ # 复制文件
180
+ for file in files:
181
+ src_file = os.path.join(root, file)
182
+ if self.should_exclude(src_file):
183
+ continue
184
+
185
+ dest_file = os.path.join(target_root, file)
186
+ # 处理文件冲突
187
+ if file.endswith('.py'):
188
+ self._copy_with_encoding_check(src_file, dest_file)
189
+ elif os.path.exists(dest_file):
190
+ suc, reason = try_merge_file(src_file, dest_file)
191
+ if not suc:
192
+ click.secho(f"⚠️ 警告: 文件合并异常 {src_file} -> {dest_file} {reason}", fg="yellow")
193
+ # 如果是Python文件,检查并添加编码声明
194
+ if file.endswith('.py'):
195
+ self._copy_with_encoding_check(src_file, dest_file)
196
+ else:
197
+ shutil.copy2(src_file, dest_file)
198
+ else:
199
+ shutil.copy2(src_file, dest_file)
200
+
201
+ def _copy_with_encoding_check(self, src_file, dest_file):
202
+ """复制Python文件,并检查添加编码声明"""
203
+ try:
204
+ with open(src_file, 'r', encoding='utf-8') as f:
205
+ content = f.read()
206
+
207
+ # 检查是否有编码声明
208
+ has_coding = False
209
+ first_line = content.splitlines()[0] if content.splitlines() else ""
210
+ if "# -*- coding: utf-8 -*-" in first_line or "# coding: utf-8" in first_line:
211
+ has_coding = True
212
+
213
+ # 如果没有编码声明,则添加
214
+ if not has_coding:
215
+ content = "# -*- coding: utf-8 -*-\n" + content
216
+
217
+ # 写入目标文件
218
+ with open(dest_file, 'w', encoding='utf-8') as f:
219
+ f.write(content)
220
+
221
+ # 复制文件元数据
222
+ shutil.copystat(src_file, dest_file)
223
+ except Exception as e:
224
+ click.secho(f"⚠️ 添加编码声明时出错: {src_file} -> {dest_file}: {str(e)}", fg="yellow")
225
+ # 如果出错,则直接复制
226
+ shutil.copy2(src_file, dest_file)
@@ -0,0 +1,10 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 构建模块包,提供项目构建、文件处理和监控功能
4
+ """
5
+
6
+ from .project_builder import build_project
7
+ from .file_handler import process_file, is_python_file
8
+ from .watcher import FileWatcher
9
+
10
+ __all__ = ['build_project', 'process_file', 'is_python_file', 'FileWatcher']
@@ -0,0 +1,112 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 文件处理模块 - 负责单个文件的复制和转换
4
+ """
5
+
6
+ import os
7
+ import shutil
8
+
9
+ from ..utils.py3to2_util import py3_to_2
10
+ from ..utils.utils import ensure_dir, run_command
11
+ from .file_merge import try_merge_file
12
+
13
+ def is_python_file(file_path):
14
+ """判断是否为Python文件"""
15
+ return file_path.endswith('.py')
16
+
17
+ def copy_file(src_path, dest_path):
18
+ """复制文件,确保目标目录存在"""
19
+ dest_dir = os.path.dirname(dest_path)
20
+ ensure_dir(dest_dir)
21
+ print(f"复制文件: {src_path} 到 {dest_path}")
22
+ shutil.copy2(src_path, dest_path)
23
+ return dest_path
24
+
25
+ def convert_py3_to_py2(file_path):
26
+ """将某个Python文件转换为Python 2"""
27
+ try:
28
+ # 首先尝试使用直接的Python API调用
29
+ from lib3to2.main import main
30
+ # main函数接受包名和参数列表
31
+ # 第一个参数是包名 'lib3to2' (这是3to2所有修复器的位置)
32
+ # 第二个参数是命令行参数列表
33
+ exit_code = main('lib3to2.fixes', ['-w', '-n', '--no-diffs', file_path, '--nofix=metaclass'])
34
+ # exit_code = py3_to_2(file_path)
35
+ return exit_code == 0, "转换完成" if exit_code == 0 else f"转换失败,错误代码: {exit_code}"
36
+ except Exception as e:
37
+ # 如果直接调用失败,则尝试命令行方式(作为备选)
38
+ try:
39
+ # 方法1:直接命令行调用
40
+ success, output = run_command(["3to2", "-w", "-n", file_path])
41
+ if not success:
42
+ # 方法2:使用shell=True参数
43
+ success, output = run_command(["3to2", "-w", "-n", file_path], shell=True)
44
+
45
+ return success, output
46
+ except Exception as cmd_e:
47
+ return False, f"Python API调用失败: {str(e)}\n命令行调用也失败: {str(cmd_e)}"
48
+
49
+ def process_file(src_path, source_dir, target_dir, is_dependency=False, dependency_name=None):
50
+ """处理单个文件(复制并根据文件类型处理)"""
51
+ # 计算相对路径和目标路径
52
+ rel_path = os.path.relpath(src_path, source_dir)
53
+
54
+ # 如果是依赖项,需要特殊处理目标路径
55
+ if is_dependency:
56
+ # 确定是属于行为包还是资源包
57
+ if "behavior_pack" in src_path.lower() or "behaviorpack" in src_path.lower():
58
+ # 在路径中定位behavior_pack部分
59
+ parts = src_path.split(os.sep)
60
+ for i, part in enumerate(parts):
61
+ if "behavior_pack" in part.lower() or "behaviorpack" in part.lower():
62
+ # 获取behavior_pack后的相对路径
63
+ sub_path = os.path.join(*parts[i+1:])
64
+ # 目标路径应该是behavior_pack目录
65
+ for item in os.listdir(target_dir):
66
+ if "behavior_pack" in item.lower() or "behaviorpack" in item.lower():
67
+ dest_path = os.path.join(target_dir, item, sub_path)
68
+ break
69
+ else:
70
+ # 如果找不到behavior_pack目录,创建一个
71
+ dest_path = os.path.join(target_dir, "behavior_pack", sub_path)
72
+ break
73
+ elif "resource_pack" in src_path.lower() or "resourcepack" in src_path.lower():
74
+ # 在路径中定位resource_pack部分
75
+ parts = src_path.split(os.sep)
76
+ for i, part in enumerate(parts):
77
+ if "resource_pack" in part.lower() or "resourcepack" in part.lower():
78
+ # 获取resource_pack后的相对路径
79
+ sub_path = os.path.join(*parts[i+1:])
80
+ # 目标路径应该是resource_pack目录
81
+ for item in os.listdir(target_dir):
82
+ if "resource_pack" in item.lower() or "resourcepack" in item.lower():
83
+ dest_path = os.path.join(target_dir, item, sub_path)
84
+ break
85
+ else:
86
+ # 如果找不到resource_pack目录,创建一个
87
+ dest_path = os.path.join(target_dir, "resource_pack", sub_path)
88
+ break
89
+ else:
90
+ # 如果不在行为包或资源包中,忽略该文件
91
+ return False, "不在行为包或资源包中的文件将被忽略", None
92
+ else:
93
+ dest_path = os.path.join(target_dir, rel_path)
94
+
95
+ # 检查目标文件是否已存在,如果存在且来自依赖,尝试合并
96
+ if is_dependency and os.path.exists(dest_path):
97
+ suc, reason = try_merge_file(src_path, dest_path)
98
+ if not suc:
99
+ # 如果合并失败或有冲突,直接返回
100
+ msg = f"文件合并失败或存在冲突" if reason is None else reason
101
+ return False, msg, dest_path
102
+ else:
103
+ # 复制文件
104
+ copy_file(src_path, dest_path)
105
+
106
+ # 如果是Python文件,进行转换
107
+ if is_python_file(src_path):
108
+ success, output = convert_py3_to_py2(dest_path)
109
+ return success, output, dest_path
110
+
111
+ # 如果是其他类型文件,直接返回成功
112
+ return True, "", dest_path
@@ -0,0 +1,49 @@
1
+ # -*- coding: utf-8 -*-
2
+ import os
3
+ import shutil
4
+
5
+
6
+ def try_merge_file(source_file, target_file) -> tuple[bool, str]:
7
+ """合并两个JSON文件的内容"""
8
+ # 如果是py文件,直接复制即可
9
+ if source_file.endswith('.py'):
10
+ # 直接复制
11
+ shutil.copy2(source_file, target_file)
12
+ return True, f"成功复制 {os.path.basename(source_file)}"
13
+ else:
14
+ # 读取源文件内容
15
+ with open(source_file, 'r', encoding='utf-8') as f:
16
+ source_content = f.read()
17
+
18
+ # 读取目标文件内容
19
+ with open(target_file, 'r', encoding='utf-8') as f:
20
+ target_content = f.read()
21
+
22
+ # 合并两个JSON对象
23
+ try:
24
+ source_json = eval(source_content)
25
+ target_json = eval(target_content)
26
+ merged_json = _merge_dicts(target_json, source_json)
27
+
28
+ # 写入合并后的内容到目标文件
29
+ with open(target_file, 'w', encoding='utf-8') as f:
30
+ f.write(str(merged_json))
31
+
32
+ return True, f"成功合并 {os.path.basename(source_file)} 到 {os.path.basename(target_file)}"
33
+ except Exception as e:
34
+ return False, f"合并失败: {str(e)}"
35
+
36
+ def _merge_dicts(dict1, dict2):
37
+ """递归合并两个字典"""
38
+ result = dict1.copy()
39
+ for key, value in dict2.items():
40
+ if key in result and isinstance(result[key], dict) and isinstance(value, dict):
41
+ # 递归合并嵌套字典
42
+ result[key] = _merge_dicts(result[key], value)
43
+ elif key in result and isinstance(result[key], list) and isinstance(value, list):
44
+ # 合并列表
45
+ result[key].extend(value)
46
+ else:
47
+ # 覆盖或添加新键
48
+ result[key] = value
49
+ return result