hlmc 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.
- hlmc-0.1.0/PKG-INFO +14 -0
- hlmc-0.1.0/README.md +2 -0
- hlmc-0.1.0/pyproject.toml +21 -0
- hlmc-0.1.0/setup.cfg +4 -0
- hlmc-0.1.0/src/hlmc/__init__.py +0 -0
- hlmc-0.1.0/src/hlmc/main.py +216 -0
- hlmc-0.1.0/src/hlmc.egg-info/PKG-INFO +14 -0
- hlmc-0.1.0/src/hlmc.egg-info/SOURCES.txt +8 -0
- hlmc-0.1.0/src/hlmc.egg-info/dependency_links.txt +1 -0
- hlmc-0.1.0/src/hlmc.egg-info/top_level.txt +1 -0
hlmc-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hlmc
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Minecraft Launcher
|
|
5
|
+
Author-email: Brady <bradyreagan7@gamil.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
RUN python -m Handy Launcher.main
|
|
14
|
+
|
hlmc-0.1.0/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hlmc" # Must be unique on PyPI
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Brady", email="bradyreagan7@gamil.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "A Minecraft Launcher"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.8"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
Homepage = "https://github.com"
|
hlmc-0.1.0/setup.cfg
ADDED
|
File without changes
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import tkinter as tk
|
|
4
|
+
from tkinter import ttk, messagebox
|
|
5
|
+
import subprocess
|
|
6
|
+
import threading
|
|
7
|
+
import minecraft_launcher_lib
|
|
8
|
+
|
|
9
|
+
class HandyLauncher:
|
|
10
|
+
def __init__(self, root):
|
|
11
|
+
self.root = root
|
|
12
|
+
self.root.title("Handy Launcher")
|
|
13
|
+
self.root.geometry("620x475") # Expanded slightly for the new button layout
|
|
14
|
+
|
|
15
|
+
# Windows XP Luna Blue Color Palette
|
|
16
|
+
self.xp_blue = "#004E8A"
|
|
17
|
+
self.xp_bg = "#ECE9D8"
|
|
18
|
+
self.xp_border = "#7A96DF"
|
|
19
|
+
|
|
20
|
+
self.root.configure(bg=self.xp_bg)
|
|
21
|
+
|
|
22
|
+
# Classic system fonts
|
|
23
|
+
self.default_font = ("MS Sans Serif", 9)
|
|
24
|
+
self.bold_font = ("MS Sans Serif", 9, "bold")
|
|
25
|
+
|
|
26
|
+
# Configure Custom AppData Path: %APPDATA%\.handymclauncherversions
|
|
27
|
+
appdata_path = os.getenv("APPDATA")
|
|
28
|
+
if not appdata_path:
|
|
29
|
+
# Fallback for Linux/macOS testing
|
|
30
|
+
appdata_path = os.path.expanduser("~")
|
|
31
|
+
|
|
32
|
+
self.mc_dir = os.path.join(appdata_path, ".handymclauncherversions")
|
|
33
|
+
|
|
34
|
+
# Auto-create directory structure so it handles everything safely
|
|
35
|
+
os.makedirs(self.mc_dir, exist_ok=True)
|
|
36
|
+
|
|
37
|
+
self.init_ui()
|
|
38
|
+
|
|
39
|
+
def init_ui(self):
|
|
40
|
+
# 1. Iconic XP Top Banner
|
|
41
|
+
banner = tk.Frame(self.root, bg=self.xp_blue, height=45)
|
|
42
|
+
banner.pack(fill=tk.X, side=tk.TOP)
|
|
43
|
+
banner.pack_propagate(False)
|
|
44
|
+
|
|
45
|
+
banner_label = tk.Label(
|
|
46
|
+
banner, text="Handy Launcher v1.0",
|
|
47
|
+
font=("MS Sans Serif", 11, "bold"), fg="white", bg=self.xp_blue
|
|
48
|
+
)
|
|
49
|
+
banner_label.pack(side=tk.LEFT, padx=10, pady=10)
|
|
50
|
+
|
|
51
|
+
# 2. Main Window Layout (Sidebar + Content Box)
|
|
52
|
+
main_frame = tk.Frame(self.root, bg=self.xp_bg, bd=2, relief=tk.GROOVE)
|
|
53
|
+
main_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
|
54
|
+
|
|
55
|
+
# Left Sidebar (XP Taskpane Style)
|
|
56
|
+
sidebar = tk.Frame(main_frame, bg="#7A96DF", width=140, bd=1, relief=tk.SUNKEN)
|
|
57
|
+
sidebar.pack(fill=tk.Y, side=tk.LEFT, padx=2, pady=2)
|
|
58
|
+
sidebar.pack_propagate(False)
|
|
59
|
+
|
|
60
|
+
sb_title = tk.Label(sidebar, text="Launcher Tasks", font=self.bold_font, bg="#4A69B5", fg="white")
|
|
61
|
+
sb_title.pack(fill=tk.X)
|
|
62
|
+
|
|
63
|
+
for text in ["📂 Instances", "👤 Accounts", "⚙️ Settings"]:
|
|
64
|
+
btn = tk.Button(
|
|
65
|
+
sidebar, text=text, font=self.default_font, anchor="w",
|
|
66
|
+
bg="#D6E3F7", activebackground="#94B7E7", bd=1, relief=tk.RAISED
|
|
67
|
+
)
|
|
68
|
+
btn.pack(fill=tk.X, padx=5, pady=3)
|
|
69
|
+
|
|
70
|
+
# 3. Right Content Panel
|
|
71
|
+
content = tk.Frame(main_frame, bg=self.xp_bg)
|
|
72
|
+
content.pack(fill=tk.BOTH, expand=True, side=tk.RIGHT, padx=10, pady=10)
|
|
73
|
+
|
|
74
|
+
# Profile Group Box
|
|
75
|
+
group_box = tk.LabelFrame(
|
|
76
|
+
content, text="Instance Configuration", font=self.bold_font,
|
|
77
|
+
bg=self.xp_bg, bd=2, relief=tk.GROOVE
|
|
78
|
+
)
|
|
79
|
+
group_box.pack(fill=tk.X, padx=5, pady=5)
|
|
80
|
+
|
|
81
|
+
# Username Input
|
|
82
|
+
tk.Label(group_box, text="Username:", font=self.default_font, bg=self.xp_bg).grid(row=0, column=0, sticky="w", padx=5, pady=5)
|
|
83
|
+
self.username_input = tk.Entry(group_box, font=self.default_font, bg="white", bd=2, relief=tk.SUNKEN)
|
|
84
|
+
self.username_input.insert(0, "HandyPlayer")
|
|
85
|
+
self.username_input.grid(row=0, column=1, sticky="we", padx=5, pady=5)
|
|
86
|
+
|
|
87
|
+
# Version Selector List
|
|
88
|
+
tk.Label(group_box, text="Version:", font=self.default_font, bg=self.xp_bg).grid(row=1, column=0, sticky="w", padx=5, pady=5)
|
|
89
|
+
self.version_var = tk.StringVar(value="1.21.1")
|
|
90
|
+
|
|
91
|
+
version_list = [
|
|
92
|
+
"1.21.1", "1.21", "1.20.4", "1.20.1", "1.19.4", "1.18.2",
|
|
93
|
+
"1.17.1", "1.16.5", "1.12.2", "1.8.9", "1.7.10", "1.6.4",
|
|
94
|
+
"1.5.2", "1.4.7", "1.2.5", "b1.7.3", "a1.1.2_01"
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
self.version_select = ttk.Combobox(group_box, textvariable=self.version_var, values=version_list, state="readonly")
|
|
98
|
+
self.version_select.grid(row=1, column=1, sticky="we", padx=5, pady=5)
|
|
99
|
+
|
|
100
|
+
# Path Frame to hold Path label and Open Folder button together
|
|
101
|
+
path_frame = tk.Frame(content, bg=self.xp_bg)
|
|
102
|
+
path_frame.pack(fill=tk.X, side=tk.TOP, anchor="w", padx=5, pady=5)
|
|
103
|
+
|
|
104
|
+
# Path Confirmation Label
|
|
105
|
+
path_label = tk.Label(
|
|
106
|
+
path_frame, text="Target: ", font=("MS Sans Serif", 8), bg=self.xp_bg, fg="#555555"
|
|
107
|
+
)
|
|
108
|
+
display_path = self.mc_dir if len(self.mc_dir) < 45 else f"...{self.mc_dir[-45:]}"
|
|
109
|
+
path_label.config(text=f"Target: {display_path}")
|
|
110
|
+
path_label.pack(side=tk.LEFT, padx=(0, 10))
|
|
111
|
+
|
|
112
|
+
# Windows XP-style Open Instance Folder Button
|
|
113
|
+
self.btn_open_folder = tk.Button(
|
|
114
|
+
path_frame, text="Open Folder", font=("MS Sans Serif", 8),
|
|
115
|
+
bg="#F0F0F0", activebackground="#DCDCDC", bd=1, relief=tk.RAISED,
|
|
116
|
+
command=self.open_instance_folder
|
|
117
|
+
)
|
|
118
|
+
self.btn_open_folder.pack(side=tk.LEFT)
|
|
119
|
+
|
|
120
|
+
# Mod Loader Selection
|
|
121
|
+
mod_box = tk.LabelFrame(content, text="Mod Loader", font=self.bold_font, bg=self.xp_bg, bd=2, relief=tk.GROOVE)
|
|
122
|
+
mod_box.pack(fill=tk.X, padx=5, pady=5)
|
|
123
|
+
|
|
124
|
+
self.mod_var = tk.StringVar(value="vanilla")
|
|
125
|
+
tk.Radiobutton(mod_box, text="Vanilla", variable=self.mod_var, value="vanilla", font=self.default_font, bg=self.xp_bg).pack(side=tk.LEFT, padx=10)
|
|
126
|
+
tk.Radiobutton(mod_box, text="Fabric", variable=self.mod_var, value="fabric", font=self.default_font, bg=self.xp_bg).pack(side=tk.LEFT, padx=10)
|
|
127
|
+
tk.Radiobutton(mod_box, text="Forge", variable=self.mod_var, value="forge", font=self.default_font, bg=self.xp_bg).pack(side=tk.LEFT, padx=10)
|
|
128
|
+
|
|
129
|
+
# Status text indicator for automated tasks
|
|
130
|
+
self.status_label = tk.Label(content, text="Ready.", font=self.default_font, bg=self.xp_bg, anchor="w")
|
|
131
|
+
self.status_label.pack(fill=tk.X, side=tk.BOTTOM, padx=5)
|
|
132
|
+
|
|
133
|
+
# 4. Classic Launch Button
|
|
134
|
+
self.btn_launch = tk.Button(
|
|
135
|
+
content, text="Launch Game", font=("MS Sans Serif", 10, "bold"),
|
|
136
|
+
bg="#E1E1E1", activebackground="#C1C1C1", bd=3, relief=tk.RAISED,
|
|
137
|
+
command=self.start_launch_thread
|
|
138
|
+
)
|
|
139
|
+
self.btn_launch.pack(fill=tk.X, side=tk.BOTTOM, padx=5, pady=5)
|
|
140
|
+
|
|
141
|
+
def open_instance_folder(self):
|
|
142
|
+
# Native OS system file opening handler
|
|
143
|
+
try:
|
|
144
|
+
if sys.platform == "win32":
|
|
145
|
+
os.startfile(self.mc_dir)
|
|
146
|
+
elif sys.platform == "darwin": # macOS
|
|
147
|
+
subprocess.Popen(["open", self.mc_dir])
|
|
148
|
+
else: # Linux
|
|
149
|
+
subprocess.Popen(["xdg-open", self.mc_dir])
|
|
150
|
+
except Exception as e:
|
|
151
|
+
messagebox.showerror("Error", f"Could not open directory: {e}")
|
|
152
|
+
|
|
153
|
+
def update_status(self, text):
|
|
154
|
+
self.status_label.config(text=text)
|
|
155
|
+
|
|
156
|
+
def start_launch_thread(self):
|
|
157
|
+
self.btn_launch.config(state=tk.DISABLED, text="Processing...")
|
|
158
|
+
thread = threading.Thread(target=self.launch_game, daemon=True)
|
|
159
|
+
thread.start()
|
|
160
|
+
|
|
161
|
+
def launch_game(self):
|
|
162
|
+
try:
|
|
163
|
+
username = self.username_input.get()
|
|
164
|
+
version = self.version_var.get()
|
|
165
|
+
|
|
166
|
+
# Step 1: Handle Core Downloader Engine
|
|
167
|
+
self.update_status(f"Status: Downloading base runtime binaries for {version}...")
|
|
168
|
+
minecraft_launcher_lib.install.install_minecraft_version(version, self.mc_dir)
|
|
169
|
+
active_version = version
|
|
170
|
+
|
|
171
|
+
# Step 2: Automated Mod Scaffolding Setup
|
|
172
|
+
if self.mod_var.get() == "fabric":
|
|
173
|
+
self.update_status("Status: Fetching and resolving Fabric dependencies...")
|
|
174
|
+
try:
|
|
175
|
+
fabric_ver = minecraft_launcher_lib.fabric.get_latest_loader_version()
|
|
176
|
+
minecraft_launcher_lib.fabric.install_fabric(version, fabric_ver, self.mc_dir)
|
|
177
|
+
active_version = minecraft_launcher_lib.fabric.get_fabric_version_list()["id"]
|
|
178
|
+
except Exception:
|
|
179
|
+
messagebox.showwarning("Warning", "Fabric may not support this specific version. Attempting Vanilla fallback.")
|
|
180
|
+
|
|
181
|
+
elif self.mod_var.get() == "forge":
|
|
182
|
+
self.update_status("Status: Scraping Forge repositories and constructing profiles...")
|
|
183
|
+
try:
|
|
184
|
+
forge_ver = minecraft_launcher_lib.forge.get_latest_forge_version(version)
|
|
185
|
+
minecraft_launcher_lib.forge.install_forge_version(forge_ver, self.mc_dir)
|
|
186
|
+
active_version = forge_ver
|
|
187
|
+
except Exception:
|
|
188
|
+
messagebox.showwarning("Warning", "Forge profile not found for this version. Attempting Vanilla fallback.")
|
|
189
|
+
|
|
190
|
+
# Ensure subfolders like 'mods' exist right away so users can find them instantly
|
|
191
|
+
os.makedirs(os.path.join(self.mc_dir, "mods"), exist_ok=True)
|
|
192
|
+
|
|
193
|
+
# Step 3: Build Launch Environment Execution Options
|
|
194
|
+
self.update_status("Status: Structuring JVM launch parameters...")
|
|
195
|
+
options = {
|
|
196
|
+
"username": username,
|
|
197
|
+
"uuid": "",
|
|
198
|
+
"token": "",
|
|
199
|
+
"gameDirectory": self.mc_dir
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
cmd = minecraft_launcher_lib.command.get_minecraft_command(active_version, self.mc_dir, options)
|
|
203
|
+
|
|
204
|
+
self.update_status("Status: Handing execution thread over to Minecraft.")
|
|
205
|
+
subprocess.call(cmd)
|
|
206
|
+
|
|
207
|
+
except Exception as e:
|
|
208
|
+
messagebox.showerror("Error", f"Execution system failure: {e}")
|
|
209
|
+
finally:
|
|
210
|
+
self.btn_launch.config(state=tk.NORMAL, text="Launch Game")
|
|
211
|
+
self.update_status("Status: Ready.")
|
|
212
|
+
|
|
213
|
+
if __name__ == "__main__":
|
|
214
|
+
root = tk.Tk()
|
|
215
|
+
app = HandyLauncher(root)
|
|
216
|
+
root.mainloop()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hlmc
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Minecraft Launcher
|
|
5
|
+
Author-email: Brady <bradyreagan7@gamil.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
RUN python -m Handy Launcher.main
|
|
14
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hlmc
|