A card game engine for TCGs, primarily Magic: The Gathering but with support for others
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Unfortunate that I'm returning to full Godot

+138 -33
+1
gdext/Cargo.toml
··· 7 7 crate-type = ["cdylib"] 8 8 9 9 [dependencies] 10 + godot_tokio = "0.3.1" 10 11 uuid = { version = "1.23.1", features = ["v4", "v5"] } 11 12 12 13 [dependencies.managrove-core]
+32 -2
gdext/src/lib.rs
··· 1 - use godot::prelude::*; 1 + use godot::{classes::Engine, prelude::*}; 2 + use godot_tokio::AsyncRuntime; 2 3 use managrove_core::Game; 3 4 4 5 mod ui; ··· 13 14 } 14 15 15 16 #[gdextension] 16 - unsafe impl ExtensionLibrary for ManaGroveNode {} 17 + unsafe impl ExtensionLibrary for ManaGroveNode { 18 + fn on_stage_init(stage: InitStage) { 19 + match stage { 20 + InitStage::Scene => { 21 + let mut engine = Engine::singleton(); 22 + engine.register_singleton(AsyncRuntime::SINGLETON, &AsyncRuntime::new_alloc()); 23 + }, 24 + _ => () 25 + } 26 + } 27 + 28 + fn on_stage_deinit(stage: InitStage) { 29 + match stage { 30 + InitStage::Scene => { 31 + let mut engine = Engine::singleton(); 32 + 33 + if let Some(async_singleton) = engine.get_singleton(AsyncRuntime::SINGLETON) { 34 + engine.unregister_singleton(AsyncRuntime::SINGLETON); 35 + async_singleton.free(); 36 + } else { 37 + godot_warn!( 38 + "Failed to find & free singleton -> {}", 39 + AsyncRuntime::SINGLETON 40 + ); 41 + } 42 + }, 43 + _ => () 44 + } 45 + } 46 + } 17 47 18 48 #[godot_api] 19 49 impl INode for ManaGroveNode {
+71
gdext/src/ui/card_base_state.rs
··· 1 + use godot::{classes::{ColorRect, InputEvent}, prelude::*}; 2 + use godot_tokio::AsyncRuntime; 3 + use crate::ui::{CardUI, card_state::{CardState, State, StateTrait}}; 4 + 5 + #[derive(GodotClass, Clone)] 6 + #[class(init, base=Node)] 7 + pub struct CardBaseState { 8 + base: Base<Node>, 9 + card_ui: Option<Gd<CardUI>> 10 + } 11 + 12 + #[godot_api] 13 + impl CardBaseState { 14 + #[signal] 15 + pub fn transition_requested(from: Gd<CardState>, to: State); 16 + } 17 + 18 + impl StateTrait for CardBaseState { 19 + fn enter(&mut self) { 20 + let mut card_state: CardState = self.clone().into(); 21 + 22 + if let Some(card_ui) = card_state.get_card_ui_mut() { 23 + if !card_ui.is_node_ready() { 24 + AsyncRuntime::block_on( 25 + card_ui 26 + .signals() 27 + .ready() 28 + .to_future() 29 + ); 30 + } 31 + 32 + card_ui.signals().reparent_requested().emit(card_ui); 33 + card_ui.call("set_color", &[Variant::from(Color::WEB_GREEN)]); 34 + card_ui.call("set_state", &[Variant::from(String::from("BASE")]); 35 + card_ui.set_pivot_offset(Vector2::ZERO); 36 + } 37 + } 38 + 39 + fn exit(&mut self) { 40 + 41 + } 42 + 43 + fn on_gui_input(&mut self, event: Gd<InputEvent>) { 44 + let mut card_state: CardState = self.clone().into(); 45 + 46 + if event.is_action_pressed("left_mouse") { 47 + if let Some(card_ui) = card_state.get_card_ui_mut() { 48 + card_ui.set_pivot_offset(card_ui.get_global_mouse_position() - card_ui.get_global_position()); 49 + self.signals().transition_requested().emit(*self, State::Clicked); 50 + } 51 + } 52 + } 53 + 54 + fn on_input(&mut self, event: Gd<InputEvent>) { 55 + 56 + } 57 + 58 + fn on_mouse_entered(&mut self) { 59 + 60 + } 61 + 62 + fn on_mouse_exited(&mut self) { 63 + 64 + } 65 + } 66 + 67 + impl Into<CardState> for CardBaseState { 68 + fn into(self) -> CardState { 69 + CardState::new(self.base, State::Base, self.card_ui.clone()) 70 + } 71 + }
+19 -31
gdext/src/ui/card_state.rs
··· 2 2 use crate::ui::CardUI; 3 3 4 4 #[derive(GodotClass)] 5 - #[class(base=Node)] 5 + #[class(init, base=Node)] 6 6 pub struct CardState { 7 7 base: Base<Node>, 8 8 #[export] ··· 10 10 card_ui: Option<Gd<CardUI>> 11 11 } 12 12 13 - #[godot_api] 14 - impl INode for CardState { 15 - fn init(base: Base<Node>) -> Self { 16 - Self { 17 - base, 18 - state: State::Base, 19 - card_ui: None 20 - } 21 - } 13 + pub trait StateTrait { 14 + fn enter(&mut self); 15 + fn exit(&mut self); 16 + fn on_input(&mut self, event: Gd<InputEvent>); 17 + fn on_gui_input(&mut self, event: Gd<InputEvent>); 18 + fn on_mouse_entered(&mut self); 19 + fn on_mouse_exited(&mut self); 22 20 } 23 21 24 22 #[godot_api] 25 23 impl CardState { 26 24 #[signal] 27 25 pub fn transition_requested(from: Gd<CardState>, to: State); 28 - } 29 26 30 - impl CardState { 31 - fn enter(&mut self) { 32 - 33 - } 34 - 35 - fn exit(&mut self) { 36 - 27 + pub fn new(base: Base<Node>, state: State, card_ui: Option<Gd<CardUI>>) -> Self { 28 + Self { 29 + base, 30 + state, 31 + card_ui 32 + } 37 33 } 38 34 39 - fn on_input(&mut self, _event: Gd<InputEvent>) { 40 - 35 + pub fn get_card_ui(&self) -> &Option<Gd<CardUI>> { 36 + &self.card_ui 41 37 } 42 - 43 - fn on_gui_input(&mut self, _event: Gd<InputEvent>) { 44 - 45 - } 46 - 47 - fn on_mouse_entered(&mut self) { 48 - 49 - } 50 - 51 - fn on_mouse_exited(&mut self) { 52 - 38 + 39 + pub fn get_card_ui_mut(&mut self) -> &mut Option<Gd<CardUI>> { 40 + &mut self.card_ui 53 41 } 54 42 } 55 43
+15
gdext/src/ui/mod.rs
··· 2 2 3 3 mod card_state; 4 4 mod card_state_machine; 5 + mod card_base_state; 5 6 6 7 #[derive(GodotClass)] 7 8 #[class(base=Control)] ··· 31 32 impl CardUI { 32 33 #[signal] 33 34 fn reparent_requested(which_card_ui: Gd<CardUI>); 35 + 36 + #[func] 37 + fn set_color(&mut self, color: Color) { 38 + if let Some(color_rect) = &mut self.color { 39 + color_rect.set_color(color); 40 + } 41 + } 42 + 43 + #[func] 44 + fn set_state(&mut self, text: GString) { 45 + if let Some(label) = &mut self.state { 46 + label.set_text(text); 47 + } 48 + } 34 49 }