Skip to content

Commit fd8c83a

Browse files
Add files via upload
1 parent 0786aee commit fd8c83a

File tree

2 files changed

+214
-0
lines changed

2 files changed

+214
-0
lines changed

src/Launcher.py

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
import os
2+
import tkinter as tk
3+
from tkinter import messagebox, simpledialog, ttk
4+
import requests
5+
import json
6+
import subprocess
7+
import platform
8+
from PIL import Image, ImageTk
9+
import threading
10+
11+
LAUNCHER_DIR = "launcherData"
12+
LOGIN_FILE = os.path.join(LAUNCHER_DIR, "login.dat")
13+
FILE_DOWNLOADS = {
14+
"./client.jar": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/client.jar",
15+
"launcherData/bg.png": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/launcherData/bg.png",
16+
"launcherData/logo.png": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/launcherData/bg.png",
17+
"libraries/lwjgl_util.jar": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/libraries/lwjgl_util.jar",
18+
"libraries/lwjgl.jar": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/libraries/lwjgl.jar",
19+
"libraries/jinput.jar": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/libraries/jinput.jar",
20+
"libraries/json-20210307.jar": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/libraries/json-20210307.jar",
21+
"natives/OpenAL64.dll": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/OpenAL64.dll",
22+
"natives/OpenAL32.dll": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/OpenAL32.dll",
23+
"natives/lwjgl64.dll": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/lwjgl64.dll",
24+
"natives/lwjgl.dll": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/lwjgl.dll",
25+
"natives/libopenal64.so": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/libopenal64.so",
26+
"natives/libopenal.so": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/libopenal.so",
27+
"natives/liblwjgl64.so": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/liblwjgl64.so",
28+
"natives/liblwjgl.so": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/liblwjgl.so",
29+
"natives/libjinput-linux64.so": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/libjinput-linux64.so",
30+
"natives/libjinput-linux.so": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/libjinput-linux.so",
31+
"natives/jinput-raw_64.dll": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/jinput-raw_64.dll",
32+
"natives/jinput-raw.dll": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/jinput-raw.dll",
33+
"natives/jinput-dx8_64.dll": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/jinput-dx8_64.dll",
34+
"natives/jinput-dx8.dll": "https://github.com/goldenboys2011/EndlessLauncher/raw/refs/heads/latest/natives/jinput-dx8.dll"
35+
}
36+
37+
38+
class LauncherApp:
39+
def __init__(self, root):
40+
self.root = root
41+
self.root.title("Endless Beta Launcher")
42+
self.ram_mb = "1024"
43+
self.login_method = tk.StringVar(value="OSMC")
44+
self.username = tk.StringVar()
45+
self.password = tk.StringVar()
46+
47+
48+
49+
def build_ui(self):
50+
# Load bg tile image
51+
self.bg_tile = Image.open("launcherData/bg.png").resize((32, 32))
52+
self.bg_tile_tk = ImageTk.PhotoImage(self.bg_tile)
53+
54+
# Optional: Load logo
55+
# self.logo = Image.open("launcherData/logo.png").resize((200, 100), Image.ANTIALIAS)
56+
# self.logo_tk = ImageTk.PhotoImage(self.logo)
57+
58+
canvas = tk.Canvas(self.root, width=300, height=400)
59+
canvas.pack(fill="both", expand=True)
60+
61+
for x in range(0, 800, self.bg_tile.width):
62+
for y in range(0, 600, self.bg_tile.height):
63+
canvas.create_image(x, y, image=self.bg_tile_tk, anchor="nw")
64+
65+
frame = tk.Frame(canvas, bg="#ffffff", bd=0)
66+
frame.place(relx=0.5, rely=0.5, anchor="center")
67+
68+
tk.Label(frame, text="Login Method:", bg="white").pack()
69+
login_menu = ttk.Combobox(frame, textvariable=self.login_method, values=["OSMC", "Microsoft"], state="readonly")
70+
login_menu.pack()
71+
72+
tk.Label(frame, text="Username:", bg="white").pack()
73+
self.username_entry = tk.Entry(frame, textvariable=self.username)
74+
self.username_entry.pack()
75+
76+
tk.Label(frame, text="Password:", bg="white").pack()
77+
self.password_entry = tk.Entry(frame, textvariable=self.password, show="*")
78+
self.password_entry.pack()
79+
80+
launch_button = tk.Button(frame, text="Launch", command=self.launch)
81+
launch_button.pack(pady=(10, 5))
82+
83+
settings_button = tk.Button(frame, text="Settings", command=self.open_settings)
84+
settings_button.pack()
85+
86+
creds = self.load_credentials()
87+
if creds:
88+
self.login_method.set(creds[0])
89+
self.username_entry.insert(0, creds[1])
90+
self.password_entry.insert(0, creds[2])
91+
92+
def open_settings(self):
93+
new_ram = simpledialog.askstring("Settings", "Enter RAM in MB:", initialvalue=self.ram_mb)
94+
if new_ram:
95+
self.ram_mb = new_ram.strip()
96+
97+
def show_alert(self, message):
98+
messagebox.showinfo("Info", message)
99+
100+
def save_credentials(self):
101+
os.makedirs(LAUNCHER_DIR, exist_ok=True)
102+
with open(LOGIN_FILE, "w") as f:
103+
f.write(f"{self.login_method.get()}\n{self.username.get()}\n{self.password.get()}")
104+
105+
def load_credentials(self):
106+
if not os.path.exists(LOGIN_FILE):
107+
return
108+
with open(LOGIN_FILE) as f:
109+
lines = f.read().splitlines()
110+
if len(lines) == 3:
111+
self.login_method.set(lines[0])
112+
self.username.set(lines[1])
113+
self.password.set(lines[2])
114+
115+
def authenticate_with_osmc(self, username, password):
116+
url = "https://os-mc.net/api/v1/authenticate"
117+
data = {"username": username, "password": password}
118+
headers = {"Content-Type": "application/json"}
119+
response = requests.post(url, json=data, headers=headers)
120+
return response.json()
121+
122+
def launch(self):
123+
method = self.login_method.get()
124+
username = self.username.get()
125+
password = self.password.get()
126+
127+
if method == "OSMC":
128+
try:
129+
response = self.authenticate_with_osmc(username, password)
130+
if response.get("success"):
131+
profile = response["selectedProfile"]
132+
player_name = profile["name"]
133+
uuid = profile["id"]
134+
self.save_credentials()
135+
self.launch_game(player_name, uuid, "osmc")
136+
else:
137+
self.show_alert("Authentication failed.")
138+
except Exception as e:
139+
print(e)
140+
self.show_alert("Login failed.")
141+
else:
142+
self.show_alert("Microsoft login not implemented.")
143+
144+
def launch_game(self, username, uuid, launch_type):
145+
print(f"Launching Minecraft for: Username: {username}, UUID: {uuid}, RAM: {self.ram_mb}MB, Type: {launch_type}")
146+
java_exec = "javaw" if platform.system() == "Windows" else "java"
147+
148+
classpath = os.pathsep.join([
149+
"client.jar",
150+
"libraries/json.jar",
151+
"libraries/lwjgl.jar",
152+
"libraries/lwjgl_util.jar"
153+
])
154+
155+
params = [
156+
java_exec,
157+
f"-Xmx{self.ram_mb}M",
158+
"-Djava.library.path=natives",
159+
"-classpath", classpath,
160+
"net.minecraft.client.Minecraft",
161+
username,
162+
uuid,
163+
launch_type
164+
]
165+
166+
try:
167+
root.withdraw() # Hide the main window for now
168+
169+
threading.Thread(target=subprocess.run(params, check=True)).start()
170+
171+
root.deiconify()
172+
print("Game exited successfully.")
173+
except subprocess.CalledProcessError as e:
174+
print("Game process failed:", e)
175+
self.show_alert("Game launch failed.")
176+
177+
178+
if __name__ == "__main__":
179+
root = tk.Tk()
180+
root.withdraw() # Hide the main window for now
181+
download_window = tk.Toplevel()
182+
download_window.title("Preparing Launcher")
183+
download_window.geometry("300x100")
184+
download_window.resizable(False, False)
185+
label = tk.Label(download_window, text="Downloading required files...")
186+
label.pack(pady=10)
187+
progress = ttk.Progressbar(download_window, mode="determinate", maximum=len(FILE_DOWNLOADS))
188+
progress.pack(pady=10, padx=20, fill="x")
189+
190+
def download_and_continue():
191+
total = len(FILE_DOWNLOADS)
192+
for i, (local_path, url) in enumerate(FILE_DOWNLOADS.items()):
193+
try:
194+
os.makedirs(os.path.dirname(local_path), exist_ok=True)
195+
if not os.path.exists(local_path):
196+
response = requests.get(url)
197+
with open(local_path, "wb") as f:
198+
f.write(response.content)
199+
progress["value"] = i + 1
200+
label.config(text=f"Downloading {os.path.basename(local_path)}")
201+
download_window.update_idletasks()
202+
except Exception as e:
203+
print(f"Error downloading {local_path}: {e}")
204+
205+
# Once done, close the popup and show main window
206+
download_window.destroy()
207+
root.deiconify()
208+
app = LauncherApp(root)
209+
app.build_ui()
210+
211+
212+
threading.Thread(target=download_and_continue).start()
213+
root.mainloop()

src/buildCommand.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
venv/bin/pyinstaller --name Launcher --noconsole Launcher.py --collect-submodules PIL

0 commit comments

Comments
 (0)