From 9d55a51782e811e8a71cda1a3d7872371ec54aeb Mon Sep 17 00:00:00 2001 From: "1992414357@qq.com" <1992414357@qq.com> Date: Sat, 14 Jun 2025 16:13:13 +0800 Subject: Change std::os::raw to std::ffi --- core/bindings/lang/clang/src/data/ngpd_game_info.rs | 3 +-- core/bindings/lang/clang/src/data/ngpd_message.rs | 8 +++++++- core/bindings/lang/clang/src/data/ngpd_player.rs | 9 +++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'core') diff --git a/core/bindings/lang/clang/src/data/ngpd_game_info.rs b/core/bindings/lang/clang/src/data/ngpd_game_info.rs index af45758..b83d0f7 100644 --- a/core/bindings/lang/clang/src/data/ngpd_game_info.rs +++ b/core/bindings/lang/clang/src/data/ngpd_game_info.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use std::ffi::{CStr, CString}; -use std::os::raw::c_char; +use std::ffi::{c_char, CStr, CString}; #[repr(C)] pub struct KeyValuePair { diff --git a/core/bindings/lang/clang/src/data/ngpd_message.rs b/core/bindings/lang/clang/src/data/ngpd_message.rs index c11ac12..466b50d 100644 --- a/core/bindings/lang/clang/src/data/ngpd_message.rs +++ b/core/bindings/lang/clang/src/data/ngpd_message.rs @@ -1,10 +1,10 @@ +use std::ffi::{c_char, c_double}; use crate::converter::string_converter::{str_c_to_rs, str_rs_to_c}; use crate::data::ngpd_game_info::FfiGameInfo; use crate::data::ngpd_player::FfiPlayer; use nogamepads_core::data::message::message_enums::{ConnectionMessage, ConnectionResponseMessage, ControlMessage, ExitReason, GameMessage, JoinFailedMessage}; use std::mem::ManuallyDrop; use std::ops::Deref; -use std::os::raw::{c_char, c_double}; #[repr(C)] pub struct FfiControlMessage { @@ -481,31 +481,37 @@ impl From<&FfiJoinFailedMessage> for JoinFailedMessage { } } +/// Free ControlMessage #[unsafe(no_mangle)] pub extern "C" fn free_control_message(msg: FfiControlMessage) { let _ = msg; } +/// Free GameMessage #[unsafe(no_mangle)] pub extern "C" fn free_game_message(msg: FfiGameMessage) { let _ = msg; } +/// Free ExitReason #[unsafe(no_mangle)] pub extern "C" fn free_exit_reason(msg: FfiExitReason) { let _ = msg; } +/// Free ConnectionMessage #[unsafe(no_mangle)] pub extern "C" fn free_connection_message(msg: FfiConnectionMessage) { let _ = msg; } +/// Free ConnectionResponseMessage #[unsafe(no_mangle)] pub extern "C" fn free_connection_response_message(msg: FfiConnectionResponseMessage) { let _ = msg; } +/// Free JoinFailedMessage #[unsafe(no_mangle)] pub extern "C" fn free_join_failed_message(msg: FfiJoinFailedMessage) { let _ = msg; diff --git a/core/bindings/lang/clang/src/data/ngpd_player.rs b/core/bindings/lang/clang/src/data/ngpd_player.rs index a1a8370..3f6a84a 100644 --- a/core/bindings/lang/clang/src/data/ngpd_player.rs +++ b/core/bindings/lang/clang/src/data/ngpd_player.rs @@ -1,5 +1,4 @@ -use std::ffi::{CStr, CString}; -use std::os::raw::{c_char, c_double, c_int}; +use std::ffi::{c_char, c_double, c_int, CStr, CString}; use std::ptr; use nogamepads_core::data::player::player_data::{Account, Customize, Player}; @@ -73,6 +72,7 @@ impl TryFrom<&FfiPlayer> for Player { } } +/// Register a player #[unsafe(no_mangle)] pub extern "C" fn player_register(id: *const c_char, password: *const c_char) -> *mut FfiPlayer { let id_str = unsafe { CStr::from_ptr(id) }.to_string_lossy(); @@ -82,6 +82,7 @@ pub extern "C" fn player_register(id: *const c_char, password: *const c_char) -> Box::into_raw(Box::new(FfiPlayer::from(&player))) } +/// Check if the player's password is correct #[unsafe(no_mangle)] pub extern "C" fn player_check(player: *const FfiPlayer, password: *const c_char) -> bool { let player = unsafe { &*player }; @@ -92,6 +93,7 @@ pub extern "C" fn player_check(player: *const FfiPlayer, password: *const c_char .unwrap_or(false) } +/// Set the player's nickname #[unsafe(no_mangle)] pub extern "C" fn player_set_nickname(player: *mut FfiPlayer, nickname: *const c_char) { let nickname_str = unsafe { CStr::from_ptr(nickname) }.to_string_lossy().into_owned(); @@ -101,6 +103,7 @@ pub extern "C" fn player_set_nickname(player: *mut FfiPlayer, nickname: *const c *unsafe { &mut *player } = FfiPlayer::from(&rust_player); } +/// Set the player's hue #[unsafe(no_mangle)] pub extern "C" fn player_set_hue(player: *mut FfiPlayer, hue: c_int) { let mut rust_player : Player = unsafe { (&*player).try_into().unwrap() }; @@ -109,6 +112,7 @@ pub extern "C" fn player_set_hue(player: *mut FfiPlayer, hue: c_int) { *unsafe { &mut *player } = FfiPlayer::from(&rust_player); } +/// Set the player's HSV color #[unsafe(no_mangle)] pub extern "C" fn player_set_hsv( player: *mut FfiPlayer, hue: c_int, saturation: c_double, value: c_double @@ -119,6 +123,7 @@ pub extern "C" fn player_set_hsv( *unsafe { &mut *player } = FfiPlayer::from(&rust_player); } +/// Free the player #[unsafe(no_mangle)] pub extern "C" fn player_free(player: *mut FfiPlayer) { if player.is_null() { return; } -- cgit From 70af7ac1dee88dee9197abc626982d6555aeb97a Mon Sep 17 00:00:00 2001 From: "1992414357@qq.com" <1992414357@qq.com> Date: Sat, 14 Jun 2025 16:13:57 +0800 Subject: Add Controller Ffi Interface --- .../lang/clang/configures/nogamepads_data.toml | 3 +- core/bindings/lang/clang/headers/nogamepads_data.h | 116 ++++++++ core/bindings/lang/clang/src/data/mod.rs | 3 +- .../lang/clang/src/data/ngpd_controller.rs | 309 +++++++++++++++++++++ 4 files changed, 429 insertions(+), 2 deletions(-) create mode 100644 core/bindings/lang/clang/src/data/ngpd_controller.rs (limited to 'core') diff --git a/core/bindings/lang/clang/configures/nogamepads_data.toml b/core/bindings/lang/clang/configures/nogamepads_data.toml index 8078516..5c7e91b 100644 --- a/core/bindings/lang/clang/configures/nogamepads_data.toml +++ b/core/bindings/lang/clang/configures/nogamepads_data.toml @@ -10,5 +10,6 @@ include = [ "ngpd_game_info", "ngpd_message", - "ngpd_player" + "ngpd_player", + "ngpd_controller", ] \ No newline at end of file diff --git a/core/bindings/lang/clang/headers/nogamepads_data.h b/core/bindings/lang/clang/headers/nogamepads_data.h index 83b8de6..102aaef 100644 --- a/core/bindings/lang/clang/headers/nogamepads_data.h +++ b/core/bindings/lang/clang/headers/nogamepads_data.h @@ -142,38 +142,154 @@ typedef struct FfiConnectionResponseMessage { union FfiConnectionResponseMessageUnion data; } FfiConnectionResponseMessage; +typedef struct FfiControllerData { + void *_0; +} FfiControllerData; + +typedef struct FfiControllerRuntime { + void *inner; + void (*drop_fn)(void*); +} FfiControllerRuntime; + #ifdef __cplusplus extern "C" { #endif // __cplusplus void free_c_string(char *ptr); +/** + * Register a player + */ struct FfiPlayer *player_register(const char *id, const char *password); +/** + * Check if the player's password is correct + */ bool player_check(const struct FfiPlayer *player, const char *password); +/** + * Set the player's nickname + */ void player_set_nickname(struct FfiPlayer *player, const char *nickname); +/** + * Set the player's hue + */ void player_set_hue(struct FfiPlayer *player, int hue); +/** + * Set the player's HSV color + */ void player_set_hsv(struct FfiPlayer *player, int hue, double saturation, double value); +/** + * Free the player + */ void player_free(struct FfiPlayer *player); +/** + * Free ControlMessage + */ void free_control_message(struct FfiControlMessage msg); +/** + * Free GameMessage + */ void free_game_message(struct FfiGameMessage msg); +/** + * Free ExitReason + */ void free_exit_reason(enum FfiExitReason msg); +/** + * Free ConnectionMessage + */ void free_connection_message(struct FfiConnectionMessage msg); +/** + * Free ConnectionResponseMessage + */ void free_connection_response_message(struct FfiConnectionResponseMessage msg); +/** + * Free JoinFailedMessage + */ void free_join_failed_message(enum FfiJoinFailedMessage msg); void free_game_info(struct FfiGameInfo map); +/** + * Create controller data + */ +struct FfiControllerData *controller_data_new(void); + +/** + * Bind player to controller + */ +void controller_data_bind_player(struct FfiControllerData *controller, + struct FfiPlayer *ffi_player); + +/** + * Build runtime + */ +struct FfiControllerRuntime *controller_data_build_runtime(struct FfiControllerData *controller); + +/** + * Free ControllerData memory + */ +void controller_data_free(struct FfiControllerData *controller); + +/** + * Close runtime and exit game + */ +void controller_runtime_close(struct FfiControllerRuntime *runtime); + +/** + * Send control message + */ +void controller_runtime_send_message(struct FfiControllerRuntime *runtime, + struct FfiControlMessage *control_message); + +/** + * Send text message + */ +void controller_runtime_send_text_message(struct FfiControllerRuntime *runtime, + const char *message_ptr); + +/** + * Press a button + */ +void controller_runtime_press_a_button(struct FfiControllerRuntime *runtime, uint8_t key); + +/** + * Release a button + */ +void controller_runtime_release_a_button(struct FfiControllerRuntime *runtime, uint8_t key); + +/** + * Release a button + */ +void controller_runtime_change_axis(struct FfiControllerRuntime *runtime, uint8_t key, double axis); + +/** + * Release a button + */ +void controller_runtime_change_direction(struct FfiControllerRuntime *runtime, + uint8_t key, + double x, + double y); + +/** + * Pop a message from the queue + */ +struct FfiGameMessage *controller_runtime_pop(struct FfiControllerRuntime *runtime); + +/** + * Free runtime memory + */ +void controller_runtime_free(struct FfiControllerRuntime *runtime); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/core/bindings/lang/clang/src/data/mod.rs b/core/bindings/lang/clang/src/data/mod.rs index c93e7f0..ca432f9 100644 --- a/core/bindings/lang/clang/src/data/mod.rs +++ b/core/bindings/lang/clang/src/data/mod.rs @@ -1,3 +1,4 @@ pub mod ngpd_player; pub mod ngpd_message; -mod ngpd_game_info; \ No newline at end of file +mod ngpd_game_info; +mod ngpd_controller; \ No newline at end of file diff --git a/core/bindings/lang/clang/src/data/ngpd_controller.rs b/core/bindings/lang/clang/src/data/ngpd_controller.rs new file mode 100644 index 0000000..923218b --- /dev/null +++ b/core/bindings/lang/clang/src/data/ngpd_controller.rs @@ -0,0 +1,309 @@ +use crate::data::ngpd_message::{FfiControlMessage, FfiGameMessage}; +use crate::data::ngpd_player::FfiPlayer; +use nogamepads::entry_mutex; +use nogamepads_core::data::controller::controller_data::ControllerData; +use nogamepads_core::data::controller::controller_runtime::ControllerRuntime; +use nogamepads_core::data::message::message_enums::ControlMessage; +use nogamepads_core::data::player::player_data::Player; +use std::ffi::{c_char, c_double, c_void, CStr}; +use std::sync::{Arc, Mutex}; + +#[repr(C)] +pub struct FfiControllerData(*mut c_void); + +#[repr(C)] +pub struct FfiControllerRuntime { + inner: *mut c_void, + drop_fn: extern "C" fn(*mut c_void), +} + +impl FfiControllerData { + + /// Create controller data + #[unsafe(no_mangle)] + pub extern "C" fn controller_data_new() -> *mut FfiControllerData { + let controller_data = ControllerData::default(); + let raw = Box::into_raw(Box::new(FfiControllerData(Box::into_raw(Box::new(controller_data)) as *mut _))); + raw + } + + /// Bind player to controller + #[unsafe(no_mangle)] + #[allow(unsafe_op_in_unsafe_fn)] + pub unsafe extern "C" fn controller_data_bind_player( + controller: *mut FfiControllerData, + ffi_player: *mut FfiPlayer + ) { + assert!(!controller.is_null(), "ControllerData pointer is null"); + assert!(!ffi_player.is_null(), "FfiPlayer pointer is null"); + + let ffi_player_ref = unsafe { &*ffi_player }; + + // Convert FfiPlayer to Player + let player = Player::try_from(&*ffi_player_ref).unwrap_or_default(); + + // Get a mutable reference to the inner ControllerData + let controller_inner = unsafe { &mut *((*controller).0 as *mut ControllerData) }; + controller_inner.bind_player(player); + + // Release the FFI Player + drop(Box::from_raw(ffi_player)); + } + + /// Build runtime + #[unsafe(no_mangle)] + #[allow(unsafe_op_in_unsafe_fn)] + pub unsafe extern "C" fn controller_data_build_runtime( + controller: *mut FfiControllerData + ) -> *mut FfiControllerRuntime { + assert!(!controller.is_null(), "ControllerData pointer is null"); + + // Take ownership + let controller_box = unsafe { Box::from_raw(controller) }; + let raw_data = (*controller_box).0; + + // Convert ControllerData + let controller_data = unsafe { Box::from_raw(raw_data as *mut ControllerData) }; + let runtime = controller_data.runtime(); + + // Define custom drop function + extern "C" fn drop_runtime(raw: *mut c_void) { + unsafe { + let arc_ptr = raw as *const Arc>; + drop(Arc::from_raw(arc_ptr)); + } + } + + // Convert to an FFI-safe structure + let arc_raw = Arc::into_raw(runtime.clone()) as *mut c_void; + + Box::into_raw(Box::new(FfiControllerRuntime { + inner: arc_raw, + drop_fn: drop_runtime, + })) + } + + /// Free ControllerData memory + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_data_free(controller: *mut FfiControllerData) { + if controller.is_null() { + return; + } + + let controller_box = unsafe { Box::from_raw(controller) }; + let raw_data = (*controller_box).0; + + if !raw_data.is_null() { + unsafe { + drop(Box::from_raw(raw_data as *mut ControllerData)); + } + } + } +} + +// ControllerRuntime implementation +impl FfiControllerRuntime { + + /// Close runtime and exit game + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_close( + runtime: *mut FfiControllerRuntime + ) { + if runtime.is_null() { + return; + } + + let arc_ptr = unsafe { (*runtime).inner as *const Arc> }; + let arc_ref = unsafe { Arc::from_raw(arc_ptr) }; + + entry_mutex!(*arc_ref, |mutex_guard| { + mutex_guard.close(); + }); + + // Reconstruct Arc + let _ = Arc::into_raw(arc_ref); + } + + /// Send control message + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_send_message( + runtime: *mut FfiControllerRuntime, + control_message: *mut FfiControlMessage + ) { + if runtime.is_null() { + return; + } + + let arc_ptr = unsafe { (*runtime).inner as *const Arc> }; + let arc_ref = unsafe { Arc::from_raw(arc_ptr) }; + let msg = unsafe { ControlMessage::from(control_message.read()) }; + + entry_mutex!(*arc_ref, |mutex_guard| { + mutex_guard.send_message(msg); + }); + + let _ = Arc::into_raw(arc_ref); + } + + /// Send text message + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_send_text_message( + runtime: *mut FfiControllerRuntime, + message_ptr: *const c_char + ) { + if runtime.is_null() || message_ptr.is_null() { + return; + } + + let c_str = unsafe { CStr::from_ptr(message_ptr) }; + let text = c_str.to_string_lossy().into_owned(); + let message = FfiControlMessage::from(ControlMessage::Msg(text)); + + unsafe { + Self::controller_runtime_send_message( + runtime, + Box::into_raw(Box::new(message)) + ) + } + } + + /// Press a button + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_press_a_button( + runtime: *mut FfiControllerRuntime, + key: u8 + ) { + if runtime.is_null() { + return; + } + + let message = FfiControlMessage::from( + ControlMessage::Pressed(key) + ); + + unsafe { + Self::controller_runtime_send_message( + runtime, + Box::into_raw(Box::new(message)) + ) + } + } + + /// Release a button + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_release_a_button( + runtime: *mut FfiControllerRuntime, + key: u8 + ) { + if runtime.is_null() { + return; + } + + let message = FfiControlMessage::from( + ControlMessage::Released(key) + ); + + unsafe { + Self::controller_runtime_send_message( + runtime, + Box::into_raw(Box::new(message)) + ) + } + } + + /// Change axis value + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_change_axis( + runtime: *mut FfiControllerRuntime, + key: u8, + axis: c_double + ) { + if runtime.is_null() { + return; + } + + let message = FfiControlMessage::from( + ControlMessage::Axis(key, axis) + ); + + unsafe { + Self::controller_runtime_send_message( + runtime, + Box::into_raw(Box::new(message)) + ) + } + } + + /// Change direction value + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_change_direction( + runtime: *mut FfiControllerRuntime, + key: u8, + x: c_double, + y: c_double + ) { + if runtime.is_null() { + return; + } + + let message = FfiControlMessage::from( + ControlMessage::Dir(key, (x, y)) + ); + + unsafe { + Self::controller_runtime_send_message( + runtime, + Box::into_raw(Box::new(message)) + ) + } + } + + /// Pop a message from the queue + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_pop( + runtime: *mut FfiControllerRuntime + ) -> *mut FfiGameMessage { + if runtime.is_null() { + return std::ptr::null_mut(); + } + + let arc_ptr = unsafe { (*runtime).inner as *const Arc> }; + let arc_ref = unsafe { Arc::from_raw(arc_ptr) }; + + let result = { + let mut pop_result = None; + + entry_mutex!(*arc_ref, |mutex_guard| { + pop_result = mutex_guard.pop(); + }); + + pop_result + }; + + // Reconstruct Arc + let _ = Arc::into_raw(arc_ref); + + if let Some(msg) = result { + // Convert to FFI type + let ffi_msg = Box::new(FfiGameMessage::from(msg)); + Box::into_raw(ffi_msg) + } else { + std::ptr::null_mut() + } + } + + /// Free runtime memory + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_free(runtime: *mut FfiControllerRuntime) { + if runtime.is_null() { + return; + } + + let runtime_box = unsafe { Box::from_raw(runtime) }; + let drop_fn = (*runtime_box).drop_fn; + let raw = (*runtime_box).inner; + + // Call custom drop function + drop_fn(raw); + } +} \ No newline at end of file -- cgit From 1541023a511e6fcfd01d0e8a2edcdd1416d5463e Mon Sep 17 00:00:00 2001 From: "1992414357@qq.com" <1992414357@qq.com> Date: Sat, 14 Jun 2025 16:14:23 +0800 Subject: Change ControllerRuntime::send_message to public --- core/src/data/controller/controller_runtime.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core') diff --git a/core/src/data/controller/controller_runtime.rs b/core/src/data/controller/controller_runtime.rs index 5e7bb6d..9030fb1 100644 --- a/core/src/data/controller/controller_runtime.rs +++ b/core/src/data/controller/controller_runtime.rs @@ -68,7 +68,7 @@ impl ControllerRuntime { self.receive(0, self.service_type.clone()) } - fn send_message (&mut self, msg: ControlMessage) { + pub fn send_message (&mut self, msg: ControlMessage) { let service = self.service_type.clone(); self.send(msg, 0, service); } -- cgit From 96220ad67a9cc64fb415db684ace23ec5d282577 Mon Sep 17 00:00:00 2001 From: "1992414357@qq.com" <1992414357@qq.com> Date: Sat, 14 Jun 2025 16:14:46 +0800 Subject: Add log library --- core/bindings/lang/clang/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) (limited to 'core') diff --git a/core/bindings/lang/clang/Cargo.toml b/core/bindings/lang/clang/Cargo.toml index 7359db0..a0c8283 100644 --- a/core/bindings/lang/clang/Cargo.toml +++ b/core/bindings/lang/clang/Cargo.toml @@ -6,7 +6,9 @@ version.workspace = true build = "build.rs" [dependencies] +nogamepads = { path = "./../../../../../NoGamepads" } nogamepads-core = { path = "./../../../../core" } +log = "0.4.27" [build-dependencies] cbindgen = "0.29.0" -- cgit From dc160a7af982c0941dcf34cd97cf7673027d802a Mon Sep 17 00:00:00 2001 From: "1992414357@qq.com" <1992414357@qq.com> Date: Sat, 14 Jun 2025 16:15:24 +0800 Subject: Remove unused log library --- core/bindings/lang/clang/Cargo.toml | 1 - 1 file changed, 1 deletion(-) (limited to 'core') diff --git a/core/bindings/lang/clang/Cargo.toml b/core/bindings/lang/clang/Cargo.toml index a0c8283..7eae084 100644 --- a/core/bindings/lang/clang/Cargo.toml +++ b/core/bindings/lang/clang/Cargo.toml @@ -8,7 +8,6 @@ build = "build.rs" [dependencies] nogamepads = { path = "./../../../../../NoGamepads" } nogamepads-core = { path = "./../../../../core" } -log = "0.4.27" [build-dependencies] cbindgen = "0.29.0" -- cgit