commit ff7ca6cc0f1f25bb02fd3a5e92e2644a43b289a6 Author: XTRA Date: Sat Aug 10 12:00:47 2024 +0300 Import from private repo diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb43611 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +target/ +*.import +Cargo.lock \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..62e4b7b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib"] + + +[dependencies] +godot = { git = "https://github.com/godot-rust/gdext", branch = "master" } +rand = "0.8.5" +toml = "0.8.19" diff --git a/MiniDemoTools.gdextension b/MiniDemoTools.gdextension new file mode 100644 index 0000000..269d0c0 --- /dev/null +++ b/MiniDemoTools.gdextension @@ -0,0 +1,15 @@ +[configuration] +entry_symbol = "gdext_rust_init" +compatibility_minimum = 4.1 +reloadable = true + +[libraries] +linux.debug.x86_64 = "res://addons/MiniDemoTools/librust.so" +linux.release.x86_64 = "res://addons/MiniDemoTools/librust.so" +##windows.debug.x86_64 = "res://../rust/target/debug/librust.dll" +##windows.release.x86_64 = "res://../rust/target/release/librust.dll" + + +[icons] + +ScramblingText = "res://addons/MiniDemoTools/icons/ScrambledText.svg" diff --git a/icons/ScrambledText.svg b/icons/ScrambledText.svg new file mode 100644 index 0000000..ab0e424 --- /dev/null +++ b/icons/ScrambledText.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + diff --git a/src/MiniEditorPlugin.rs b/src/MiniEditorPlugin.rs new file mode 100644 index 0000000..1f5ba5f --- /dev/null +++ b/src/MiniEditorPlugin.rs @@ -0,0 +1,17 @@ +#[derive(GodotClass)] +#[class(tool, init, editor_plugin, base=EditorPlugin)] + +struct MiniEditorPlugin { + base: Base, +} + +#[godot_api] +impl IEditorPlugin for MiniEditorPlugin { + fn enter_tree(&mut self) { + + } + + fn exit_tree(&mut self) { + + } +} \ No newline at end of file diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..40799ab --- /dev/null +++ b/src/config.rs @@ -0,0 +1,139 @@ +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); + + + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..e29ab4c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,29 @@ +use godot::{init::EditorRunBehavior, prelude::*}; + +struct MDT; +mod scrambling_text; +mod config; +mod manager; + +#[gdextension] +unsafe impl ExtensionLibrary for MDT { + + fn editor_run_behavior() -> EditorRunBehavior { + return EditorRunBehavior::AllClasses + } + + fn min_level() -> InitLevel { + return InitLevel::Scene + } + + fn on_level_init(level: InitLevel) { + match level { + InitLevel::Scene => { + if cfg!(debug_assertions) { + godot_print_rich!("[b]MiniDemoTools[/b] is in [color=red][b][u]DEBUG[/u][/b][/color] mode!") + } + } + _ => {} + } + } +} diff --git a/src/manager.rs b/src/manager.rs new file mode 100644 index 0000000..31fb107 --- /dev/null +++ b/src/manager.rs @@ -0,0 +1,69 @@ +use godot::prelude::*; +use godot::global::Key; +use godot::classes::{AudioStreamOggVorbis, Engine, InputEvent, InputEventKey}; + +#[derive(GodotClass)] +#[class(base=Node)] +struct Manager { + #[export(file = "*.ogg")] + bgm: GString, + #[var] + beat_count: i32, + #[var] + scenes: Array>, + instanced_scenes: Vec>, + base: Base +} + +#[godot_api] +impl INode for Manager { + fn init(base: Base) -> Self { + Self { + bgm: GString::from(""), + beat_count: 0, + scenes: Array::new(), + instanced_scenes: Vec::new(), + base, + } + } + + fn unhandled_input(&mut self, event: Gd) { + if event.is_released() { + if let Ok(key) = event.clone().try_cast::() { + if key.get_keycode() == Key::ESCAPE { + godot_print!("Goodbye!"); + self.base_mut().get_tree().unwrap().quit(); + } + } + } + } +} + +#[godot_api] +impl Manager { + #[func] + fn set_scene(&mut self, number: i32) { + let scene = self.instanced_scenes[number as usize].clone(); // Memory leak??? Idk + self.base_mut().add_child(scene); + } + + #[func] + fn register_scene(&mut self, scene: Gd) { + self.instanced_scenes.push(scene.instantiate_as()) + } + + #[func] + fn start_audio(&mut self) { + let editor_hint = Engine::singleton().is_editor_hint(); + if !editor_hint { + let bgm = self.bgm.clone(); + godot_print!(" Hello world fj"); + let mut stream: Gd = load(bgm); + stream.set_loop(false); + let mut player = AudioStreamPlayer::new_alloc(); + player.set_stream(stream); + player.set_autoplay(true); + self.base_mut().add_child(player); + } + } +} \ No newline at end of file diff --git a/src/scrambling_text.rs b/src/scrambling_text.rs new file mode 100644 index 0000000..cde94fa --- /dev/null +++ b/src/scrambling_text.rs @@ -0,0 +1,168 @@ + +use godot::prelude::*; +use godot::classes::{Label, Engine}; + +#[derive(GodotClass)] +#[class(base=Label)] +struct ScramblingText { + #[export(multiline)] + chars: GString, + #[export] + scrambling: bool, + #[export] + speed: f64, + #[export] + duration: f64, + #[export] + infinite: bool, + forbidden_chars: Option>, + original_text: Option, + time_since_scramble: f64, //[DOC] This is the variable used for measuring time since the letters have been scrambled + time_since_step: f64, //[DOC] This is the variable used for measuring time since the amount of static letters was changed + step_iterator: i32, + editor_hint: bool, + base: Base