aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Collins <[email protected]>2018-05-05 17:07:07 +0100
committerMatthew Collins <[email protected]>2018-05-05 17:07:07 +0100
commitf3accef78c9de43727d7eae93f190952e486a7c8 (patch)
tree677a7d0cffe960fa159871485a759f230fcff44b
parentRework how the sys crate is generated (diff)
downloadsteamworks-rs-f3accef78c9de43727d7eae93f190952e486a7c8.tar.xz
steamworks-rs-f3accef78c9de43727d7eae93f190952e486a7c8.zip
Only allow run_callbacks to be run on a single thread at any time
-rw-r--r--src/callback.rs18
-rw-r--r--src/lib.rs50
-rw-r--r--src/matchmaking.rs8
-rw-r--r--src/server.rs35
-rw-r--r--src/user.rs6
-rw-r--r--steamworks-sys/build.rs2
6 files changed, 73 insertions, 46 deletions
diff --git a/src/callback.rs b/src/callback.rs
index 6808a45..18c1db0 100644
--- a/src/callback.rs
+++ b/src/callback.rs
@@ -27,11 +27,11 @@ fn print_err(err: Box<Any>) {
pub(crate) unsafe fn register_callback<C, F, Manager>(inner: &Arc<Inner<Manager>>, f: F, game_server: bool)
where C: Callback,
- F: FnMut(C) + Send + Sync + 'static
+ F: FnMut(C) + Send + 'static
{
unsafe extern "C" fn run<C, F>(_: *mut c_void, userdata: *mut c_void, param: *mut c_void)
where C: Callback,
- F: FnMut(C) + Send + Sync + 'static
+ F: FnMut(C) + Send + 'static
{
let func: &mut F = &mut *(userdata as *mut F);
let param = C::from_raw(param);
@@ -40,14 +40,14 @@ pub(crate) unsafe fn register_callback<C, F, Manager>(inner: &Arc<Inner<Manager>
unsafe extern "C" fn run_extra<C, F>(cb: *mut c_void, userdata: *mut c_void, param: *mut c_void, _: u8, _: sys::SteamAPICall)
where C: Callback,
- F: FnMut(C) + Send + Sync + 'static
+ F: FnMut(C) + Send + 'static
{
run::<C, F>(cb, userdata, param);
}
unsafe extern "C" fn dealloc<C, F>(cb: *mut c_void, userdata: *mut c_void)
where C: Callback,
- F: FnMut(C) + Send + Sync + 'static
+ F: FnMut(C) + Send + 'static
{
sys::SteamAPI_UnregisterCallback(cb);
@@ -73,7 +73,7 @@ pub(crate) unsafe fn register_callback<C, F, Manager>(inner: &Arc<Inner<Manager>
}
pub(crate) unsafe fn register_call_result<C, F, Manager>(inner: &Arc<Inner<Manager>>, api_call: sys::SteamAPICall, callback_id: i32, f: F)
- where F: for <'a> FnMut(&'a C, bool) + 'static + Send + Sync
+ where F: for <'a> FnMut(&'a C, bool) + 'static + Send
{
struct CallData<F, Manager> {
func: F,
@@ -82,7 +82,7 @@ pub(crate) unsafe fn register_call_result<C, F, Manager>(inner: &Arc<Inner<Manag
}
unsafe extern "C" fn run<C, F, Manager>(cb: *mut c_void, userdata: *mut c_void, param: *mut c_void)
- where F: for<'a> FnMut(&'a C, bool) + Send + Sync + 'static
+ where F: for<'a> FnMut(&'a C, bool) + Send + 'static
{
let data: &mut CallData<F, Manager> = &mut *(userdata as *mut CallData<F, Manager>);
#[cfg(debug_assertions)]
@@ -105,7 +105,7 @@ pub(crate) unsafe fn register_call_result<C, F, Manager>(inner: &Arc<Inner<Manag
}
unsafe extern "C" fn run_extra<C, F, Manager>(cb: *mut c_void, userdata: *mut c_void, param: *mut c_void, io_error: u8, api_call: sys::SteamAPICall)
- where F: for<'a> FnMut(&'a C, bool) + Send + Sync + 'static
+ where F: for<'a> FnMut(&'a C, bool) + Send + 'static
{
let data: &mut CallData<F, Manager> = &mut *(userdata as *mut CallData<F, Manager>);
@@ -129,8 +129,8 @@ pub(crate) unsafe fn register_call_result<C, F, Manager>(inner: &Arc<Inner<Manag
}
}
- unsafe extern "C" fn dealloc<C, F, Manager>(cb: *mut c_void, userdata: *mut c_void)
- where F: for <'a> FnMut(&'a C, bool) + Send + Sync + 'static
+ unsafe extern "C" fn dealloc<C, F, Manager>(_cb: *mut c_void, userdata: *mut c_void)
+ where F: for <'a> FnMut(&'a C, bool) + Send + 'static
{
let data: Box<CallData<F, Manager>> = Box::from_raw(userdata as _);
diff --git a/src/lib.rs b/src/lib.rs
index 26662e7..5884eb4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -29,6 +29,7 @@ use std::ffi::{CString, CStr};
use std::fmt::{
Debug, Formatter, self
};
+use std::marker::PhantomData;
use std::collections::HashMap;
pub type SResult<T> = Result<T, SteamError>;
@@ -57,6 +58,13 @@ impl <Manager> Clone for Client<Manager> {
}
}
+/// Allows access parts of the steam api that can only be called
+/// on a single thread at any given time.
+pub struct SingleClient<Manager = ClientManager> {
+ _inner: Arc<Inner<Manager>>,
+ _not_sync: PhantomData<*mut ()>,
+}
+
struct Inner<Manager> {
_manager: Manager,
callbacks: Mutex<Callbacks>,
@@ -71,6 +79,7 @@ unsafe impl <Manager: Send + Sync> Send for Inner<Manager> {}
unsafe impl <Manager: Send + Sync> Sync for Inner<Manager> {}
unsafe impl <Manager: Send + Sync> Send for Client<Manager> {}
unsafe impl <Manager: Send + Sync> Sync for Client<Manager> {}
+unsafe impl <Manager: Send + Sync> Send for SingleClient<Manager> {}
/// Returns true if the app wasn't launched through steam and
/// begins relaunching it, the app should exit as soon as possible.
@@ -83,6 +92,9 @@ pub fn restart_app_if_necessary(app_id: AppId) -> bool {
}
}
+fn static_assert_send<T: Send>() {}
+fn static_assert_sync<T>() where T: Sync {}
+
impl Client<ClientManager> {
/// Attempts to initialize the steamworks api and returns
/// a client to access the rest of the api.
@@ -101,7 +113,10 @@ impl Client<ClientManager> {
/// * The game isn't running on the same user/level as the steam client
/// * The user doesn't own a license for the game.
/// * The app ID isn't completely set up.
- pub fn init() -> SResult<Client<ClientManager>> {
+ pub fn init() -> SResult<(Client<ClientManager>, SingleClient<ClientManager>)> {
+ static_assert_send::<Client<ClientManager>>();
+ static_assert_sync::<Client<ClientManager>>();
+ static_assert_send::<SingleClient<ClientManager>>();
unsafe {
if sys::SteamAPI_Init() == 0 {
return Err(SteamError::InitFailed);
@@ -114,15 +129,17 @@ impl Client<ClientManager> {
call_results: HashMap::new(),
}),
});
- Ok(Client {
- inner: client,
+ Ok((Client {
+ inner: client.clone(),
client: raw_client,
- })
+ }, SingleClient {
+ _inner: client,
+ _not_sync: PhantomData,
+ }))
}
}
}
-
-impl <Manager> Client<Manager> {
+impl <M> SingleClient<M> where M: Manager{
/// Runs any currently pending callbacks
///
/// This runs all currently pending callbacks on the current
@@ -132,10 +149,12 @@ impl <Manager> Client<Manager> {
/// in order to reduce the latency between recieving events.
pub fn run_callbacks(&self) {
unsafe {
- sys::SteamAPI_RunCallbacks();
+ M::run_callbacks();
}
}
+}
+impl <Manager> Client<Manager> {
/// Registers the passed function as a callback for the
/// given type.
///
@@ -143,7 +162,7 @@ impl <Manager> Client<Manager> {
/// is called when the event arrives.
pub fn register_callback<C, F>(&self, f: F)
where C: Callback,
- F: FnMut(C) + 'static + Send + Sync
+ F: FnMut(C) + 'static + Send
{
unsafe {
register_callback(&self.inner, f, false);
@@ -229,11 +248,22 @@ impl <Manager> Drop for Inner<Manager> {
}
}
+/// Used to seperate client and game server modes
+pub unsafe trait Manager {
+ unsafe fn run_callbacks();
+}
+
/// Manages keeping the steam api active for clients
pub struct ClientManager {
_priv: (),
}
+unsafe impl Manager for ClientManager {
+ unsafe fn run_callbacks() {
+ sys::SteamAPI_RunCallbacks();
+ }
+}
+
impl Drop for ClientManager {
fn drop(&mut self) {
unsafe {
@@ -269,7 +299,7 @@ mod tests {
use super::*;
#[test]
fn basic_test() {
- let client = Client::init().unwrap();
+ let (client, single) = Client::init().unwrap();
client.register_callback(|p: PersonaStateChange| {
println!("Got callback: {:?}", p);
@@ -301,7 +331,7 @@ mod tests {
friends.request_user_information(SteamId(76561198174976054), true);
for _ in 0 .. 50 {
- client.run_callbacks();
+ single.run_callbacks();
::std::thread::sleep(::std::time::Duration::from_millis(100));
}
}
diff --git a/src/matchmaking.rs b/src/matchmaking.rs
index 177cb8e..f219381 100644
--- a/src/matchmaking.rs
+++ b/src/matchmaking.rs
@@ -54,7 +54,7 @@ impl <Manager> Matchmaking<Manager> {
/// * `LobbyEnter`
/// * `LobbyCreated`
pub fn create_lobby<F>(&self, ty: LobbyType, max_members: u32, mut cb: F)
- where F: FnMut(Result<LobbyId, SteamError>) + 'static + Send + Sync
+ where F: FnMut(Result<LobbyId, SteamError>) + 'static + Send
{
assert!(max_members <= 250); // Steam API limits
unsafe {
@@ -81,7 +81,7 @@ impl <Manager> Matchmaking<Manager> {
/// Tries to join the lobby with the given ID
pub fn join_lobby<F>(&self, lobby: LobbyId, mut cb: F)
- where F: FnMut(Result<LobbyId, ()>) + 'static + Send + Sync
+ where F: FnMut(Result<LobbyId, ()>) + 'static + Send
{
unsafe {
let api_call = sys::SteamAPI_ISteamMatchmaking_JoinLobby(self.mm, lobby.0);
@@ -109,7 +109,7 @@ impl <Manager> Matchmaking<Manager> {
#[test]
fn test_lobby() {
- let client = Client::init().unwrap();
+ let (client, single) = Client::init().unwrap();
let mm = client.matchmaking();
mm.request_lobby_list(|v| {
@@ -120,7 +120,7 @@ fn test_lobby() {
});
for _ in 0 .. 100 {
- client.run_callbacks();
+ single.run_callbacks();
::std::thread::sleep(::std::time::Duration::from_millis(100));
}
} \ No newline at end of file
diff --git a/src/server.rs b/src/server.rs
index fc1f6e8..ee67742 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -57,7 +57,7 @@ impl Server {
ip: Ipv4Addr, steam_port: u16,
game_port: u16, query_port: u16,
server_mode: ServerMode, version: &str,
- ) -> SResult<Server> {
+ ) -> SResult<(Server, SingleClient<ServerManager>)> {
unsafe {
let version = CString::new(version).unwrap();
let raw_ip: u32 = ip.into();
@@ -82,22 +82,13 @@ impl Server {
call_results: HashMap::new(),
}),
});
- Ok(Server {
- inner: server,
+ Ok((Server {
+ inner: server.clone(),
server: server_raw,
- })
- }
- }
- /// Runs any currently pending callbacks
- ///
- /// This runs all currently pending callbacks on the current
- /// thread.
- ///
- /// This should be called frequently (e.g. once per a frame)
- /// in order to reduce the latency between recieving events.
- pub fn run_callbacks(&self) {
- unsafe {
- sys::SteamGameServer_RunCallbacks();
+ }, SingleClient {
+ _inner: server,
+ _not_sync: PhantomData,
+ }))
}
}
@@ -245,7 +236,7 @@ impl Server {
#[test]
fn test() {
- let server = Server::init(
+ let (server, single) = Server::init(
[127, 0, 0, 1].into(),
23333, 23334, 23335,
ServerMode::Authentication, "0.0.1"
@@ -269,7 +260,7 @@ fn test() {
println!("{:?}", server.begin_authentication_session(id, &ticket));
for _ in 0 .. 20 {
- server.run_callbacks();
+ single.run_callbacks();
::std::thread::sleep(::std::time::Duration::from_millis(50));
}
@@ -278,7 +269,7 @@ fn test() {
server.cancel_authentication_ticket(auth);
for _ in 0 .. 20 {
- server.run_callbacks();
+ single.run_callbacks();
::std::thread::sleep(::std::time::Duration::from_millis(50));
}
@@ -291,6 +282,12 @@ pub struct ServerManager {
_priv: (),
}
+unsafe impl Manager for ServerManager {
+ unsafe fn run_callbacks() {
+ sys::SteamGameServer_RunCallbacks();
+ }
+}
+
impl Drop for ServerManager {
fn drop(&mut self) {
unsafe {
diff --git a/src/user.rs b/src/user.rs
index b21ac5f..8298656 100644
--- a/src/user.rs
+++ b/src/user.rs
@@ -108,7 +108,7 @@ pub enum AuthSessionError {
#[test]
fn test() {
- let client = Client::init().unwrap();
+ let (client, single) = Client::init().unwrap();
let user = client.user();
client.register_callback(|v: AuthSessionTicketResponse| println!("{:?}", v));
@@ -120,7 +120,7 @@ fn test() {
println!("{:?}", user.begin_authentication_session(id, &ticket));
for _ in 0 .. 20 {
- client.run_callbacks();
+ single.run_callbacks();
::std::thread::sleep(::std::time::Duration::from_millis(50));
}
@@ -129,7 +129,7 @@ fn test() {
user.cancel_authentication_ticket(auth);
for _ in 0 .. 20 {
- client.run_callbacks();
+ single.run_callbacks();
::std::thread::sleep(::std::time::Duration::from_millis(50));
}
diff --git a/steamworks-sys/build.rs b/steamworks-sys/build.rs
index 2aa6c42..dde20e3 100644
--- a/steamworks-sys/build.rs
+++ b/steamworks-sys/build.rs
@@ -129,7 +129,7 @@ extern "C" {
(fty, fty_rust)
}
- for SteamStruct{struct_: ref ty, ref fields} in &steam_api.structs {
+ for &SteamStruct{struct_: ref ty, ref fields} in &steam_api.structs {
if ty.contains("::") || !ty.ends_with("_t") || fields.iter().any(|v| v.fieldtype.contains('['))
|| ty.chars().next().map_or(true, |v| v.is_lowercase())
|| ty.starts_with("GSStats")