Skip to content
This repository was archived by the owner on Aug 26, 2022. It is now read-only.

Commit b27ec82

Browse files
v0.6 (cosmetic changes)
1 parent 6c57ec6 commit b27ec82

3 files changed

Lines changed: 75 additions & 104 deletions

File tree

APLauncher.pyw

Lines changed: 39 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import threading
1414
import re
1515
import shutil
1616
import datetime
17+
import webview
1718

1819
class SettingsPage(Frame):
1920

@@ -48,7 +49,6 @@ class LabeledEntry(Frame):
4849
def set(self, val):
4950
self.entryvar.set(val)
5051

51-
5252
class App:
5353

5454
def __init__(self):
@@ -66,16 +66,13 @@ class App:
6666
os.mkdir("assets")
6767
if not os.path.isdir("temp"):
6868
os.mkdir("temp")
69-
urlretrieve("https://raw.github.com/SpacePython12/AP-Launcher/main/assets/background.png", "assets/background.png")
69+
urlretrieve(url="https://raw.github.com/SpacePython12/AP-Launcher/main/assets/background.png", filename="assets/background.png")
70+
urlretrieve(url="https://raw.github.com/SpacePython12/AP-Launcher/main/assets/icon.ico", filename="assets/icon.ico")
7071
self.background = ImageTk.PhotoImage(Image.open("assets/background.png"))
72+
self.icon = ImageTk.PhotoImage(file="assets/icon.ico")
73+
self.win.iconphoto(True, self.icon)
7174
self.background2 = Label(self.mainframe, image=self.background)
7275
self.background2.grid(column=0, row=0, sticky="nsew")
73-
self.buttonframe = Frame(self.mainframe)
74-
self.buttonframe.grid(column=0, row=1)
75-
self.accountlabel = Label(self.buttonframe, text="Account: ")
76-
self.accountlabel.grid(column=1, row=0)
77-
self.accountbutton = Button(self.buttonframe, text="Choose...", command=lambda: self.accountdialog())
78-
self.accountbutton.grid(column=2, row=0)
7976
self.versionvar = StringVar()
8077
self.get_versions()
8178
try:
@@ -97,6 +94,30 @@ class App:
9794
self.versionvar.set(self.versions[0])
9895
except IndexError:
9996
pass
97+
self.accesstoken = self.cache["accessid"]["id"]
98+
self.username = self.cache["username"]
99+
self.accounttype = "microsoft"
100+
self.premium = self.cache["premium"]
101+
self.buttonframe = Frame(self.mainframe)
102+
self.buttonframe.grid(column=0, row=1)
103+
self.login_frame = Frame(self.buttonframe)
104+
self.login_frame.grid(column=0, row=0)
105+
self.connect_label = Label(self.login_frame, text=" Premium mode: ")
106+
self.connect_label.grid(column=2, row=0)
107+
self.connect_var = IntVar(self.login_frame)
108+
self.connect_var.set(self.premium)
109+
self.connect_box = Checkbutton(self.login_frame, variable=self.connect_var)
110+
self.connect_box.grid(column=3, row=0)
111+
self.username_var = StringVar(self.login_frame)
112+
self.username_var.set(str(self.username))
113+
self.username_label = Label(self.login_frame, text="Username:")
114+
self.username_label.grid(column=0, row=0)
115+
self.username_entry = Entry(self.login_frame, textvariable=self.username_var)
116+
self.username_entry.grid(column=1, row=0)
117+
self.login_button = Button(self.buttonframe, text="Login", command=lambda: self.login(self.username_var.get(), premium=bool(self.connect_var.get())))
118+
self.login_button.grid(column=2, row=0)
119+
self.toggle_premium_mode(self.username_label, self.username_entry, self.connect_var)
120+
self.connect_box.config(command=lambda: self.toggle_premium_mode(self.username_label, self.username_entry, self.connect_var))
100121
self.versionlabel = Label(self.buttonframe, text="Version: ")
101122
self.versionlabel.grid(column=3, row=0)
102123
self.versionlist = Combobox(self.buttonframe, textvariable=self.versionvar, width=30)
@@ -145,16 +166,6 @@ class App:
145166
self.profadd.grid(column=0, row=7, sticky="nsew")
146167
self.update_profiles(self.versionvar.get())
147168
self.profilelist.bind("<<ComboboxSelected>>", lambda x: self.update_profiles(self.versionvar.get()))
148-
self.accesstoken = self.cache["accessid"]["id"]
149-
self.username = self.cache["username"]
150-
self.accounttype = "microsoft"
151-
self.premium = self.cache["premium"]
152-
if not self.username == "":
153-
if self.premium:
154-
type_ = "Premium"
155-
else:
156-
type_ = "Non-Premium"
157-
self.accountbutton.config(text=f"{self.username} ({type_})")
158169

159170
def kill_process(self):
160171
"""Kills the running Minecraft process. I dont really know what to do about this function..."""
@@ -175,7 +186,6 @@ class App:
175186
return
176187
else:
177188
messagebox.showinfo("Success", "The process was successfully terminated.")
178-
179189

180190
def do_popup(self, event):
181191
"""Popup handler for the process killer"""
@@ -225,41 +235,6 @@ class App:
225235
"""Gets launcher profiles"""
226236
return json.load(open(os.path.join(self.minecraftdir, "launcher_profiles.json")))
227237

228-
def accountdialog(self):
229-
"""Login dialog"""
230-
dwin = Toplevel(self.win)
231-
dwin.title("Accounts")
232-
login_frame = Frame(dwin)
233-
login_frame.pack(side="left")
234-
connect_label = Label(login_frame, text="Premium mode: ")
235-
connect_label.grid(column=0, row=0)
236-
connect_var = IntVar(login_frame)
237-
connect_var.set(self.premium)
238-
connect_box = Checkbutton(login_frame, variable=connect_var)
239-
connect_box.grid(column=1, row=0)
240-
type_label = Label(login_frame, text="Legacy (Mojang) account:")
241-
type_label.grid(column=0, row=1)
242-
type_var = IntVar(login_frame)
243-
type_var.set(0)
244-
type_box = Checkbutton(login_frame, variable=type_var)
245-
type_box.grid(column=1, row=1)
246-
username_var = StringVar(login_frame)
247-
username_var.set(str(self.username))
248-
username_label = Label(login_frame, text="Email:")
249-
username_label.grid(column=0, row=2)
250-
username_entry = Entry(login_frame, textvariable=username_var)
251-
username_entry.grid(column=1, row=2)
252-
password_var = StringVar(login_frame)
253-
password_label = Label(login_frame, text="Password:")
254-
password_label.grid(column=0, row=3)
255-
password_entry = Entry(login_frame, textvariable=password_var, show="•")
256-
password_entry.grid(column=1, row=3)
257-
login_button = Button(login_frame, text="Login", command=lambda: self.login(dwin, username_var.get(), password_var.get(), premium=bool(connect_var.get())))
258-
login_button.grid(column=0, row=4)
259-
self.toggle_premium_mode(username_label, password_label, password_entry, connect_var)
260-
connect_box.config(command=lambda: self.toggle_premium_mode(username_label, password_label, password_entry, connect_var))
261-
type_box.config(command=lambda: self.toggle_account_type(type_var))
262-
263238
def update_profiles(self, name):
264239
"""Updates special game arguments"""
265240
try:
@@ -286,36 +261,23 @@ class App:
286261
self.versionlist["values"] = self.versions
287262
self.profilelist["values"] = self.versions
288263
json.dump(open(os.path.join(self.minecraftdir, "launcher_profiles.json"), "w"), self.accounts)
289-
290264

291-
def login(self, win, username, password, error=True, premium=False):
265+
def login(self, username, error=True, premium=False):
292266
"""True login process that requests an access token. (Unfinished)"""
293-
if not username == "":
294-
if premium:
295-
type_ = "Premium"
296-
else:
297-
type_ = "Non-Premium"
298-
self.accountbutton.config(text=f"{username} ({type_})")
299267
if username == "":
300268
messagebox.showinfo("Try again", "No login info was provided.")
301-
win.lift()
302269
return
303270
if not premium:
304271
self.accesstoken = ""
305272
self.username = username
306273
self.cache["username"] = username
307274
self.cache["premium"] = premium
308-
win.withdraw()
309275
else:
310276
messagebox.showinfo("Not yet implemented", "Currently, AP Launcher does not support premium accounts.")
311-
win.lift()
312277
return
313-
try:
314-
clienttoken = self.accounts["clientToken"]
315-
except:
316-
clienttoken = str(uuid.uuid4())
317-
self.accounts["clientToken"] = clienttoken
318-
win.withdraw()
278+
url = ""
279+
login_window = webview.create_window("Login to your Microsoft account", url)
280+
webview.start()
319281

320282
def start_game(self):
321283
"""Starts the game"""
@@ -366,7 +328,6 @@ class App:
366328
line = sb.stdout.readline().rstrip()
367329
if not line == "":
368330
self.update_procscreen(line)
369-
print("Process finished")
370331
self.playbutton.config(state="normal", text="\nPlay\n")
371332
self.playcontext.entryconfigure(0, state="disabled")
372333

@@ -375,22 +336,15 @@ class App:
375336
self.processtext.config(state="normal")
376337
self.processtext.insert("end", text+"\n")
377338
self.processtext.config(state="disabled")
339+
self.processtext.see("end")
378340

379-
def toggle_premium_mode(self, ul, pl, pe, cv):
341+
def toggle_premium_mode(self, ul, ue, cv):
380342
if cv.get() == 1:
381-
pl.grid(column=0, row=3)
382-
ul.config(text="Email:")
383-
pe.grid(column=1, row=3)
343+
ul.grid_forget()
344+
ue.grid_forget()
384345
elif cv.get() == 0:
385-
pl.grid_forget()
386-
ul.config(text="Username:")
387-
pe.grid_forget()
388-
389-
def toggle_account_type(self, tv):
390-
if tv.get() == 1:
391-
self.accounttype = "mojang"
392-
elif tv.get() == 0:
393-
self.accounttype = "microsoft"
346+
ul.grid(column=0, row=0)
347+
ue.grid(column=1, row=0)
394348

395349
def get_latest_version(self, type_):
396350
versions = [x[0] for x in os.walk(os.path.join(self.minecraftdir, "versions"))]

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ You may need to install some libraries, including...
1616
In the future, I will link some version packages as backups if Minecraft is blocked on your network.
1717

1818
# Changelog:
19-
* Version installers are now better supported
20-
* AP Launcher is now more stable after installation
21-
* AP Launcher now can run Minecraft!
22-
- (Note: assets are being kinked out, for now you will have to play without sound)
23-
19+
* Made some cosmetic changes.
20+
* Added an icon for the launcher.
21+
* Minecraft sounds and other assets are now downloaded at the start.

launcher_process.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,20 @@
77
import threading
88
import uuid as uuidlib
99
from urllib.request import urlretrieve
10+
from urllib.error import HTTPError
1011
import shutil
1112
import datetime
1213

1314
# Base program derived from https://stackoverflow.com/questions/14531917/launch-minecraft-from-command-line-username-and-password-as-prefix
1415

15-
"""
16-
Debug output
17-
"""
16+
1817
def debug(str):
18+
"""Debug output"""
1919
if os.getenv('DEBUG') != None:
2020
print(str)
2121

22-
"""
23-
[Gets the natives_string toprepend to the jar if it exists. If there is nothing native specific, returns and empty string]
24-
"""
2522
def get_natives_string(lib):
23+
"""[Gets the natives_string to prepend to the jar if it exists. If there is nothing native specific, returns and empty string]"""
2624
arch = ""
2725
if platform.architecture()[0] == "64bit":
2826
arch = "64"
@@ -46,11 +44,8 @@ def get_natives_string(lib):
4644

4745
return nativesFile
4846

49-
50-
"""
51-
[Parses "rule" subpropery of library object, testing to see if should be included]
52-
"""
5347
def should_use_library(lib):
48+
"""[Parses "rule" subpropery of library object, testing to see if should be included]"""
5449
def rule_says_yes(rule):
5550
useLib = None
5651

@@ -85,10 +80,8 @@ def rule_says_yes(rule):
8580

8681
return shouldUseLibrary
8782

88-
"""
89-
[Get string of all libraries to add to java classpath]
90-
"""
9183
def get_classpath(lib, mcDir):
84+
"""[Get string of all libraries to add to java classpath]"""
9285
cp = []
9386

9487
for i in lib["libraries"]:
@@ -129,6 +122,27 @@ def move_libraries(mcdir, dest, libjson, cp, version):
129122
print(f"{name} successfully moved to natives folder.")
130123
index += 1
131124

125+
def download_asset(hash_, failedlist):
126+
try:
127+
urlretrieve(url=f"https://resources.download.minecraft.net/{hash_[:2]}/{hash_}", filename=os.path.join(assetsDir, f"objects/{hash_[:2]}/{hash_}"))
128+
except HTTPError:
129+
failedlist.append(hash_)
130+
131+
def download_assets(assetsdir, assetindex):
132+
failedlist = []
133+
for hash_ in [assetindex["objects"][asset]["hash"] for asset in list(assetindex["objects"].keys())]:
134+
if not os.path.isdir(os.path.join(assetsDir, f"objects/{hash_[:2]}")):
135+
os.mkdir(os.path.join(assetsDir, f"objects/{hash_[:2]}"))
136+
if not os.path.isfile(os.path.join(assetsDir, f"objects/{hash_[:2]}/{hash_}")):
137+
thread = threading.Thread(None, lambda: download_asset(hash_, failedlist))
138+
thread.start()
139+
for hash_ in failedlist:
140+
if not os.path.isdir(os.path.join(assetsDir, f"objects/{hash_[:2]}")):
141+
os.mkdir(os.path.join(assetsDir, f"objects/{hash_[:2]}"))
142+
if not os.path.isfile(os.path.join(assetsDir, f"objects/{hash_[:2]}/{hash_}")):
143+
thread = threading.Thread(None, lambda: download_asset(hash_, failedlist))
144+
thread.start()
145+
132146
try:
133147
username = sys.argv[sys.argv.index("-username")+1]
134148
version = sys.argv[sys.argv.index("-version")+1]
@@ -147,6 +161,11 @@ def move_libraries(mcdir, dest, libjson, cp, version):
147161
clientJson = json.load(
148162
open(os.path.join(mcDir, 'versions', version, f'{version}.json'))
149163
)
164+
assetJson = json.load(
165+
open(os.path.join(mcDir, 'assets/indexes', f'{clientJson["assets"]}.json'))
166+
)
167+
assetsDir = os.path.join(mcDir, 'assets')
168+
download_assets(assetsDir, assetJson)
150169

151170
additionalArgs = []
152171

@@ -204,7 +223,7 @@ def move_libraries(mcdir, dest, libjson, cp, version):
204223
'--gameDir',
205224
mcDir,
206225
'--assetsDir',
207-
os.path.join(mcDir, 'assets'),
226+
assetsDir,
208227
'--assetIndex',
209228
assetIndex,
210229
'--uuid',

0 commit comments

Comments
 (0)