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

Commit 782d435

Browse files
authored
Create Roblox-FFlag-Editor.py
1 parent 87704d9 commit 782d435

File tree

1 file changed

+183
-0
lines changed

1 file changed

+183
-0
lines changed

Roblox-FFlag-Editor.py

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import os
2+
import json
3+
from PyQt5 import QtWidgets
4+
5+
class RobloxFFlagEditor(QtWidgets.QWidget):
6+
def __init__(self):
7+
super().__init__()
8+
self.setWindowTitle("Roblox FFlag Editor - @GiFXED (Beta)")
9+
self.setFixedSize(400, 400)
10+
self.initUI()
11+
self.ensure_json_exists()
12+
13+
def initUI(self):
14+
layout = QtWidgets.QVBoxLayout(self)
15+
16+
self.tabs = QtWidgets.QTabWidget()
17+
self.basic_tab = QtWidgets.QWidget()
18+
self.advanced_tab = QtWidgets.QWidget()
19+
self.tabs.addTab(self.basic_tab, "Basic Controls")
20+
self.tabs.addTab(self.advanced_tab, "Advanced Controls")
21+
22+
self.basic_layout = QtWidgets.QVBoxLayout(self.basic_tab)
23+
self.advanced_layout = QtWidgets.QVBoxLayout(self.advanced_tab)
24+
25+
self.noclip_button = QtWidgets.QPushButton("Toggle Noclip")
26+
self.noclip_button.clicked.connect(lambda: self.toggle_fflag("Noclip", noclip_flags))
27+
self.basic_layout.addWidget(self.noclip_button)
28+
29+
self.hip_height_label = QtWidgets.QLabel("Set Hip Height Value:")
30+
self.basic_layout.addWidget(self.hip_height_label)
31+
32+
self.hip_height_input = QtWidgets.QSpinBox(self)
33+
self.hip_height_input.setRange(-500, 0)
34+
self.basic_layout.addWidget(self.hip_height_input)
35+
36+
self.set_hip_height_button = QtWidgets.QPushButton("Set Hip Height")
37+
self.set_hip_height_button.clicked.connect(self.set_hip_height)
38+
self.basic_layout.addWidget(self.set_hip_height_button)
39+
40+
self.network_ownership_button = QtWidgets.QPushButton("Set Network Ownership")
41+
self.network_ownership_button.clicked.connect(lambda: self.set_flags(network_ownership_flags))
42+
self.basic_layout.addWidget(self.network_ownership_button)
43+
44+
self.gravity_button = QtWidgets.QPushButton("Set Low Gravity")
45+
self.gravity_button.clicked.connect(lambda: self.set_flags(low_gravity_flags))
46+
self.basic_layout.addWidget(self.gravity_button)
47+
48+
self.log = QtWidgets.QTextEdit(self)
49+
self.log.setReadOnly(True)
50+
self.basic_layout.addWidget(self.log)
51+
52+
self.custom_fflag_input = QtWidgets.QLineEdit(self)
53+
self.custom_fflag_input.setPlaceholderText("Enter Custom FFlag")
54+
self.advanced_layout.addWidget(self.custom_fflag_input)
55+
56+
self.custom_value_input = QtWidgets.QLineEdit(self)
57+
self.custom_value_input.setPlaceholderText("Enter Custom Value")
58+
self.advanced_layout.addWidget(self.custom_value_input)
59+
60+
self.add_custom_fflag_button = QtWidgets.QPushButton("Add Custom FFlag")
61+
self.add_custom_fflag_button.clicked.connect(self.add_custom_fflag)
62+
self.advanced_layout.addWidget(self.add_custom_fflag_button)
63+
64+
self.log_advanced = QtWidgets.QTextEdit(self)
65+
self.log_advanced.setReadOnly(True)
66+
self.advanced_layout.addWidget(self.log_advanced)
67+
68+
self.beta_warning = QtWidgets.QLabel("This is a beta version. Report bugs on the GitHub repo.")
69+
self.basic_layout.addWidget(self.beta_warning)
70+
71+
layout.addWidget(self.tabs)
72+
self.setLayout(layout)
73+
74+
self.log.append("FFlag Editor initialized. Make changes and restart Roblox to see the effects.")
75+
76+
def get_roblox_folder(self):
77+
for root, dirs, files in os.walk(os.path.join(os.getenv("LOCALAPPDATA"), "Roblox", "Versions")):
78+
if "RobloxPlayerBeta.exe" in files:
79+
return root
80+
return None
81+
82+
def create_client_settings(self):
83+
folder = self.get_roblox_folder()
84+
if folder is None:
85+
self.log.append("Roblox installation not found.")
86+
return None
87+
88+
settings_folder = os.path.join(folder, "ClientSettings")
89+
if not os.path.exists(settings_folder):
90+
os.makedirs(settings_folder)
91+
self.log.append(f"Created ClientSettings folder at: {settings_folder}")
92+
93+
return settings_folder
94+
95+
def ensure_json_exists(self):
96+
settings_folder = self.create_client_settings()
97+
if settings_folder:
98+
json_path = os.path.join(settings_folder, "ClientAppSettings.json")
99+
if not os.path.exists(json_path):
100+
with open(json_path, 'w') as f:
101+
json.dump({}, f)
102+
self.log.append(f"Initialized JSON at {json_path}. Restart Roblox to see changes.")
103+
104+
def save_json(self, data):
105+
settings_folder = self.create_client_settings()
106+
if settings_folder:
107+
json_path = os.path.join(settings_folder, "ClientAppSettings.json")
108+
with open(json_path, 'w') as f:
109+
json.dump(data, f, indent=4)
110+
self.log.append(f"Saved JSON to {json_path}. Restart Roblox to see changes.")
111+
112+
def load_json(self):
113+
settings_folder = self.create_client_settings()
114+
json_path = os.path.join(settings_folder, "ClientAppSettings.json")
115+
try:
116+
with open(json_path, 'r') as f:
117+
return json.load(f)
118+
except (FileNotFoundError, json.JSONDecodeError) as e:
119+
self.log.append(f"Error loading JSON: {e}")
120+
self.ensure_json_exists()
121+
return {}
122+
123+
def toggle_fflag(self, flag_name, flag_data):
124+
data = self.load_json()
125+
126+
if flag_name == "Noclip":
127+
if "FFlagDebugSimDefaultPrimalSolver" in data:
128+
self.log.append("Disabling Noclip...")
129+
data.pop("FFlagDebugSimDefaultPrimalSolver", None)
130+
data.pop("DFIntMaximumFreefallMoveTimeInTenths", None)
131+
data.pop("DFIntDebugSimPrimalStiffness", None)
132+
else:
133+
self.log.append("Enabling Noclip...")
134+
data.update(flag_data[0])
135+
136+
self.save_json(data)
137+
138+
def set_hip_height(self):
139+
hip_height_value = self.hip_height_input.value()
140+
data = self.load_json()
141+
data["DFIntMaxAltitudePDStickHipHeightPercent"] = str(hip_height_value)
142+
self.save_json(data)
143+
self.log.append(f"Set Hip Height to {hip_height_value}.")
144+
145+
def set_flags(self, flag_data):
146+
data = self.load_json()
147+
data.update(flag_data)
148+
self.save_json(data)
149+
150+
def add_custom_fflag(self):
151+
custom_fflag = self.custom_fflag_input.text()
152+
custom_value = self.custom_value_input.text()
153+
154+
if custom_fflag and custom_value:
155+
data = self.load_json()
156+
data[custom_fflag] = custom_value
157+
self.save_json(data)
158+
self.log_advanced.append(f"Added custom FFlag: {custom_fflag} = {custom_value}")
159+
else:
160+
self.log_advanced.append("Please enter both FFlag and value.")
161+
162+
noclip_flags = [{
163+
"FFlagDebugSimDefaultPrimalSolver": "True",
164+
"DFIntMaximumFreefallMoveTimeInTenths": "1000",
165+
"DFIntDebugSimPrimalStiffness": "0"
166+
}]
167+
168+
network_ownership_flags = {
169+
"DFIntMinClientSimulationRadius": "2147000000",
170+
"DFIntMinimalSimRadiusBuffer": "2147000000",
171+
"DFIntMaxClientSimulationRadius": "2147000000"
172+
}
173+
174+
low_gravity_flags = {
175+
"FFlagDebugSimDefaultPrimalSolver": "True",
176+
"DFIntDebugSimPrimalLineSearch": "3"
177+
}
178+
179+
if __name__ == "__main__":
180+
app = QtWidgets.QApplication([])
181+
window = RobloxFFlagEditor()
182+
window.show()
183+
app.exec_()

0 commit comments

Comments
 (0)