aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthew Collins <[email protected]>2017-09-06 21:00:38 +0100
committerMatthew Collins <[email protected]>2017-09-06 21:00:38 +0100
commit56d42212176597350764664ea7afe9c980c44064 (patch)
tree372cff43e97c18f5f361669f696f6192308881e4 /src
parentHandle the fact windows 64 bit uses a different library name than other platf... (diff)
downloadsteamworks-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.rs29
-rw-r--r--src/lib.rs68
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 {
diff --git a/src/lib.rs b/src/lib.rs
index 73b9c61..40c965b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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);
}
}
}