aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--core/bindings/lang/clang/Cargo.toml1
-rw-r--r--core/bindings/lang/clang/configures/nogamepads_data.toml3
-rw-r--r--core/bindings/lang/clang/headers/nogamepads_data.h116
-rw-r--r--core/bindings/lang/clang/src/data/mod.rs3
-rw-r--r--core/bindings/lang/clang/src/data/ngpd_controller.rs309
-rw-r--r--core/bindings/lang/clang/src/data/ngpd_game_info.rs3
-rw-r--r--core/bindings/lang/clang/src/data/ngpd_message.rs8
-rw-r--r--core/bindings/lang/clang/src/data/ngpd_player.rs9
-rw-r--r--core/src/data/controller/controller_runtime.rs2
10 files changed, 447 insertions, 8 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 8d0c110..42c2be8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3227,6 +3227,7 @@ name = "nogamepads-c-bindings"
version = "0.1.0"
dependencies = [
"cbindgen",
+ "nogamepads",
"nogamepads-core",
]
diff --git a/core/bindings/lang/clang/Cargo.toml b/core/bindings/lang/clang/Cargo.toml
index 7359db0..7eae084 100644
--- a/core/bindings/lang/clang/Cargo.toml
+++ b/core/bindings/lang/clang/Cargo.toml
@@ -6,6 +6,7 @@ version.workspace = true
build = "build.rs"
[dependencies]
+nogamepads = { path = "./../../../../../NoGamepads" }
nogamepads-core = { path = "./../../../../core" }
[build-dependencies]
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<Mutex<ControllerRuntime>>;
+ 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<Mutex<ControllerRuntime>> };
+ 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<Mutex<ControllerRuntime>> };
+ 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<Mutex<ControllerRuntime>> };
+ 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
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; }
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);
}