use godot::prelude::*; use godot::classes::{ConfigFile, Engine, DisplayServer, display_server::{WindowFlags, WindowMode, VSyncMode}, window::WindowInitialPosition}; #[derive(GodotClass)] #[class(base=Node)] struct Config { // DISCUSSION: Should we expose these in-editor so the default values can be modified? #[export(file = "")] config_path: GString, #[var] window_height: i32, #[var] window_width: i32, #[var] is_fullscreen: bool, #[var] is_borderless: bool, #[var] monitor: i32, #[var] window_position_x: i32, #[var] window_position_y: i32, #[var] max_framerate: i32, #[var] vertical_sync: bool, #[var] resolution_scale: f32, base: Base, } #[godot_api] impl INode for Config { fn init(base: Base) -> Self { Self { config_path: GString::from("res://config.toml"), window_height: 600, window_width: 400, is_fullscreen: false, is_borderless: true, monitor: 0, window_position_x: 0, window_position_y: 0, max_framerate: 60, vertical_sync: true, resolution_scale: 1.0, base, } } fn enter_tree(&mut self) { let editor_hint = Engine::singleton().is_editor_hint(); let mut config = ConfigFile::new_gd(); let res = config.load(GString::from("res://config.toml")); if res != godot::global::Error::OK { godot_error!("Failed to load config file"); } else { //TODO This could be improved //// GDext doesn's support defining defaults at this moment, and there's no way in hell I'm implementing checks for each config key. //// If a config field is missing, it should throw an error, but not halt the whole demo // // We can get the keys and sections with get_sections() and get_section_keys() and then iterate over each one and load them if they match with the Config struct // self.window_width = config.get_value(GString::from("window"), GString::from("width")).to::(); self.window_height = config.get_value(GString::from("window"), GString::from("height")).to::(); self.is_fullscreen = config.get_value(GString::from("window"), GString::from("fullscreen")).to::(); self.is_borderless = config.get_value(GString::from("window"), GString::from("borderless")).to::(); self.window_position_x = config.get_value(GString::from("window"), GString::from("position_x")).to::(); self.window_position_y = config.get_value(GString::from("window"), GString::from("position_y")).to::(); self.monitor = config.get_value(GString::from("window"), GString::from("monitor")).to::(); self.max_framerate = config.get_value(GString::from("graphics"), GString::from("max_framerate")).to::(); self.vertical_sync = config.get_value(GString::from("graphics"), GString::from("vertical_sync")).to::(); self.resolution_scale = config.get_value(GString::from("graphics"), GString::from("resolution_scale")).to::(); } if !editor_hint { // THIS CHECK IS VERY IMPORTANT!!! I don't want to fuck my godot up again by resizing the editor and moving it out of bounds.. Self::apply_video_settings(self); } } } #[godot_api] impl Config { #[func] fn apply_video_settings(&mut self) { let mut disp_server = DisplayServer::singleton(); let mut window = self.base().get_window().unwrap(); let mut engine = Engine::singleton(); let initial_window_size = disp_server.window_get_size(); let window_offset_after_resize: Vector2i = Vector2i::from_array([(self.window_width - initial_window_size.x) / 2, (self.window_height - initial_window_size.y) / 2]); if self.is_fullscreen { disp_server.window_set_mode(WindowMode::FULLSCREEN) } else { disp_server.window_set_mode(WindowMode::WINDOWED) } if self.vertical_sync { disp_server.window_set_vsync_mode(VSyncMode::ENABLED); } else { disp_server.window_set_vsync_mode(VSyncMode::DISABLED); } disp_server.window_set_flag(WindowFlags::BORDERLESS, self.is_borderless); disp_server.window_set_current_screen(self.monitor); disp_server.window_set_size(Vector2i::from_array([self.window_width, self.window_height])); //FIXME: Doesn't seem to work on Linux, at least not on KDE+Wayland. Most likely an issue with Godot itself // as trying to set the window position from GDscript doesn't work either... // EDIT: It worked for a moment, then broke again... weird window.set_initial_position(WindowInitialPosition::ABSOLUTE); if cfg!(debug_assertions) { godot_print!("WINDOW SIZE: {}, {}", initial_window_size.x, initial_window_size.y); godot_print!("Initial size: {}, {}", initial_window_size.x, initial_window_size.y); godot_print!("offset: {}, {}", window_offset_after_resize.x, window_offset_after_resize.y); godot_print!("New pos: {}, {}", self.window_position_x - window_offset_after_resize.x, self.window_position_y - window_offset_after_resize.y); } window.set_position(Vector2i::from_array([self.window_position_x - window_offset_after_resize.x, initial_window_size.y - window_offset_after_resize.y])); engine.set_max_fps(self.max_framerate); } }