-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsourcefix.py
More file actions
288 lines (243 loc) · 11.5 KB
/
sourcefix.py
File metadata and controls
288 lines (243 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
import tkinter as tk
from tkinter import filedialog, messagebox
import os
import subprocess
import requests
import time
from PIL import Image, ImageTk
import shutil # Import for folder deletion
import webbrowser # For opening browser search
import sys
import platform # For detecting the operating system
import pkgutil # For accessing embedded resources
# List of SDKs to choose from, with names and corresponding numeric values
SDK_LIST = [
("Source SDK 2006", "215"),
("Source SDK 2007", "218"),
("Source SDK Base 2013 MP", "243750"),
("Source SDK Base 2013 SP", "243730"),
]
# Function to extract bat2exe.exe from the program resources into a specific folder
def extract_bat_to_exe(destination):
try:
# Check if the app is running from a packaged state (e.g., PyInstaller)
if hasattr(sys, '_MEIPASS'):
# Path to the temporary folder where bundled resources are extracted
bat2exe_source = os.path.join(sys._MEIPASS, "bat2exe.exe")
else:
# Fallback for development when running directly from script
bat2exe_source = "bat2exe.exe"
# Ensure the source file exists
if not os.path.exists(bat2exe_source):
raise FileNotFoundError(f"bat2exe.exe not found at {bat2exe_source}")
# Copy the bat2exe.exe to the destination
shutil.copy(bat2exe_source, destination)
# Confirm the file exists after extraction
if not os.path.exists(destination):
raise FileNotFoundError(f"Failed to extract bat2exe.exe to {destination}")
return True
except Exception as e:
messagebox.showerror("Error", f"Failed to extract bat2exe.exe: {str(e)}")
return False
# Function to locate Steam directory (for Windows only)
def locate_steam():
steam_path = ""
if platform.system() == "Windows":
# Windows-specific Steam directory selection
steam_path = filedialog.askdirectory(title="Select Steam Directory")
if steam_path:
steam_exe = os.path.join(steam_path, "Steam.exe")
if os.path.exists(steam_exe):
steam_entry.delete(0, tk.END)
steam_entry.insert(0, steam_path)
else:
messagebox.showwarning("Warning", "Steam.exe not found in the selected directory.")
else:
messagebox.showinfo("Info", "Steam directory not selected.")
# Function to locate Sourcemods directory
def locate_sourcemods():
sourcemods_path = filedialog.askdirectory(title="Select Sourcemods Directory")
if sourcemods_path:
sourcemods_var.set(sourcemods_path)
else:
messagebox.showinfo("Info", "Sourcemods directory not selected.")
# Function to locate Mod directory (specific mod within sourcemods)
def locate_mod():
mod_path = filedialog.askdirectory(title="Select Mod Directory (within Sourcemods)")
if mod_path:
mod_var.set(mod_path)
else:
messagebox.showinfo("Info", "Mod directory not selected.")
# Updated function to detect SteamAppId and select SDK automatically, ignoring version numbers and comments
def open_sdk_help():
mod_path = mod_var.get()
if not mod_path:
messagebox.showwarning("Warning", "Please enter a mod path first.")
return
gameinfo_path = os.path.join(mod_path, "gameinfo.txt")
if os.path.exists(gameinfo_path):
try:
with open(gameinfo_path, "r") as file:
for line in file:
# Remove comments (everything after //)
line = line.split("//")[0].strip()
# Skip empty lines or lines containing only version numbers
if not line or line.isdigit() or line in ["2006", "2007", "2013"]:
continue
# Check for the line containing "SteamAppId"
if "SteamAppId" in line:
# Extract the numeric value of SteamAppId
steam_app_id = line.split()[-1]
for sdk_name, sdk_id in SDK_LIST:
if sdk_id == steam_app_id:
sdk_var.set(sdk_name)
messagebox.showinfo("SDK Detection", f"SteamAppId {steam_app_id} matches '{sdk_name}'. SDK automatically selected.")
return
# If no matching SDK is found
messagebox.showwarning("Warning", f"SteamAppId {steam_app_id} not found in the SDK list.")
return
except Exception as e:
messagebox.showerror("Error", f"Failed to read gameinfo.txt: {str(e)}")
else:
messagebox.showwarning("Warning", f"gameinfo.txt not found in {mod_path}.")
# Function to detect the operating system and generate launchers accordingly
def generate_launcher():
sourcemods_path = sourcemods_var.get()
mod_path = mod_var.get()
selected_sdk_id = sdk_dict[sdk_var.get()] # Get the numeric SDK ID based on the selected name
if sourcemods_path and mod_path and selected_sdk_id:
if not os.path.exists(sourcemods_path):
messagebox.showerror("Error", "Invalid Sourcemods path.")
return
if not os.path.basename(sourcemods_path).lower() == "sourcemods":
messagebox.showerror("Error", "Please select a 'sourcemods' folder.")
return
mod_folder = os.path.basename(mod_path)
os_type = platform.system() # Detect the OS (e.g., Windows, Linux)
if os_type == "Windows":
# Windows-specific batch file and .exe generation
steam_path = steam_entry.get()
steam_exe_name = "Steam.exe"
batch_content = f'"{steam_path}\\{steam_exe_name}" -applaunch {selected_sdk_id} -game "{mod_path}"'
batch_file_name = f"{mod_folder}.bat"
batch_file_path = os.path.join(sourcemods_path, batch_file_name)
try:
with open(batch_file_path, "w") as batch_file:
batch_file.write(batch_content)
messagebox.showinfo("Success", f"Batch file generated successfully at {batch_file_path}.")
handle_bat_to_exe(batch_file_path, sourcemods_path)
except Exception as e:
messagebox.showerror("Error", f"Error writing batch file: {str(e)}")
else:
messagebox.showerror("Error", "Unsupported operating system.")
else:
messagebox.showwarning("Warning", "Please select all paths and SDK.")
# Function to download BatToExe and convert the batch file
def handle_bat_to_exe(bat_file_path, sourcemods_path):
bat2exe_dir = os.path.join(sourcemods_path, "bat2exe")
if not os.path.exists(bat2exe_dir):
os.makedirs(bat2exe_dir)
bat_to_exe_path = os.path.join(bat2exe_dir, "bat2exe.exe")
if not os.path.exists(bat_to_exe_path):
if not extract_bat_to_exe(bat_to_exe_path):
return
time.sleep(2)
exe_file_name = os.path.splitext(os.path.basename(bat_file_path))[0] + ".exe"
exe_file_path = os.path.join(sourcemods_path, exe_file_name)
try:
subprocess.run(
[
bat_to_exe_path,
"/bat", bat_file_path,
"/exe", exe_file_path,
"/quiet"
],
check=True
)
messagebox.showinfo("Success", f"Executable generated successfully at {exe_file_path}.")
enable_run_button(exe_file_path)
except subprocess.CalledProcessError as e:
messagebox.showerror("Error", f"Error during conversion: {str(e)}")
finally:
if os.path.exists(bat2exe_dir):
time.sleep(3)
shutil.rmtree(bat2exe_dir)
messagebox.showinfo("Success", f"Temporary folders removed at {bat2exe_dir}.")
if os.path.exists(bat_file_path):
os.remove(bat_file_path)
# Function to enable the Run button if the executable exists
def enable_run_button(exe_file_path):
if os.path.exists(exe_file_path):
run_button.config(state=tk.NORMAL)
# Function to run the generated executable
def run_exe():
sourcemods_path = sourcemods_var.get()
mod_folder = os.path.basename(mod_var.get())
os_type = platform.system()
if not sourcemods_path or not mod_folder:
messagebox.showwarning("Warning", "Please fill in all fields before running.")
return
if os_type == "Windows":
exe_file_path = os.path.join(sourcemods_path, f"{mod_folder}.exe")
if os.path.exists(exe_file_path):
try:
subprocess.run([exe_file_path], check=True)
except subprocess.CalledProcessError as e:
messagebox.showerror("Error", f"Failed to run the executable: {str(e)}")
else:
messagebox.showwarning("Warning", "The executable does not exist. Please generate it first.")
else:
messagebox.showwarning("Warning", "This feature is currently only supported on Windows.")
def resource_path(relative_path):
try:
base_path = sys._MEIPASS
except AttributeError:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
# Creating the main window
root = tk.Tk()
root.title("Sourcemod Executable Generator")
root.geometry("450x245")
root.config(bg="black")
root.iconbitmap(resource_path("app_icon.ico"))
bg_image = Image.open(resource_path("background_art.jpg"))
bg_image = bg_image.resize((450, 245), Image.Resampling.LANCZOS)
bg_image_tk = ImageTk.PhotoImage(bg_image)
bg_label = tk.Label(root, image=bg_image_tk, bd=0)
bg_label.place(x=0, y=0, relwidth=1, relheight=1)
steam_label = tk.Label(root, text="Steam Path:", bg="black", fg="white")
steam_label.place(x=10, y=10)
steam_entry = tk.Entry(root, width=30, bg="white", fg="black")
steam_entry.place(x=120, y=10)
steam_button = tk.Button(root, text="Steam Path", command=locate_steam, bg="gray", fg="white")
steam_button.place(x=330, y=10)
sourcemods_label = tk.Label(root, text="Sourcemods Path:", bg="black", fg="white")
sourcemods_label.place(x=10, y=50)
sourcemods_var = tk.StringVar()
sourcemods_entry = tk.Entry(root, textvariable=sourcemods_var, width=30, bg="white", fg="black")
sourcemods_entry.place(x=120, y=50)
sourcemods_button = tk.Button(root, text="Sourcemods Path", command=locate_sourcemods, bg="gray", fg="white")
sourcemods_button.place(x=330, y=50)
mod_label = tk.Label(root, text="Mod Path:", bg="black", fg="white")
mod_label.place(x=10, y=90)
mod_var = tk.StringVar()
mod_entry = tk.Entry(root, textvariable=mod_var, width=30, bg="white", fg="black")
mod_entry.place(x=120, y=90)
mod_button = tk.Button(root, text="Mod Path", command=locate_mod, bg="gray", fg="white")
mod_button.place(x=330, y=90)
sdk_label = tk.Label(root, text="Select SDK:", bg="black", fg="white")
sdk_label.place(x=10, y=125)
sdk_dict = {sdk[0]: sdk[1] for sdk in SDK_LIST}
sdk_names = [sdk[0] for sdk in SDK_LIST]
sdk_var = tk.StringVar(root)
sdk_var.set(sdk_names[0])
sdk_menu = tk.OptionMenu(root, sdk_var, *sdk_names)
sdk_menu.config(bg="black", fg="white", highlightbackground="black", highlightcolor="black", borderwidth=0)
sdk_menu.place(x=120, y=125)
generate_button = tk.Button(root, text="Generate", command=generate_launcher, bg="gray", fg="white")
generate_button.place(x=120, y=170)
run_button = tk.Button(root, text="Run", command=run_exe, state=tk.DISABLED, bg="gray", fg="white")
run_button.place(x=190, y=170)
sdk_help_button = tk.Button(root, text="What SDK?", command=open_sdk_help, bg="gray", fg="white")
sdk_help_button.place(x=330, y=130)
root.mainloop()