diff options
| -rw-r--r-- | Cargo.lock | 8 | ||||
| -rw-r--r-- | Cargo.toml | 4 | ||||
| -rw-r--r-- | Project_Export.toml | 10 | ||||
| -rw-r--r-- | apps/client/src/bevy_plugins/plugin_client_app.rs | 6 | ||||
| -rw-r--r-- | apps/client/src/data/layout_data.rs | 2 | ||||
| -rw-r--r-- | apps/console/src/bin/padc.rs | 7 | ||||
| -rw-r--r-- | core/bindings/c_lang/Cargo.toml | 12 | ||||
| -rw-r--r-- | core/bindings/c_lang/headers/ngpd_player.h | 39 | ||||
| -rw-r--r-- | core/bindings/c_lang/src/data/mod.rs | 1 | ||||
| -rw-r--r-- | core/bindings/c_lang/src/data/ngpd_player.rs | 139 | ||||
| -rw-r--r-- | core/bindings/c_lang/src/lib.rs | 1 | ||||
| -rw-r--r-- | core/src/service/cli_addition/runtime_consoles.rs | 3 | ||||
| -rw-r--r-- | export/src/bin/export_project.rs | 6 |
13 files changed, 221 insertions, 17 deletions
@@ -3204,6 +3204,14 @@ dependencies = [ ] [[package]] +name = "nogamepads-c-bindings" +version = "0.1.0" +dependencies = [ + "libc", + "nogamepads-core", +] + +[[package]] name = "nogamepads-client" version = "0.1.0" dependencies = [ @@ -16,7 +16,9 @@ members = [ "core", "apps/console", "apps/client", - "export" + "export", + + "core/bindings/c_lang" ] [workspace.package] diff --git a/Project_Export.toml b/Project_Export.toml index d07bc31..50896b1 100644 --- a/Project_Export.toml +++ b/Project_Export.toml @@ -15,6 +15,11 @@ powershell_complete = { raw = "./.cargo/resources/scripts/", target = "./bin/com "install_completion_powershell.ps1" ] } +# Headers +headers = { raw = "./core/bindings/c_lang/headers/", target = "./lib", files = [ + "ngpd_player.h" +] } + # Items defined in [release.deps] # It will search starting from the build directory and copy to the specified location in the target directory. [release.deps] @@ -22,4 +27,9 @@ powershell_complete = { raw = "./.cargo/resources/scripts/", target = "./bin/com # Windows executables win_exes = { raw = "./", target = "./bin", files = [ "padc.exe", "pad.exe" +] } + +# Windows dynamic link libraries +dlls = { raw = "./", target = "./lib", files = [ + "nogamepads_c.dll" ] }
\ No newline at end of file diff --git a/apps/client/src/bevy_plugins/plugin_client_app.rs b/apps/client/src/bevy_plugins/plugin_client_app.rs index e7d60d2..c95d0a4 100644 --- a/apps/client/src/bevy_plugins/plugin_client_app.rs +++ b/apps/client/src/bevy_plugins/plugin_client_app.rs @@ -1,9 +1,6 @@ use std::sync::{Arc, Mutex}; -use bevy::app::FixedLast; -use bevy::input::common_conditions::input_just_pressed; use bevy::log::info; -use bevy::log::tracing::Instrument; -use bevy::prelude::{App, AppExit, Commands, Component, EventReader, IntoScheduleConfigs, KeyCode, NextState, OnEnter, OnExit, Plugin, PreStartup, Query, ResMut, Startup, State, States, Update}; +use bevy::prelude::{App, Commands, Component, OnEnter, Plugin, PreStartup, Query, ResMut, Startup, States}; use bevy_tokio_tasks::TokioTasksRuntime; use nogamepads::entry_mutex; use nogamepads_core::data::controller::controller_data::ControllerData; @@ -12,6 +9,7 @@ use nogamepads_core::data::player::player_data::Player; use nogamepads_core::service::tcp_network::pad_client::pad_client_service::PadClientNetwork; use crate::bevy_plugins::plugin_client_app::GameState::Exiting; +#[allow(dead_code)] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)] enum GameState { #[default] diff --git a/apps/client/src/data/layout_data.rs b/apps/client/src/data/layout_data.rs index f960b41..9c283e5 100644 --- a/apps/client/src/data/layout_data.rs +++ b/apps/client/src/data/layout_data.rs @@ -13,7 +13,7 @@ pub struct LayoutXml { } #[derive(Debug, Deserialize)] -struct Preload { +pub struct Preload { #[serde(rename = "sound", default)] pub sounds: Vec<Asset>, diff --git a/apps/console/src/bin/padc.rs b/apps/console/src/bin/padc.rs index e44f0f9..e34fee1 100644 --- a/apps/console/src/bin/padc.rs +++ b/apps/console/src/bin/padc.rs @@ -11,14 +11,10 @@ use std::net::SocketAddr; use std::path::PathBuf; use std::process::exit; use std::str::FromStr; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc}; use std::sync::atomic::Ordering::SeqCst; -use std::time::Duration; use clap_complete::{generate, Shell}; use log::{info, LevelFilter}; -use tokio::{select, spawn}; -use tokio::signal::ctrl_c; -use tokio::time::sleep; use nogamepads::entry_mutex; use nogamepads::logger_utils::logger_build; use nogamepads_core::data::controller::controller_cli::{process_controller_cli, ControllerCli}; @@ -31,7 +27,6 @@ use nogamepads_core::service::service_runner::{NoGamepadsService, ServiceRunner} use nogamepads_core::service::tcp_network::DEFAULT_PORT; use nogamepads_core::service::tcp_network::pad_client::pad_client_service::PadClientNetwork; use nogamepads_core::service::tcp_network::pad_server::pad_server_service::PadServerNetwork; -use nogamepads_core::service::tcp_network::utils::tokio_utils::build_tokio_runtime; #[derive(Parser, Debug)] #[command(version, color = ColorChoice::Auto)] diff --git a/core/bindings/c_lang/Cargo.toml b/core/bindings/c_lang/Cargo.toml new file mode 100644 index 0000000..a0ee61f --- /dev/null +++ b/core/bindings/c_lang/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "nogamepads-c-bindings" +edition = "2024" +version.workspace = true + +[dependencies] +nogamepads-core = { path = "../../../core" } +libc = "0.2.172" + +[lib] +name = "nogamepads_c" +crate-type = ["cdylib"] diff --git a/core/bindings/c_lang/headers/ngpd_player.h b/core/bindings/c_lang/headers/ngpd_player.h new file mode 100644 index 0000000..00fbe5b --- /dev/null +++ b/core/bindings/c_lang/headers/ngpd_player.h @@ -0,0 +1,39 @@ +#ifndef PLAYER_FFI_H +#define PLAYER_FFI_H + +#include <stdbool.h> +#include <stdint.h> + +typedef struct FfiAccount { + char* id; + char* player_hash; +} FfiAccount; + +typedef struct FfiCustomize { + char* nickname; + int32_t color_hue; + double color_saturation; + double color_value; +} FfiCustomize; + +typedef struct FfiPlayer { + FfiAccount account; + FfiCustomize* customize; +} FfiPlayer; + +#ifdef __cplusplus +extern "C" { +#endif + +FfiPlayer* player_register(const char* id, const char* password); +bool player_check(const FfiPlayer* player, const char* password); +void player_set_nickname(FfiPlayer* player, const char* nickname); +void player_set_hue(FfiPlayer* player, int hue); +void player_set_hsv(FfiPlayer* player, int hue, double saturation, double value); +void player_free(FfiPlayer* player); + +#ifdef __cplusplus +} +#endif + +#endif
\ No newline at end of file diff --git a/core/bindings/c_lang/src/data/mod.rs b/core/bindings/c_lang/src/data/mod.rs new file mode 100644 index 0000000..32af6d8 --- /dev/null +++ b/core/bindings/c_lang/src/data/mod.rs @@ -0,0 +1 @@ +pub mod ngpd_player;
\ No newline at end of file diff --git a/core/bindings/c_lang/src/data/ngpd_player.rs b/core/bindings/c_lang/src/data/ngpd_player.rs new file mode 100644 index 0000000..2ab615c --- /dev/null +++ b/core/bindings/c_lang/src/data/ngpd_player.rs @@ -0,0 +1,139 @@ +use std::ffi::{CStr, CString}; +use std::os::raw::{c_char, c_double, c_int}; +use std::ptr; +use nogamepads_core::data::player::player_data::{Account, Customize, Player}; + +#[repr(C)] +pub struct FfiAccount { + id: *mut c_char, + player_hash: *mut c_char, +} + +#[repr(C)] +pub struct FfiCustomize { + nickname: *mut c_char, + color_hue: c_int, + color_saturation: c_double, + color_value: c_double, +} + +#[repr(C)] +pub struct FfiPlayer { + account: FfiAccount, + customize: *mut FfiCustomize, +} + +impl From<Account> for FfiAccount { + fn from(acc: Account) -> Self { + FfiAccount { + id: CString::new(acc.id).unwrap().into_raw(), + player_hash: CString::new(acc.player_hash).unwrap().into_raw(), + } + } +} + +impl From<Player> for FfiPlayer { + fn from(player: Player) -> Self { + let account = FfiAccount::from(player.account); + let customize = player.customize.map(|c| { + Box::into_raw(Box::new(FfiCustomize { + nickname: CString::new(c.nickname).unwrap().into_raw(), + color_hue: c.color_hue, + color_saturation: c.color_saturation, + color_value: c.color_value, + })) + }).unwrap_or(ptr::null_mut()); + + FfiPlayer { account, customize } + } +} + +impl TryFrom<&FfiPlayer> for Player { + type Error = (); + + fn try_from(ffi: &FfiPlayer) -> Result<Self, Self::Error> { + let account = Account { + id: unsafe { CStr::from_ptr(ffi.account.id) }.to_str().map_err(|_| ())?.to_owned(), + player_hash: unsafe { CStr::from_ptr(ffi.account.player_hash) }.to_str().map_err(|_| ())?.to_owned(), + }; + + let customize = if !ffi.customize.is_null() { + let c = unsafe { &*ffi.customize }; + Some(Customize { + nickname: unsafe { CStr::from_ptr(c.nickname) }.to_str().map_err(|_| ())?.to_owned(), + color_hue: c.color_hue, + color_saturation: c.color_saturation, + color_value: c.color_value, + }) + } else { + None + }; + + Ok(Player { account, customize }) + } +} + +#[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(); + let pass_str = unsafe { CStr::from_ptr(password) }.to_string_lossy(); + + let player = Player::register(id_str.into_owned(), pass_str.into_owned()); + Box::into_raw(Box::new(FfiPlayer::from(player))) +} + +#[unsafe(no_mangle)] +pub extern "C" fn player_check(player: *const FfiPlayer, password: *const c_char) -> bool { + let player = unsafe { &*player }; + let pass_str = unsafe { CStr::from_ptr(password) }.to_string_lossy(); + + Player::try_from(player) + .map(|p| p.check(pass_str.into_owned())) + .unwrap_or(false) +} + +#[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(); + let mut rust_player : Player = unsafe { (&*player).try_into().unwrap() }; + + rust_player.nickname(&nickname_str); + *unsafe { &mut *player } = FfiPlayer::from(rust_player); +} + +#[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() }; + + rust_player.hue(hue); + *unsafe { &mut *player } = FfiPlayer::from(rust_player); +} + +#[unsafe(no_mangle)] +pub extern "C" fn player_set_hsv( + player: *mut FfiPlayer, hue: c_int, saturation: c_double, value: c_double +) { + let mut rust_player : Player = unsafe { (&*player).try_into().unwrap() }; + + rust_player.hsv(hue, saturation, value); + *unsafe { &mut *player } = FfiPlayer::from(rust_player); +} + +#[unsafe(no_mangle)] +pub extern "C" fn player_free(player: *mut FfiPlayer) { + if player.is_null() { return; } + + let ffi_player = unsafe { Box::from_raw(player) }; + + // Free account strings + unsafe { + let _ = CString::from_raw(ffi_player.account.id); + let _ = CString::from_raw(ffi_player.account.player_hash); + } + + // Free customize if present + if !ffi_player.customize.is_null() { + let ffi_custom = unsafe { Box::from_raw(ffi_player.customize) }; + unsafe { let _ = CString::from_raw(ffi_custom.nickname); }; + } +}
\ No newline at end of file diff --git a/core/bindings/c_lang/src/lib.rs b/core/bindings/c_lang/src/lib.rs new file mode 100644 index 0000000..12e35bb --- /dev/null +++ b/core/bindings/c_lang/src/lib.rs @@ -0,0 +1 @@ +pub mod data;
\ No newline at end of file diff --git a/core/src/service/cli_addition/runtime_consoles.rs b/core/src/service/cli_addition/runtime_consoles.rs index c96c0f2..2b2984b 100644 --- a/core/src/service/cli_addition/runtime_consoles.rs +++ b/core/src/service/cli_addition/runtime_consoles.rs @@ -1,10 +1,9 @@ -use std::process::exit; use crate::service::cli_addition::utils::read_cli; use clap::{Command, FromArgMatches}; use std::sync::{Arc, Mutex}; use std::time::Duration; use log::{info, warn}; -use tokio::{count, join, select, spawn}; +use tokio::{join, select, spawn}; use tokio::signal::ctrl_c; use tokio::time::sleep; use crate::service::service_runner::NoGamepadsService; diff --git a/export/src/bin/export_project.rs b/export/src/bin/export_project.rs index 6c6eaaf..b83e54b 100644 --- a/export/src/bin/export_project.rs +++ b/export/src/bin/export_project.rs @@ -29,7 +29,7 @@ pub fn main() { let version = if let Some(v) = args.get(1) { v.to_string() } else { env!("PROJECT_VERSION").to_string() }; let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).parent().unwrap().to_path_buf(); - let toml_config = root.join("../../../Project_Export.toml"); + let toml_config = root.join("./Project_Export.toml"); let config: Config = toml::from_str(fs::read_to_string(toml_config).unwrap().as_str()) .expect("Failed to parse TOML"); @@ -48,14 +48,14 @@ pub fn main() { let _ = remove_dir_all(&export_version_dir); for data in config.release.root { - println!("Releasing \"{}\" files", data.0); + println!("Releasing \"{}\"", data.0); let raw_path = root.join(data.1.raw); let target_path = export_version_dir.join(data.1.target); copy_files(&raw_path, &target_path, data.1.files); } for data in config.release.deps { - println!("Releasing \"{}\" files", data.0); + println!("Releasing \"{}\"", data.0); let raw_path = target_dir.join(data.1.raw); let target_path = export_version_dir.join(data.1.target); copy_files(&raw_path, &target_path, data.1.files); |
