# GPL3 or any later version # (C) J.Y.Amihud ( blenderdumbass ) 2024 # This is the launcher of the game. import os import subprocess import time import json import threading import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk from gi.repository import GLib import urllib.request import urllib.parse # V E R S I O N # ############################################### VERSION = "08-08-24" ############################################### def getData(link): try: req = urllib.request.Request(link) f = urllib.request.urlopen(req) data = json.loads(f.read().decode('utf-8')) return data except: return None from Scripts.Common import * #### MAKING THE WINDOW #### win = Gtk.Window() win.set_title("Dani's Race") win.set_size_request(799, 280) win.connect("destroy", Gtk.main_quit) win.set_default_icon_from_file("SettingUI/icon.png") box = Gtk.VBox() win.add(box) #### Building the UI itself ### banner = Gtk.Image.new_from_file('SettingUI/banner.jpg') box.pack_start(banner, 0,0,0) pannel = Gtk.HeaderBar() pannel.set_show_close_button(True) win.set_titlebar(pannel) playbox = Gtk.HBox() pannel.pack_start(playbox) def play(w): data = load_settings() if data: blenderplayer = data.get("blenderplayer") command = [blenderplayer] if data.get("fullscreen"): command.append("-f") else: command.append("-w") command.append(data.get("resolution").split(":")[0]) command.append(data.get("resolution").split(":")[1]) # The file of the game command.append(os.getcwd()+"/assembly.blend") # print(command) subprocess.Popen(command) else: set_settings(w) playbutton = Gtk.Button("Start Game") playbutton.connect("clicked", play) playbox.pack_start(playbutton, 0,5,5) ################### SETTINGS ######################### def set_settings(w): settingsWindow = Gtk.Dialog("Dani's Race Settings", buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK), ) settingsWindow.set_size_request(600, 400) box = settingsWindow.get_content_area() # Scroller scrl = Gtk.ScrolledWindow() box.pack_start(scrl, 1,1,1) # Actuall useful box box = Gtk.VBox() scrl.add(box) # UPBGE executable upbgebox = Gtk.HBox() upbgelabel = Gtk.Label("UPBGE executable: ") upbgeinput = Gtk.Entry() def get_upbge_do(w): os.system("xdg-open https://github.com/UPBGE/upbge/releases/download/v0.36.1/upbge-0.36.1-linux-x86_64.tar.xz") downloadUPBGE = Gtk.Button("Get UPBGE") downloadUPBGE.connect("clicked", get_upbge_do) downloadUPBGE.set_tooltip_text("Download the latest working UPBGE for GNU / Linux.") upbgeinput.set_text("blenderplayer") upbgeinput.set_tooltip_text("Location of the blenderplayer executable on the system ( should in UPBGE folder ).") upbgebox.pack_start(upbgelabel, 0,5,5) upbgebox.pack_start(upbgeinput, 1,5,5) upbgebox.pack_start(downloadUPBGE, 0,5,5) box.pack_start(upbgebox, 0,5,5) ###### GRAPHICS / COMPLEXITY ##### box.pack_start(Gtk.Label("Graphics"), 0,5,5) # Resolution resbox = Gtk.HBox() resfull = Gtk.CheckButton("Fullscreen") resfull.set_tooltip_text("Whether to run the game Fullscreen.") resmenu = Gtk.ComboBoxText() resmenu.set_tooltip_text("What resolution to run the game at.") resolutions = [ "7680:4320", "5120:2880", "3840:2160", "2560:1440", "1920:1080", "1600:900", "1366:768", "1280:720", "1024:576", "960:540", "854:480", "640:360" ] for i in resolutions: resmenu.append_text(i) resmenu.set_active(4) resbox.pack_start(resfull, 0,5,5) resbox.pack_end(resmenu, 0,5,5) box.pack_start(resbox, 0,5,5) # Target FPS def hide_show_target_fps(w): fpsbox.set_visible(not w.get_active()) autoFPS = Gtk.CheckButton("Automatic Target FPS") autoFPS.set_active(True) autoFPS.connect("clicked", hide_show_target_fps) autoFPS.set_tooltip_text("Set Target FPS automatically to decrease input lag.") box.pack_start(autoFPS, 0,5,5) fpsbox = Gtk.HBox() box.pack_start(fpsbox, 0,5,5) fpsbox.pack_start(Gtk.Label("Target FPS"), 0,5,5) fpsbox.set_tooltip_text("FPS that the engine will try to render.\nDo not put more than the computer can handle.\nOtherwise the game will have way too much input lag.") fpsadjust = Gtk.Adjustment(30, lower=1, upper=1000, step_increment=1) fps = Gtk.SpinButton(adjustment=fpsadjust, digits=0) fpsbox.pack_end(fps, 0,5,5) # Optimization aggressiveness optbox = Gtk.HBox() optbox.pack_start(Gtk.Label("Optimization Strength: "),0,5,5) opt_adjust = Gtk.Adjustment(1, lower=0, upper=1, step_increment=0.01) opt_scale = Gtk.HScale(adjustment=opt_adjust) opt_scale.set_digits(2) opt_scale.set_size_request(250,20) optbox.set_tooltip_text("How aggressively should the game try to preserve FPS.") optbox.pack_end(opt_scale, 0, 5, 5) box.pack_start(optbox, 0,5,5) # Vsync vsyncbox = Gtk.HBox() box.pack_start(vsyncbox, 0,5,5) vsyncbox.pack_start(Gtk.Label("Vsync"), 0,5,5) vsyncoptions = ["On", "Off", "Adaptive"] vsyncmenu = Gtk.ComboBoxText() for i in vsyncoptions: vsyncmenu.append_text(i) vsyncmenu.set_active(1) vsyncbox.pack_end(vsyncmenu, 0,5,5) # Compositing compositor = Gtk.CheckButton("Post Processing Effects") compositor.set_tooltip_text("Bloom, sun beams, film and color grading effects.") compositor.set_active(True) box.pack_start(compositor, 0,5,5) # Reflections reflections = Gtk.CheckButton("Screen-Space Reflections") reflections.set_tooltip_text("Pseudo-accurate reflections.") reflections.set_active(True) box.pack_start(reflections, 0,5,5) # Ambient Occlusion ao = Gtk.CheckButton("Ambient Occlusion") ao.set_tooltip_text("Makes the shadow areas darker when objects are close together.") ao.set_active(False) box.pack_start(ao, 0,5,5) # Trees, Poles, Fenses tplbox = Gtk.HBox() trees = Gtk.CheckButton("Trees") trees.set_tooltip_text("Whether to spawn Trees.") trees.set_active(True) poles = Gtk.CheckButton("Light Poles") poles.set_tooltip_text("Whether to spawn Light Poles.") poles.set_active(True) fences = Gtk.CheckButton("Fences") fences.set_tooltip_text("Whether to spawn Metal and or Wooden fences.") fences.set_active(True) tplbox.pack_start(trees, 1,5,5) tplbox.pack_start(poles, 1,5,5) tplbox.pack_start(fences, 1,5,5) box.pack_start(tplbox, 0,5,5) # Amount of cars carsbox = Gtk.HBox() carsbox.pack_start(Gtk.Label("Traffic Density"), 0,5,5) maxcarsadjust = Gtk.Adjustment(4, lower=1, upper=20, step_increment=1) maxcarsinput = Gtk.SpinButton(adjustment=maxcarsadjust, digits=0) maxcarsinput.set_tooltip_text("How many NPC cars to spawn on roads.") carsbox.pack_end(maxcarsinput, 0,5,5) box.pack_start(carsbox, 0,5,5) # Sampling samplesbox = Gtk.HBox() sampleslabel = Gtk.Label("Main Samples: ") samplesadjust = Gtk.Adjustment(1, lower=1, upper=64, step_increment=1) samplesinput = Gtk.SpinButton(adjustment=samplesadjust, digits=0) samplesinput.set_sensitive(False) samplesinput.set_tooltip_text("How many times to render the image per frame. More gives more accurate soft shadows and anti-aliasing. Less is faster.") samplesbox.pack_start(sampleslabel, 0,5,5) samplesbox.pack_end(samplesinput, 0,5,5) box.pack_start(samplesbox, 0,5,5) # Subsurface Sampling skinsamplesbox = Gtk.HBox() skinsampleslabel = Gtk.Label("Skin Samples: ") skinsamplesadjust = Gtk.Adjustment(5, lower=1, upper=64, step_increment=1) skinsamplesinput = Gtk.SpinButton(adjustment=skinsamplesadjust, digits=0) skinsamplesinput.set_sensitive(False) skinsamplesinput.set_tooltip_text("How accurate the subsurface materials ( skin ) should be. More, prettier, less faster.") skinsamplesbox.pack_start(skinsampleslabel, 0,5,5) skinsamplesbox.pack_end(skinsamplesinput, 0,5,5) box.pack_start(skinsamplesbox, 0,5,5) # Volumetric sampling box.pack_start(Gtk.HSeparator(), 0,5,5) ############################# volumesamplesbox = Gtk.HBox() volumesampleslabel = Gtk.Label("Volumetric Samples: ") volumesamplesadjust = Gtk.Adjustment(32, lower=1, upper=64, step_increment=1) volumesamplesinput = Gtk.SpinButton(adjustment=volumesamplesadjust, digits=0) volumesamplesinput.set_tooltip_text("How accurate should be fog, smoke and fire effects. More prettier, less faster.") volumesamplesbox.pack_start(volumesampleslabel, 0,5,5) volumesamplesbox.pack_end(volumesamplesinput, 0,5,5) box.pack_start(volumesamplesbox, 0,5,5) # Volumetric lighting volumelight = Gtk.CheckButton("Volumetric Lighting") volumelight.set_active(True) volumelight.set_tooltip_text("Enable light to interact with volumetric materials.") box.pack_start(volumelight, 0,5,5) # Volumetric shadow def show_hide_volume_shadows(w): volumeshadowsamplesbox.set_visible( w.get_active() ) volumeshadow = Gtk.CheckButton("Volumetric Shadows") volumeshadow.set_active(False) volumeshadow.set_tooltip_text("Enable volumetrics to cast shadows ( Very slow ).") volumeshadow.connect("clicked", show_hide_volume_shadows) box.pack_start(volumeshadow, 0,5,5) # Volumetric shadow sampling volumeshadowsamplesbox = Gtk.HBox() volumeshadowsampleslabel = Gtk.Label("Volumetric Shadows Samples: ") volumeshadowsamplesadjust = Gtk.Adjustment(3, lower=1, upper=64, step_increment=1) volumeshadowsamplesinput = Gtk.SpinButton(adjustment=volumeshadowsamplesadjust, digits=0) volumeshadowsamplesinput.set_tooltip_text("How accurate should be volumentric shadows. More prettier, less faster.") volumeshadowsamplesbox.pack_start(volumeshadowsampleslabel, 0,5,5) volumeshadowsamplesbox.pack_end(volumeshadowsamplesinput, 0,5,5) box.pack_start(volumeshadowsamplesbox, 0,5,5) # Shadows box.pack_start(Gtk.HSeparator(), 0,5,5) ############################# def show_hide_shadows(w): softshadows.set_visible( w.get_active() ) contactshadows.set_visible( w.get_active() ) shadowcubebox.set_visible( w.get_active() ) shadowcascadebox.set_visible( w.get_active() ) shadows = Gtk.CheckButton("Shadows") shadows.set_active(True) shadows.set_tooltip_text("Whether to render Shadows.") shadows.connect("clicked", show_hide_shadows) box.pack_start(shadows, 0,5,5) # Soft Shadows softshadows = Gtk.CheckButton("Soft Shadows") softshadows.set_active(True) softshadows.set_tooltip_text("Whether to try rendering soft Shadows. ( Requires more than one Sample )") box.pack_start(softshadows, 0,5,5) # Contact Shadows contactshadows = Gtk.CheckButton("Contact Shadows") contactshadows.set_active(True) contactshadows.set_tooltip_text("Render a special pass of shadows to fill up small cracks.") box.pack_start(contactshadows, 0,5,5) # Shadow resolution shadowresolutions = [ "4096", "2048", "1024", "512", "256", "128", "64" ] shadowcubebox = Gtk.HBox() shadowcubelabel = Gtk.Label("Lamp Shadow Resolution: ") shadowcubemenu = Gtk.ComboBoxText() for i in shadowresolutions: shadowcubemenu.append_text(i) shadowcubemenu.set_active(3) shadowcubebox.pack_start(shadowcubelabel,0,5,5) shadowcubebox.pack_end(shadowcubemenu,0,5,5) box.pack_start(shadowcubebox, 0,5,5) # Shadow cascade size shadowcascadebox = Gtk.HBox() shadowcascadelabel = Gtk.Label("Sun Shadow Resolution: ") shadowcascademenu = Gtk.ComboBoxText() for i in shadowresolutions: shadowcascademenu.append_text(i) shadowcascademenu.set_active(2) shadowcascadebox.pack_start(shadowcascadelabel,0,5,5) shadowcascadebox.pack_end(shadowcascademenu,0,5,5) box.pack_start(shadowcascadebox, 0,5,5) ############ CONTROLS ######################## box.pack_start(Gtk.HSeparator(), 0,5,5) ############################# box.pack_start(Gtk.Label("Controls"), 0,5,5) def show_hide_car_controls(w): controlboxes["veh_forward"].set_visible( not w.get_active() ) controlboxes["veh_backward"].set_visible( not w.get_active() ) controlboxes["veh_left"].set_visible( not w.get_active() ) controlboxes["veh_right"].set_visible( not w.get_active() ) turnxbox.set_visible( not w.get_active() ) carmouseguides.set_visible( w.get_active() ) carmouseshow.set_visible( w.get_active() ) controlcarmouse = Gtk.CheckButton("Control Car With a Mouse") controlcarmouse.connect("clicked", show_hide_car_controls ) controlcarmouse.set_tooltip_text("Use the mouse to control the car. Allows for more precise input. Has a learning curve.") box.pack_start(controlcarmouse, 0,5,5) carmouseguides = Gtk.CheckButton("Mouse Control Guides") carmouseguides.set_active(True) carmouseguides.set_tooltip_text("Show guides on the screen when controlling the car with the mouse.") box.pack_start(carmouseguides, 0,5,5) carmouseshow = Gtk.CheckButton("Show Mouse Cursor") carmouseshow.set_tooltip_text("Show mouse cursor when controlling the car with the mouse. ( Easier to understand than the guides, but can obstruct the view ).") box.pack_start(carmouseshow, 0,5,5) # Keyboard steering sensitivity turnxbox = Gtk.HBox() box.pack_start(turnxbox, 0,5,5) turnxbox.pack_start(Gtk.Label("Car Turning Sensitivity: "), 0, 5,5) turnxbox.set_tooltip_text("How fast will the front wheels turn when turning.\nLower value, smoother. Higher, faster turning.") turn_adjust = Gtk.Adjustment(1, lower=0.1, upper=10.0, step_increment=0.1) turn_scale = Gtk.HScale(adjustment=turn_adjust) turn_scale.set_digits(2) turn_scale.set_size_request(250,20) turnxbox.pack_end(turn_scale, 0,5,5) controlnames = { "veh_forward" :"Drive Forward", "veh_backward" :"Drive Backward", "veh_left" :"Steer Left", "veh_right" :"Steer Right", "veh_drift" :"Handbrake", "veh_nitro" :"Use Nitro", "veh_resque" :"Resque During Race", "veh_gear_up" :"Shift Gears Up", "veh_gear_down":"Shift Gears Down", "veh_auto_gear":"Switch Automatic Gearbox", "veh_dynamcam" :"Switch Dynamic Camera", "veh_upload" :"Truck Deploy Cargo", "chr_forward" :"Walk Forward", "chr_backward" :"Walk Backward", "chr_left" :"Walk Left", "chr_right" :"Walk Right", "chr_jump" :"Jump", "chr_get_car" :"Enter Car", "chr_swimdown" :"Swim Down" } controldefaults = { "veh_forward" :"UpArrow", "veh_backward" :"DownArrow", "veh_left" :"LeftArrow", "veh_right" :"RightArrow", "veh_drift" :"Space", "veh_nitro" :"Z", "veh_resque" :"BackSpace", "veh_gear_up" :"W", "veh_gear_down":"S", "veh_auto_gear":"Q", "veh_dynamcam" :"C", "veh_upload" :"D", "chr_forward" :"W", "chr_backward" :"S", "chr_left" :"A", "chr_right" :"D", "chr_jump" :"Space", "chr_get_car" :"Enter", "chr_swimdown" :"LShift" } controlwidgets = {} controlboxes = {} for control in controlnames: cbox = Gtk.HBox() box.pack_start(cbox, 0,5,5) controlboxes[control] = cbox cbox.pack_start(Gtk.Label(controlnames[control]), 0,5,5) controlwidgets[control] = Gtk.ComboBoxText() cbox.pack_end(controlwidgets[control], 0,5,5) for key in keycodes: controlwidgets[control].append_text(key) controlwidgets[control].set_active( list(keycodes.keys()).index(controldefaults[control]) ) ######## NETWORK ###### box.pack_start(Gtk.HSeparator(), 0,5,5) ############################# box.pack_start(Gtk.Label("Multiplayer"), 0,5,5) def show_hide_multiplayer(w): hostbox.set_visible( w.get_active() ) usernamebox.set_visible( w.get_active() ) multiplayerroombox.set_visible( w.get_active() ) multiplayer = Gtk.CheckButton("Multiplayer") multiplayer.connect("clicked", show_hide_multiplayer) box.pack_start(multiplayer, 0,5,5) hostbox = Gtk.HBox() hostbox.pack_start(Gtk.Label("Hostname:"), 0,5,5) hostname = Gtk.Entry() hostbox.pack_end(hostname, 0,5,5) box.pack_start(hostbox, 0,5,5) usernamebox = Gtk.HBox() usernamebox.pack_start(Gtk.Label("Username:"),0,5,5) username = Gtk.Entry() usernamebox.pack_end(username,0,5,5) box.pack_start(usernamebox, 0,5,5) multiplayerroombox = Gtk.HBox() multiplayerroombox.pack_start(Gtk.Label("Room:"),0,5,5) multiplayerroom = Gtk.Entry() multiplayerroombox.pack_end(multiplayerroom,0,5,5) box.pack_start(multiplayerroombox, 0,5,5) ######### TIME ######## box.pack_start(Gtk.HSeparator(), 0,5,5) ############################# box.pack_start(Gtk.Label("In Game Time"), 0,5,5) clockspeedbox = Gtk.HBox() clockspeedbox.pack_start(Gtk.Label("In Game Clock Speed:"), 0,5,5) clockspeedadjustment = Gtk.Adjustment(20, lower=0.1, upper=10000, step_increment=0.1) clockspeedentry = Gtk.SpinButton(adjustment=clockspeedadjustment, digits=2) clockspeedentry.set_tooltip_text("How much the clock in the game is faster than the real clock. 1 is real time speed. 10 is ten times faster.") clockspeedbox.pack_end(clockspeedentry, 0,5,5) box.pack_start(clockspeedbox, 0,5,5) ############################################# DEV SETTINGS ##################### box.pack_start(Gtk.HSeparator(), 0,5,5) ############################# box.pack_start(Gtk.Label("For Developers"), 0,5,5) def show_hide_devmode(w): devmode_cheats.set_visible( w.get_active() ) devmode_visible_rays.set_visible( w.get_active() ) if not w.get_active(): devmode_cheats.set_active( False ) devmode_visible_rays.set_active( False ) devmode = Gtk.CheckButton("Developer Mode") devmode.set_tooltip_text("Developer mode is mode used in development of the game.") box.pack_start(devmode, 0,5,5) devmode.connect("clicked", show_hide_devmode ) devmode_cheats = Gtk.CheckButton("Developer Keyboard Cheatcodes") devmode_cheats.set_tooltip_text("Enable keyboards cheat codes, for testing purposes.") box.pack_start(devmode_cheats, 0,5,5) devmode_visible_rays = Gtk.CheckButton("Developer Visible Rays") devmode_visible_rays.set_tooltip_text("Show the rays that are used for AIs to see.") box.pack_start(devmode_visible_rays, 0,5,5) ################################################################################ # Loading settings data = load_settings() if data: upbgeinput.set_text( data.get("blenderplayer", "blenderplayer") ) resfull.set_active( data.get("fullscreen", False ) ) resmenu.set_active( resolutions.index( data.get("resolution", "1920:1080" ) ) ) compositor.set_active( data.get("compositor", True ) ) reflections.set_active( data.get("reflections", True ) ) trees.set_active( data.get("trees", True ) ) poles.set_active( data.get("poles", True ) ) fences.set_active( data.get("fences", True ) ) samplesadjust.set_value( data.get("samples", 1 ) ) skinsamplesadjust.set_value( data.get("skinsamples", 5 ) ) volumesamplesadjust.set_value( data.get("volumesamples", 32 ) ) volumelight.set_active( data.get("volumelight", True ) ) volumeshadow.set_active( data.get("volumeshadow", False ) ) volumeshadowsamplesadjust.set_value( data.get("volshadsampl", 3 ) ) shadows.set_active( data.get("shadows", True ) ) softshadows.set_active( data.get("softshadows", True ) ) contactshadows.set_active( data.get("cntctshadows", True ) ) shadowcubemenu.set_active( shadowresolutions.index( data.get("shadowslamps", "512" ) ) ) shadowcascademenu.set_active( shadowresolutions.index( data.get("shadowssun", "1024" ) ) ) devmode.set_active( data.get("devmode", False ) ) devmode_cheats.set_active( data.get("dev-cheats", False ) ) devmode_visible_rays.set_active(data.get("dev-rays", False ) ) clockspeedadjustment.set_value( data.get("clockspeed", 20.0 ) ) controlcarmouse.set_active( data.get("veh_mouse", False ) ) maxcarsadjust.set_value( data.get("maxcars", 4 ) ) carmouseguides.set_active( data.get("veh_mouse_guides",True ) ) carmouseshow.set_active( data.get("veh_mouse_cursor",False ) ) multiplayer.set_active( data.get("multiplayer", False ) ) hostname.set_text( data.get("mp-host", "http://localhost:6969") ) username.set_text( data.get("mp-name", "Dani" ) ) multiplayerroom.set_text( data.get("mp-room", "Main" ) ) fpsadjust.set_value( data.get("fps", 30 ) ) vsyncmenu.set_active( vsyncoptions.index( data.get("vsync", "Off" ))) ao.set_active( data.get("ao", False ) ) autoFPS.set_active( data.get("autofps", True ) ) opt_scale.set_value( data.get("opt", 1.0 ) ) turn_scale.set_value( data.get("turn", 1.0 ) ) for control in controlwidgets: try: controlwidgets[control].set_active( list(keycodes.keys()).index(data.get(control)) ) except: controlwidgets[control].set_active( list(keycodes.keys()).index(controldefaults[control]) ) settingsWindow.show_all() show_hide_shadows(shadows) show_hide_volume_shadows(volumeshadow) show_hide_devmode(devmode) show_hide_car_controls(controlcarmouse) show_hide_multiplayer(multiplayer) hide_show_target_fps(autoFPS) response = settingsWindow.run() if response == Gtk.ResponseType.OK: folder = get_settings_folder() f = folder+"/config.json" data = {"blenderplayer":upbgeinput.get_text(),# "fullscreen" :resfull.get_active(),# "resolution" :resmenu.get_active_text(),# "compositor" :compositor.get_active(),# "reflections" :reflections.get_active(),# "trees" :trees.get_active(),# "poles" :poles.get_active(),# "fences" :fences.get_active(),# "samples" :int(samplesadjust.get_value()),# "skinsamples" :int(skinsamplesadjust.get_value()),# "volumesamples":int(volumesamplesadjust.get_value()),# "volumelight" :volumelight.get_active(),# "volumeshadow" :volumeshadow.get_active(),# "volshadsampl" :int(volumeshadowsamplesadjust.get_value()),# "shadows" :shadows.get_active(), # "softshadows" :softshadows.get_active(),# "cntctshadows" :contactshadows.get_active(),# "shadowslamps" :shadowcubemenu.get_active_text(),# "shadowssun" :shadowcascademenu.get_active_text(), # "devmode" :devmode.get_active(), "dev-cheats" :devmode_cheats.get_active(), "dev-rays" :devmode_visible_rays.get_active(), "clockspeed" :clockspeedadjustment.get_value(), "veh_mouse" :controlcarmouse.get_active(), "maxcars" :int(maxcarsadjust.get_value()), "veh_mouse_guides":carmouseguides.get_active(), "veh_mouse_cursor":carmouseshow.get_active(), "multiplayer" :multiplayer.get_active(), "mp-host" :hostname.get_text(), "mp-name" :username.get_text(), "mp-room" :multiplayerroom.get_text(), "fps" :int(fpsadjust.get_value()), "vsync" :vsyncmenu.get_active_text(), "ao" :ao.get_active(), "autofps" :autoFPS.get_active(), "opt" :opt_scale.get_value(), "turn" :turn_scale.get_value() } for control in controlwidgets: data[control] = controlwidgets[control].get_active_text() with open(f, "w") as save: json.dump(data, save, indent=4, sort_keys=True) settingsWindow.destroy() settingsbutton = Gtk.Button("Settings") settingsbutton.connect("clicked", set_settings) settingsbutton.set_relief(Gtk.ReliefStyle.NONE) playbox.pack_start(settingsbutton, 0,5,5) def do_updates(w): updatesData = getData("https://blenderdumbass.codeberg.page/DanisRace/updates.json") updatesWindow = Gtk.Dialog("Dani's Race Updates") updatesWindow.set_size_request(600, 400) box = updatesWindow.get_content_area() # Scroller scrl = Gtk.ScrolledWindow() box.pack_start(scrl, 1,1,1) # Actuall useful box box = Gtk.VBox() scrl.add(box) if updatesData: for n, version in enumerate(updatesData): vdata = updatesData[version] if version == VERSION: buttontext = "Installed" tooltip = "You already have version "+version elif vdata.get("available"): buttontext = "Download" tooltip = "Download page for version "+version else: buttontext = "Help Unlock" tooltip = "Dani's Race "+version+" is not unlocked yet. Help with unlocking it." # For the fist one if n == 0: add = "NEWEST!!! " else: add = "" verbox = Gtk.HBox() verbox.pack_start(Gtk.Label(add+"Dani's Race v"+version), 0,5,5) def open_webpage(w, link): os.system("xdg-open "+link) actionButton = Gtk.Button(buttontext) actionButton.set_tooltip_text(tooltip) actionButton.connect("clicked", open_webpage, vdata.get("page")) verbox.pack_end(actionButton, 0, 5, 5) box.pack_start(verbox, 0,5,5) box.pack_start(Gtk.HSeparator(), 0,5,5) else: box.pack_start(Gtk.Label("Could not get update information.\nCheck internet connection."), 1 , 5, 5) updatesWindow.show_all() updatesWindow.run() updatesWindow.destroy() updatesbutton = Gtk.Button("Updates") updatesbutton.connect("clicked", do_updates) updatesbutton.set_relief(Gtk.ReliefStyle.NONE) playbox.pack_start(updatesbutton, 0,5,5) def get_settings_folder(): game = "danisrace" try: data_dir = os.environ["XDG_DATA_HOME"] + "/" + game except: data_dir = os.path.expanduser("~/.local/share/"+game) try: os.makedirs(data_dir) except: pass return data_dir def load_settings(): folder = get_settings_folder() f = folder+"/config.json" try: with open(f) as o: return json.load(o) except: return None #### Launching he ui ###### win.show_all() Gtk.main()