cml-launcher 1.0.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.
- cml_launcher-1.0.0/PKG-INFO +78 -0
- cml_launcher-1.0.0/README.md +64 -0
- cml_launcher-1.0.0/cml/__init__.py +39 -0
- cml_launcher-1.0.0/cml/__main__.py +8 -0
- cml_launcher-1.0.0/cml/app.py +174 -0
- cml_launcher-1.0.0/cml/core.py +297 -0
- cml_launcher-1.0.0/cml/modules/config_manager.py +75 -0
- cml_launcher-1.0.0/cml/modules/pages/__init__.py +12 -0
- cml_launcher-1.0.0/cml/modules/pages/download_page.py +517 -0
- cml_launcher-1.0.0/cml/modules/pages/home_page.py +219 -0
- cml_launcher-1.0.0/cml/modules/pages/mods_page.py +318 -0
- cml_launcher-1.0.0/cml/modules/pages/settings_page.py +105 -0
- cml_launcher-1.0.0/cml/modules/pages/versions_page.py +150 -0
- cml_launcher-1.0.0/cml/modules/sidebar.py +54 -0
- cml_launcher-1.0.0/cml_launcher.egg-info/PKG-INFO +78 -0
- cml_launcher-1.0.0/cml_launcher.egg-info/SOURCES.txt +19 -0
- cml_launcher-1.0.0/cml_launcher.egg-info/dependency_links.txt +1 -0
- cml_launcher-1.0.0/cml_launcher.egg-info/requires.txt +5 -0
- cml_launcher-1.0.0/cml_launcher.egg-info/top_level.txt +1 -0
- cml_launcher-1.0.0/pyproject.toml +33 -0
- cml_launcher-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cml-launcher
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: CML - cm Minecraft Launcher - 纯代码 Minecraft 启动器
|
|
5
|
+
Author: cm
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/your-repo/cml-launcher
|
|
8
|
+
Requires-Python: >=3.8
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: minecraft-launcher-lib>=1.4.0
|
|
11
|
+
Provides-Extra: gui
|
|
12
|
+
Requires-Dist: customtkinter>=5.2.0; extra == "gui"
|
|
13
|
+
Requires-Dist: Pillow>=10.0.0; extra == "gui"
|
|
14
|
+
|
|
15
|
+
# CML - cm Minecraft Launcher
|
|
16
|
+
|
|
17
|
+
简洁高效的 Minecraft 启动器,基于 CustomTkinter 构建。
|
|
18
|
+
|
|
19
|
+
## 功能特性
|
|
20
|
+
|
|
21
|
+
- 账户管理(离线登录)
|
|
22
|
+
- 版本管理(安装/删除/选择)
|
|
23
|
+
- 模组管理(扫描/启用/禁用/删除)
|
|
24
|
+
- Modrinth 模组/光影搜索下载
|
|
25
|
+
- 自动 Java 检测
|
|
26
|
+
- 深色主题 UI
|
|
27
|
+
|
|
28
|
+
## 安装
|
|
29
|
+
|
|
30
|
+
### 方式一:pip 安装
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install cml-launcher
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
安装后,在命令行运行:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cml
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
或使用模块方式:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
python -m cml
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 方式二:开发模式
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
git clone <repo-url>
|
|
52
|
+
cd cml-launcher
|
|
53
|
+
pip install -e .
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 使用
|
|
57
|
+
|
|
58
|
+
安装后,运行以下命令启动:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
cml
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 系统要求
|
|
65
|
+
|
|
66
|
+
- Python 3.8+
|
|
67
|
+
- Windows/Linux/macOS
|
|
68
|
+
- Minecraft 游戏文件(首次启动会自动下载)
|
|
69
|
+
|
|
70
|
+
## 依赖
|
|
71
|
+
|
|
72
|
+
- customtkinter >= 5.2.0
|
|
73
|
+
- minecraft-launcher-lib >= 1.4.0
|
|
74
|
+
- Pillow >= 10.0.0
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# CML - cm Minecraft Launcher
|
|
2
|
+
|
|
3
|
+
简洁高效的 Minecraft 启动器,基于 CustomTkinter 构建。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- 账户管理(离线登录)
|
|
8
|
+
- 版本管理(安装/删除/选择)
|
|
9
|
+
- 模组管理(扫描/启用/禁用/删除)
|
|
10
|
+
- Modrinth 模组/光影搜索下载
|
|
11
|
+
- 自动 Java 检测
|
|
12
|
+
- 深色主题 UI
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
### 方式一:pip 安装
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install cml-launcher
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
安装后,在命令行运行:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
cml
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
或使用模块方式:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
python -m cml
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 方式二:开发模式
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone <repo-url>
|
|
38
|
+
cd cml-launcher
|
|
39
|
+
pip install -e .
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 使用
|
|
43
|
+
|
|
44
|
+
安装后,运行以下命令启动:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
cml
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 系统要求
|
|
51
|
+
|
|
52
|
+
- Python 3.8+
|
|
53
|
+
- Windows/Linux/macOS
|
|
54
|
+
- Minecraft 游戏文件(首次启动会自动下载)
|
|
55
|
+
|
|
56
|
+
## 依赖
|
|
57
|
+
|
|
58
|
+
- customtkinter >= 5.2.0
|
|
59
|
+
- minecraft-launcher-lib >= 1.4.0
|
|
60
|
+
- Pillow >= 10.0.0
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
MIT
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CML - cm Minecraft Launcher
|
|
3
|
+
|
|
4
|
+
无 GUI 版本:通过代码启动/下载游戏
|
|
5
|
+
|
|
6
|
+
用法:
|
|
7
|
+
import cml
|
|
8
|
+
|
|
9
|
+
# 启动游戏
|
|
10
|
+
cml.launch_game("1.20.1") # 通过版本名启动
|
|
11
|
+
cml.launch_game(jar_path="C:/MC/versions/1.20.1/1.20.1.jar") # 通过 jar 绝对路径启动
|
|
12
|
+
|
|
13
|
+
# 下载游戏
|
|
14
|
+
cml.download_version("1.20.1") # 下载到默认目录
|
|
15
|
+
cml.download_version("1.20.1", "D:/MC") # 下载到指定目录
|
|
16
|
+
|
|
17
|
+
# 其他
|
|
18
|
+
cml.list_versions() # 获取可下载版本
|
|
19
|
+
cml.get_versions() # 获取已安装版本
|
|
20
|
+
cml.set_version("1.20.1") # 设置当前版本
|
|
21
|
+
cml.get_java_path() # 获取 Java 路径
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
__version__ = "1.0.0"
|
|
25
|
+
__author__ = "cm"
|
|
26
|
+
|
|
27
|
+
from .core import CMLCore, launch_game, get_versions, set_version, get_java_path, download_version, list_versions, search_versions
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"CMLCore",
|
|
31
|
+
"launch_game",
|
|
32
|
+
"get_versions",
|
|
33
|
+
"set_version",
|
|
34
|
+
"get_java_path",
|
|
35
|
+
"download_version",
|
|
36
|
+
"list_versions",
|
|
37
|
+
"search_versions",
|
|
38
|
+
"__version__",
|
|
39
|
+
]
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CML - cm Minecraft Launcher
|
|
3
|
+
主入口模块
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import customtkinter as ctk
|
|
7
|
+
import os
|
|
8
|
+
import subprocess
|
|
9
|
+
import threading
|
|
10
|
+
import minecraft_launcher_lib as mll
|
|
11
|
+
|
|
12
|
+
from .modules.sidebar import Sidebar
|
|
13
|
+
from .modules.pages.home_page import HomePage
|
|
14
|
+
from .modules.pages.versions_page import VersionsPage
|
|
15
|
+
from .modules.pages.download_page import DownloadPage
|
|
16
|
+
from .modules.pages.mods_page import ModsPage
|
|
17
|
+
from .modules.pages.settings_page import SettingsPage
|
|
18
|
+
from .modules.config_manager import ConfigManager
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CMLauncher(ctk.CTk):
|
|
22
|
+
def __init__(self):
|
|
23
|
+
super().__init__()
|
|
24
|
+
|
|
25
|
+
self.title("CML - cm Minecraft Launcher")
|
|
26
|
+
self.geometry("1000x650")
|
|
27
|
+
self.minsize(900, 600)
|
|
28
|
+
|
|
29
|
+
ctk.set_appearance_mode("dark")
|
|
30
|
+
ctk.set_default_color_theme("blue")
|
|
31
|
+
self.configure(bg_color="#1a1a2e")
|
|
32
|
+
|
|
33
|
+
self.config = ConfigManager()
|
|
34
|
+
self.pages = {}
|
|
35
|
+
self.current_page = None
|
|
36
|
+
|
|
37
|
+
self._setup_ui()
|
|
38
|
+
|
|
39
|
+
# 启动后台线程自动检测 Java
|
|
40
|
+
threading.Thread(target=self._auto_detect_java, daemon=True).start()
|
|
41
|
+
|
|
42
|
+
def _setup_ui(self):
|
|
43
|
+
self.sidebar = Sidebar(self, self._switch_page)
|
|
44
|
+
self.sidebar.pack(side="left", fill="y")
|
|
45
|
+
|
|
46
|
+
self.content = ctk.CTkFrame(self, fg_color="#16213e", corner_radius=0)
|
|
47
|
+
self.content.pack(side="right", fill="both", expand=True)
|
|
48
|
+
|
|
49
|
+
self.pages["home"] = HomePage(self.content, self.config)
|
|
50
|
+
self.pages["versions"] = VersionsPage(self.content, self.config)
|
|
51
|
+
self.pages["download"] = DownloadPage(self.content)
|
|
52
|
+
self.pages["mods"] = ModsPage(self.content, self.config)
|
|
53
|
+
self.pages["settings"] = SettingsPage(self.content, self.config)
|
|
54
|
+
|
|
55
|
+
self._switch_page("home")
|
|
56
|
+
|
|
57
|
+
def _switch_page(self, page_name):
|
|
58
|
+
if self.current_page:
|
|
59
|
+
self.current_page.pack_forget()
|
|
60
|
+
page = self.pages.get(page_name)
|
|
61
|
+
if page:
|
|
62
|
+
page.pack(fill="both", expand=True, padx=20, pady=20)
|
|
63
|
+
self.current_page = page
|
|
64
|
+
self.sidebar.set_active(page_name)
|
|
65
|
+
|
|
66
|
+
def _auto_detect_java(self):
|
|
67
|
+
"""启动时后台检测 Java 路径(已有有效路径则跳过)"""
|
|
68
|
+
saved = self.config.get("java_path", "")
|
|
69
|
+
if saved and os.path.exists(saved):
|
|
70
|
+
return # 已有有效路径,不重复扫描
|
|
71
|
+
|
|
72
|
+
found = self._scan_java()
|
|
73
|
+
if found:
|
|
74
|
+
self.config.set("java_path", found)
|
|
75
|
+
# 通知首页刷新 Java 显示
|
|
76
|
+
self.after(0, self._notify_java_found, found)
|
|
77
|
+
|
|
78
|
+
def _scan_java(self):
|
|
79
|
+
"""多策略扫描 Java,返回第一个找到的 javaw.exe 路径"""
|
|
80
|
+
|
|
81
|
+
# 策略1:mll 内置检测
|
|
82
|
+
try:
|
|
83
|
+
path = mll.utils.get_java_executable()
|
|
84
|
+
if path and path != "java" and os.path.exists(path):
|
|
85
|
+
return path
|
|
86
|
+
except Exception:
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
# 策略2:Minecraft 自带 runtime(jre-legacy / java-runtime-gamma 等)
|
|
90
|
+
mc_dir = mll.utils.get_minecraft_directory()
|
|
91
|
+
runtime_base = os.path.join(mc_dir, "runtime")
|
|
92
|
+
if os.path.exists(runtime_base):
|
|
93
|
+
for runtime_name in os.listdir(runtime_base):
|
|
94
|
+
for sub in ["bin", os.path.join("bin", "java")]:
|
|
95
|
+
candidate = os.path.join(runtime_base, runtime_name, "windows", runtime_name, sub, "javaw.exe")
|
|
96
|
+
if os.path.exists(candidate):
|
|
97
|
+
return candidate
|
|
98
|
+
# 另一种路径结构
|
|
99
|
+
candidate2 = os.path.join(runtime_base, runtime_name, sub, "javaw.exe")
|
|
100
|
+
if os.path.exists(candidate2):
|
|
101
|
+
return candidate2
|
|
102
|
+
|
|
103
|
+
# 策略3:注册表
|
|
104
|
+
reg_keys = [
|
|
105
|
+
r"HKLM\SOFTWARE\JavaSoft\Java Runtime Environment",
|
|
106
|
+
r"HKLM\SOFTWARE\JavaSoft\JDK",
|
|
107
|
+
r"HKLM\SOFTWARE\JavaSoft\Java Development Kit",
|
|
108
|
+
r"HKLM\SOFTWARE\WOW6432Node\JavaSoft\Java Runtime Environment",
|
|
109
|
+
]
|
|
110
|
+
for key in reg_keys:
|
|
111
|
+
try:
|
|
112
|
+
result = subprocess.run(
|
|
113
|
+
["reg", "query", key, "/v", "JavaHome"],
|
|
114
|
+
capture_output=True, text=True, timeout=5,
|
|
115
|
+
)
|
|
116
|
+
if result.returncode == 0:
|
|
117
|
+
for line in result.stdout.splitlines():
|
|
118
|
+
if "REG_SZ" in line:
|
|
119
|
+
java_home = line.split("REG_SZ")[-1].strip()
|
|
120
|
+
exe = os.path.join(java_home, "bin", "javaw.exe")
|
|
121
|
+
if os.path.exists(exe):
|
|
122
|
+
return exe
|
|
123
|
+
except Exception:
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
# 策略4:常见安装目录扫描
|
|
127
|
+
common_bases = [
|
|
128
|
+
r"C:\Program Files\Java",
|
|
129
|
+
r"C:\Program Files\Eclipse Adoptium",
|
|
130
|
+
r"C:\Program Files\Microsoft",
|
|
131
|
+
r"C:\Program Files (x86)\Java",
|
|
132
|
+
r"D:\Java",
|
|
133
|
+
r"D:\Program Files\Java",
|
|
134
|
+
]
|
|
135
|
+
for base in common_bases:
|
|
136
|
+
if not os.path.exists(base):
|
|
137
|
+
continue
|
|
138
|
+
try:
|
|
139
|
+
for entry in os.listdir(base):
|
|
140
|
+
exe = os.path.join(base, entry, "bin", "javaw.exe")
|
|
141
|
+
if os.path.exists(exe):
|
|
142
|
+
return exe
|
|
143
|
+
except Exception:
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
# 策略5:where java(PATH 里找)
|
|
147
|
+
try:
|
|
148
|
+
result = subprocess.run(
|
|
149
|
+
["where", "javaw"], capture_output=True, text=True, timeout=5
|
|
150
|
+
)
|
|
151
|
+
if result.returncode == 0:
|
|
152
|
+
path = result.stdout.strip().splitlines()[0]
|
|
153
|
+
if os.path.exists(path):
|
|
154
|
+
return path
|
|
155
|
+
except Exception:
|
|
156
|
+
pass
|
|
157
|
+
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
def _notify_java_found(self, path):
|
|
161
|
+
"""检测到 Java 后刷新首页显示"""
|
|
162
|
+
home = self.pages.get("home")
|
|
163
|
+
if home and hasattr(home, "_refresh_java_info"):
|
|
164
|
+
home._refresh_java_info()
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def main():
|
|
168
|
+
"""命令行入口(用于 python -m cml 或安装后 cml 命令)"""
|
|
169
|
+
app = CMLauncher()
|
|
170
|
+
app.mainloop()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
if __name__ == "__main__":
|
|
174
|
+
main()
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CML - cm Minecraft Launcher
|
|
3
|
+
核心启动模块(无 GUI)
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
import minecraft_launcher_lib as mll
|
|
9
|
+
from .modules.config_manager import ConfigManager
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CMLCore:
|
|
13
|
+
"""CML 核心类(无 GUI)"""
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self.config = ConfigManager()
|
|
17
|
+
self.minecraft_dir = mll.utils.get_minecraft_directory()
|
|
18
|
+
|
|
19
|
+
def get_java_path(self):
|
|
20
|
+
"""获取 Java 路径(自动检测)"""
|
|
21
|
+
saved = self.config.get("java_path", "")
|
|
22
|
+
if saved and os.path.exists(saved):
|
|
23
|
+
return saved
|
|
24
|
+
|
|
25
|
+
# 自动检测
|
|
26
|
+
java_path = self._detect_java()
|
|
27
|
+
if java_path:
|
|
28
|
+
self.config.set("java_path", java_path)
|
|
29
|
+
return java_path
|
|
30
|
+
|
|
31
|
+
def _detect_java(self):
|
|
32
|
+
"""多策略扫描 Java"""
|
|
33
|
+
# 策略1:mll 内置检测
|
|
34
|
+
try:
|
|
35
|
+
path = mll.utils.get_java_executable()
|
|
36
|
+
if path and path != "java" and os.path.exists(path):
|
|
37
|
+
return path
|
|
38
|
+
except Exception:
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
# 策略2:Minecraft 自带 runtime
|
|
42
|
+
runtime_base = os.path.join(self.minecraft_dir, "runtime")
|
|
43
|
+
if os.path.exists(runtime_base):
|
|
44
|
+
for runtime_name in os.listdir(runtime_base):
|
|
45
|
+
for sub in ["bin", os.path.join("bin", "java")]:
|
|
46
|
+
candidate = os.path.join(runtime_base, runtime_name, "windows", runtime_name, sub, "javaw.exe")
|
|
47
|
+
if os.path.exists(candidate):
|
|
48
|
+
return candidate
|
|
49
|
+
candidate2 = os.path.join(runtime_base, runtime_name, sub, "javaw.exe")
|
|
50
|
+
if os.path.exists(candidate2):
|
|
51
|
+
return candidate2
|
|
52
|
+
|
|
53
|
+
# 策略3:注册表
|
|
54
|
+
reg_keys = [
|
|
55
|
+
r"HKLM\SOFTWARE\JavaSoft\Java Runtime Environment",
|
|
56
|
+
r"HKLM\SOFTWARE\JavaSoft\JDK",
|
|
57
|
+
r"HKLM\SOFTWARE\WOW6432Node\JavaSoft\Java Runtime Environment",
|
|
58
|
+
]
|
|
59
|
+
for key in reg_keys:
|
|
60
|
+
try:
|
|
61
|
+
result = subprocess.run(
|
|
62
|
+
["reg", "query", key, "/v", "JavaHome"],
|
|
63
|
+
capture_output=True, text=True, timeout=5,
|
|
64
|
+
)
|
|
65
|
+
if result.returncode == 0:
|
|
66
|
+
for line in result.stdout.splitlines():
|
|
67
|
+
if "REG_SZ" in line:
|
|
68
|
+
java_home = line.split("REG_SZ")[-1].strip()
|
|
69
|
+
exe = os.path.join(java_home, "bin", "javaw.exe")
|
|
70
|
+
if os.path.exists(exe):
|
|
71
|
+
return exe
|
|
72
|
+
except Exception:
|
|
73
|
+
continue
|
|
74
|
+
|
|
75
|
+
# 策略4:常见安装目录
|
|
76
|
+
common_bases = [
|
|
77
|
+
r"C:\Program Files\Java",
|
|
78
|
+
r"C:\Program Files\Eclipse Adoptium",
|
|
79
|
+
r"C:\Program Files\Microsoft",
|
|
80
|
+
r"D:\Java",
|
|
81
|
+
]
|
|
82
|
+
for base in common_bases:
|
|
83
|
+
if not os.path.exists(base):
|
|
84
|
+
continue
|
|
85
|
+
try:
|
|
86
|
+
for entry in os.listdir(base):
|
|
87
|
+
exe = os.path.join(base, entry, "bin", "javaw.exe")
|
|
88
|
+
if os.path.exists(exe):
|
|
89
|
+
return exe
|
|
90
|
+
except Exception:
|
|
91
|
+
continue
|
|
92
|
+
|
|
93
|
+
# 策略5:PATH
|
|
94
|
+
try:
|
|
95
|
+
result = subprocess.run(
|
|
96
|
+
["where", "javaw"], capture_output=True, text=True, timeout=5
|
|
97
|
+
)
|
|
98
|
+
if result.returncode == 0:
|
|
99
|
+
path = result.stdout.strip().splitlines()[0]
|
|
100
|
+
if os.path.exists(path):
|
|
101
|
+
return path
|
|
102
|
+
except Exception:
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
def get_installed_versions(self):
|
|
108
|
+
"""获取已安装的版本列表"""
|
|
109
|
+
try:
|
|
110
|
+
return mll.utils.get_installed_versions(self.minecraft_dir)
|
|
111
|
+
except Exception:
|
|
112
|
+
return []
|
|
113
|
+
|
|
114
|
+
def get_current_version(self):
|
|
115
|
+
"""获取当前选中的版本"""
|
|
116
|
+
return self.config.get("current_version")
|
|
117
|
+
|
|
118
|
+
def set_current_version(self, version_name):
|
|
119
|
+
"""设置当前版本"""
|
|
120
|
+
self.config.set("current_version", version_name)
|
|
121
|
+
|
|
122
|
+
def launch_game(self, version=None, username=None, jar_path=None):
|
|
123
|
+
"""
|
|
124
|
+
启动 Minecraft 游戏
|
|
125
|
+
|
|
126
|
+
参数:
|
|
127
|
+
version: 版本名(如 "1.20.1"),为 None 则使用当前选中版本
|
|
128
|
+
username: 用户名,为 None 则使用配置中的用户名
|
|
129
|
+
jar_path: .jar 文件绝对路径,指定后忽略 version 参数
|
|
130
|
+
|
|
131
|
+
返回:
|
|
132
|
+
成功返回 True,失败返回 False
|
|
133
|
+
"""
|
|
134
|
+
if username is None:
|
|
135
|
+
username = self.config.get("username", "Player")
|
|
136
|
+
|
|
137
|
+
java_path = self.get_java_path()
|
|
138
|
+
if not java_path:
|
|
139
|
+
print("错误:未找到 Java,请手动设置 Java 路径")
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
if jar_path:
|
|
144
|
+
# 指定 jar 路径启动
|
|
145
|
+
if not os.path.exists(jar_path):
|
|
146
|
+
print(f"错误:jar 文件不存在 {jar_path}")
|
|
147
|
+
return False
|
|
148
|
+
|
|
149
|
+
# 获取版本目录作为游戏目录
|
|
150
|
+
game_dir = os.path.dirname(os.path.dirname(jar_path))
|
|
151
|
+
assets_dir = os.path.join(game_dir, "assets")
|
|
152
|
+
libs_dir = os.path.join(game_dir, "libraries")
|
|
153
|
+
|
|
154
|
+
command = [
|
|
155
|
+
java_path,
|
|
156
|
+
f"-Djava.library.path={libs_dir}",
|
|
157
|
+
"-cp", jar_path,
|
|
158
|
+
"net.minecraft.client.Main",
|
|
159
|
+
"--username", username,
|
|
160
|
+
"--version", os.path.basename(os.path.dirname(jar_path)),
|
|
161
|
+
"--gameDir", game_dir,
|
|
162
|
+
"--assetsDir", assets_dir,
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
print(f"启动 jar:{jar_path}")
|
|
166
|
+
else:
|
|
167
|
+
# 使用版本名启动
|
|
168
|
+
if version is None:
|
|
169
|
+
version = self.get_current_version()
|
|
170
|
+
|
|
171
|
+
if not version:
|
|
172
|
+
print("错误:未指定版本,且未设置当前版本")
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
options = {
|
|
176
|
+
"username": username,
|
|
177
|
+
"uuid": self.config.get("uuid", ""),
|
|
178
|
+
"token": self.config.get("token", ""),
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
command = mll.command.get_minecraft_command(
|
|
182
|
+
version, self.minecraft_dir, options
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# 替换 java 路径
|
|
186
|
+
if command and command[0] == "java":
|
|
187
|
+
command[0] = java_path
|
|
188
|
+
|
|
189
|
+
print(f"启动版本:{version}")
|
|
190
|
+
|
|
191
|
+
print(f"Java 路径:{java_path}")
|
|
192
|
+
print(f"用户名:{username}")
|
|
193
|
+
|
|
194
|
+
# 启动游戏
|
|
195
|
+
subprocess.Popen(command, cwd=self.minecraft_dir)
|
|
196
|
+
return True
|
|
197
|
+
|
|
198
|
+
except Exception as e:
|
|
199
|
+
print(f"启动失败:{e}")
|
|
200
|
+
return False
|
|
201
|
+
|
|
202
|
+
def install_version(self, version, minecraft_version=None, path=None):
|
|
203
|
+
"""
|
|
204
|
+
安装新版本
|
|
205
|
+
|
|
206
|
+
参数:
|
|
207
|
+
version: 版本名(如 "1.20.1")
|
|
208
|
+
minecraft_version: 对应的 MC 版本(通常和 version 相同)
|
|
209
|
+
path: 安装目录路径,为 None 则使用默认 .minecraft 目录
|
|
210
|
+
"""
|
|
211
|
+
if minecraft_version is None:
|
|
212
|
+
minecraft_version = version
|
|
213
|
+
|
|
214
|
+
target_dir = path if path else self.minecraft_dir
|
|
215
|
+
|
|
216
|
+
try:
|
|
217
|
+
print(f"正在安装版本 {version} 到 {target_dir}...")
|
|
218
|
+
mll.install.install_minecraft_version(
|
|
219
|
+
minecraft_version, target_dir
|
|
220
|
+
)
|
|
221
|
+
print(f"版本 {version} 安装成功")
|
|
222
|
+
return True
|
|
223
|
+
except Exception as e:
|
|
224
|
+
print(f"安装失败:{e}")
|
|
225
|
+
return False
|
|
226
|
+
|
|
227
|
+
def get_available_versions(self):
|
|
228
|
+
"""获取可下载的版本列表"""
|
|
229
|
+
try:
|
|
230
|
+
return mll.utils.get_available_versions(self.minecraft_dir)
|
|
231
|
+
except Exception:
|
|
232
|
+
return []
|
|
233
|
+
|
|
234
|
+
def search_versions(self, keyword):
|
|
235
|
+
"""搜索版本"""
|
|
236
|
+
all_versions = self.get_available_versions()
|
|
237
|
+
keyword = keyword.lower()
|
|
238
|
+
return [v for v in all_versions if keyword in v.get("id", "").lower()]
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def launch_game(version=None, username=None, jar_path=None):
|
|
242
|
+
"""
|
|
243
|
+
快捷函数:启动 Minecraft 游戏
|
|
244
|
+
|
|
245
|
+
用法:
|
|
246
|
+
import cml
|
|
247
|
+
cml.launch_game("1.20.1") # 通过版本名启动
|
|
248
|
+
cml.launch_game(jar_path="C:/MC/versions/1.20.1/1.20.1.jar") # 通过 jar 路径启动
|
|
249
|
+
"""
|
|
250
|
+
core = CMLCore()
|
|
251
|
+
return core.launch_game(version, username, jar_path)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def get_versions():
|
|
255
|
+
"""获取已安装版本列表"""
|
|
256
|
+
core = CMLCore()
|
|
257
|
+
return core.get_installed_versions()
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def set_version(version_name):
|
|
261
|
+
"""设置当前版本"""
|
|
262
|
+
core = CMLCore()
|
|
263
|
+
core.set_current_version(version_name)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def get_java_path():
|
|
267
|
+
"""获取 Java 路径"""
|
|
268
|
+
core = CMLCore()
|
|
269
|
+
return core.get_java_path()
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def download_version(version, path=None):
|
|
273
|
+
"""
|
|
274
|
+
快捷函数:下载安装 Minecraft 版本
|
|
275
|
+
|
|
276
|
+
用法:
|
|
277
|
+
import cml
|
|
278
|
+
cml.download_version("1.20.1") # 下载到默认目录
|
|
279
|
+
cml.download_version("1.20.1", "D:/MC") # 下载到指定目录
|
|
280
|
+
"""
|
|
281
|
+
core = CMLCore()
|
|
282
|
+
return core.install_version(version, path=path)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def list_versions():
|
|
286
|
+
"""快捷函数:获取可下载版本列表"""
|
|
287
|
+
core = CMLCore()
|
|
288
|
+
return core.get_available_versions()
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def search_versions(keyword):
|
|
292
|
+
"""快捷函数:搜索可下载版本"""
|
|
293
|
+
core = CMLCore()
|
|
294
|
+
return core.search_versions(keyword)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
__all__ = ["CMLCore", "launch_game", "get_versions", "set_version", "get_java_path", "download_version", "list_versions", "search_versions"]
|