godot-ggrs-wrapper 0.5.0

A Rust GDNative project to provide GGRS to the Godot Engine
Documentation
use crate::*;
use ggrs::{PlayerHandle, SyncTestSession};

/// A Godot implementation of [`SyncTestSession`]
#[derive(NativeClass)]
#[inherit(Node)]
pub struct GodotGGRSSyncTestSession {
    sess: Option<SyncTestSession>,
    callback_node: Option<Ref<Node>>,
}

impl GodotGGRSSyncTestSession {
    fn new(_owner: &Node) -> Self {
        GodotGGRSSyncTestSession {
            sess: None,
            callback_node: None,
        }
    }
}

#[methods]
impl GodotGGRSSyncTestSession {
    //EXPORTED FUNCTIONS
    #[export]
    fn _ready(&self, _owner: &Node) {
        godot_print!("GodotGGRSSyncTest _ready() called.");
    }

    /// Creates a [SyncTestSession],
    /// call this when you want to start setting up a `SyncTestSession` takes the total number of players, the check distance and the max prediction frames as parameters
    /// # Notes
    /// - Max prediction frames is the maximum number of frames GGRS will roll back. Every gamestate older than this is guaranteed to be correct if the players did not desync.
    /// - This value used to default to `8 frames`, but this has been made adjustable with `GGRS 0.7.0`
    #[export]
    pub fn create_new_session(
        &mut self,
        _owner: &Node,
        num_players: u32,
        check_distance: usize,
        max_pred: usize,
    ) {
        let input_size: usize = std::mem::size_of::<u32>();
        match SyncTestSession::new(num_players, input_size, max_pred, check_distance) {
            Ok(s) => self.sess = Some(s),
            Err(e) => godot_error!("{}", e),
        }
    }

    /// Deprecated method to create a [SyncTestSession]. Use [Self::create_new_session()] instead.
    #[deprecated(since = "0.5.0", note = "please use `create_new_session()` instead")]
    #[export]
    pub fn create_session(&mut self, _owner: &Node, num_players: u32, check_distance: usize) {
        self.create_new_session(_owner, num_players, check_distance, 8)
    }

    /// Sets [SyncTestSession::set_frame_delay()] of specified handle.
    /// # Errors
    /// - Will print a [ERR_MESSAGE_NO_SESSION_MADE] error if a session has not been made
    #[export]
    pub fn set_frame_delay(
        &mut self,
        _owner: &Node,
        frame_delay: u32,
        player_handle: PlayerHandle,
    ) {
        match &mut self.sess {
            Some(s) => match s.set_frame_delay(frame_delay, player_handle) {
                Ok(_) => return,
                Err(e) => godot_error!("{}", e),
            },
            None => godot_error!("{}", ERR_MESSAGE_NO_SESSION_MADE),
        }
    }

    /// This function will advance the frame using an array of all the inputs given as a parameter (inputs are currently an int in Godot).
    /// Before using this function you have to set the callback node and make sure it has the following callback functions implemented
    /// - [CALLBACK_FUNC_SAVE_GAME_STATE]
    /// - [CALLBACK_FUNC_LOAD_GAME_STATE]
    /// - [CALLBACK_FUNC_SAVE_GAME_STATE]
    /// # Errors
    /// - Will print a [ERR_MESSAGE_NO_SESSION_MADE] error if a session has not been made
    /// - Will print a [ERR_MESSAGE_NO_CALLBACK_NODE] error if a callback node has not been set
    #[export]
    pub fn advance_frame(&mut self, _owner: &Node, all_inputs: Vec<u32>) {
        let mut all_inputs_bytes = Vec::new();
        for i in all_inputs {
            all_inputs_bytes.push(Vec::from(i.to_be_bytes()));
        }

        match self.callback_node {
            Some(callback_node) => match &mut self.sess {
                Some(s) => match s.advance_frame(&all_inputs_bytes) {
                    Ok(requests) => {
                        ggrs_request_handlers::handle_requests(&callback_node, requests);
                    }
                    Err(e) => {
                        godot_error!("{}", e);
                    }
                },
                None => {
                    godot_error!("{}", ERR_MESSAGE_NO_SESSION_MADE);
                }
            },
            None => {
                godot_error!("{}", ERR_MESSAGE_NO_CALLBACK_NODE);
            }
        }
    }

    /// Calls and returns [SyncTestSession::max_prediction()].
    /// Will return a 0 if no session was made.
    /// # Errors
    /// - Will print an [ERR_MESSAGE_NO_SESSION_MADE] error if a session has not been made
    #[export]
    pub fn get_max_prediction(&mut self, _owner: &Node) -> usize {
        match &mut self.sess {
            Some(s) => s.max_prediction(),
            None => {
                godot_error!("{}", ERR_MESSAGE_NO_SESSION_MADE);
                return 0;
            }
        }
    }

    /// Sets the callback node that will be called when using [Self::advance_frame()]
    #[export]
    pub fn set_callback_node(&mut self, _owner: &Node, callback: Ref<Node>) {
        self.callback_node = Some(callback);
    }
}