diff options
| author | Matthew Collins <[email protected]> | 2017-09-06 21:00:38 +0100 |
|---|---|---|
| committer | Matthew Collins <[email protected]> | 2017-09-06 21:00:38 +0100 |
| commit | 56d42212176597350764664ea7afe9c980c44064 (patch) | |
| tree | 372cff43e97c18f5f361669f696f6192308881e4 /src | |
| parent | Handle the fact windows 64 bit uses a different library name than other platf... (diff) | |
| download | steamworks-rs-56d42212176597350764664ea7afe9c980c44064.tar.xz steamworks-rs-56d42212176597350764664ea7afe9c980c44064.zip | |
Initial steam callbacks work
The callback system requires the use of C++ classes. I've ended
up linking a static lib that forwards a rust closure to a C++
class.
Diffstat (limited to 'src')
| -rw-r--r-- | src/friends.rs | 29 | ||||
| -rw-r--r-- | src/lib.rs | 68 |
2 files changed, 97 insertions, 0 deletions
diff --git a/src/friends.rs b/src/friends.rs index b2e6bf8..318af69 100644 --- a/src/friends.rs +++ b/src/friends.rs @@ -44,6 +44,35 @@ impl Friends { friends } } + + pub fn request_user_information(&self, user: SteamId, name_only: bool) { + unsafe { + println!("rui: {}", sys::SteamAPI_ISteamFriends_RequestUserInformation(self.friends, user.0, name_only as u8)); + } + } +} + +#[derive(Debug)] +pub struct PersonaStateChange { + pub steam_id: SteamId, + pub flags: i32, // TODO: +} + +unsafe impl Callback for PersonaStateChange { + fn id() -> i32 { + 304 + } + fn size() -> i32 { + ::std::mem::size_of::<sys::PersonaStateChange_t>() as i32 + } + + unsafe fn from_raw(raw: *mut libc::c_void) -> Self { + let val = &mut *(raw as *mut sys::PersonaStateChange_t); + PersonaStateChange { + steam_id: SteamId(val.steam_id), + flags: val.flags as i32, + } + } } pub struct Friend { @@ -1,4 +1,5 @@ +extern crate libc; extern crate steamworks_sys as sys; #[macro_use] extern crate error_chain; @@ -17,6 +18,7 @@ mod friends; pub use friends::*; use std::rc::Rc; +use std::cell::RefCell; use std::ffi::CStr; use std::borrow::Cow; use std::fmt::{ @@ -30,6 +32,8 @@ pub struct Client { struct ClientInner { client: *mut sys::ISteamClient, pipe: sys::HSteamPipe, + + callbacks: RefCell<Vec<*mut libc::c_void>>, } impl Client { @@ -42,6 +46,7 @@ impl Client { let client = Rc::new(ClientInner { client: client, pipe: sys::SteamAPI_ISteamClient_CreateSteamPipe(client), + callbacks: RefCell::new(Vec::new()), }); Ok(Client { inner: client, @@ -49,6 +54,49 @@ impl Client { } } + pub fn run_callbacks(&self) { + unsafe { + sys::SteamAPI_RunCallbacks(); + } + } + + pub fn register_callback<C, F>(&self, f: F) + where C: Callback, + F: FnMut(C) + 'static + { + unsafe { + let userdata = Box::into_raw(Box::new(f)); + + extern "C" fn run_func<C, F>(userdata: *mut libc::c_void, param: *mut libc::c_void) + where C: Callback, + F: FnMut(C) + 'static + { + unsafe { + let func: &mut F = &mut *(userdata as *mut F); + let param = C::from_raw(param); + func(param); + } + } + extern "C" fn dealloc<C, F>(userdata: *mut libc::c_void) + where C: Callback, + F: FnMut(C) + 'static + { + let func: Box<F> = unsafe { Box::from_raw(userdata as _) }; + drop(func); + } + + let ptr = sys::register_rust_steam_callback( + C::size() as _, + userdata as _, + run_func::<C, F>, + dealloc::<C, F>, + C::id() as _ + ); + let mut cbs = self.inner.callbacks.borrow_mut(); + cbs.push(ptr); + } + } + pub fn utils(&self) -> Utils { unsafe { let utils = sys::SteamAPI_ISteamClient_GetISteamUtils( @@ -98,6 +146,9 @@ impl Client { impl Drop for ClientInner { fn drop(&mut self) { unsafe { + for cb in &**self.callbacks.borrow() { + sys::unregister_rust_steam_callback(*cb); + } debug_assert!(sys::SteamAPI_ISteamClient_BReleaseSteamPipe(self.client, self.pipe) != 0); sys::SteamAPI_Shutdown(); } @@ -107,6 +158,12 @@ impl Drop for ClientInner { #[derive(Clone, Copy, Debug)] pub struct SteamId(pub(crate) u64); +pub unsafe trait Callback { + fn id() -> i32; + fn size() -> i32; + unsafe fn from_raw(raw: *mut libc::c_void) -> Self; +} + #[cfg(test)] mod tests { use super::*; @@ -114,6 +171,10 @@ mod tests { fn basic_test() { let client = Client::init().unwrap(); + client.register_callback(|p: PersonaStateChange| { + println!("Got callback: {:?}", p); + }); + let utils = client.utils(); println!("Utils:"); println!("AppId: {:?}", utils.app_id()); @@ -135,6 +196,13 @@ mod tests { println!("{:?}", list); for f in &list { println!("Friend: {:?} - {}({:?})", f.id(), f.name(), f.state()); + friends.request_user_information(f.id(), true); + } + friends.request_user_information(SteamId(76561198174976054), true); + + for _ in 0 .. 50 { + client.run_callbacks(); + ::std::thread::sleep_ms(100); } } } |