diff options
| author | Matthew Collins <[email protected]> | 2017-09-06 15:51:08 +0100 |
|---|---|---|
| committer | Matthew Collins <[email protected]> | 2017-09-06 15:51:08 +0100 |
| commit | d1be508a5fbee5535593ca246de389f40f1f7b34 (patch) | |
| tree | 70c3235f9db852097b6ec50b7d532342e8d30287 /src | |
| download | archived-steamworks-rs-d1be508a5fbee5535593ca246de389f40f1f7b34.tar.xz archived-steamworks-rs-d1be508a5fbee5535593ca246de389f40f1f7b34.zip | |
Initial commit
Diffstat (limited to 'src')
| -rw-r--r-- | src/app.rs | 112 | ||||
| -rw-r--r-- | src/error.rs | 17 | ||||
| -rw-r--r-- | src/friends.rs | 100 | ||||
| -rw-r--r-- | src/lib.rs | 140 | ||||
| -rw-r--r-- | src/utils.rs | 23 |
5 files changed, 392 insertions, 0 deletions
diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 0000000..2ba0b44 --- /dev/null +++ b/src/app.rs @@ -0,0 +1,112 @@ +use super::*; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct AppId(pub u32); + +pub struct Apps { + pub(crate) apps: *mut sys::ISteamApps, + pub(crate) _client: Rc<ClientInner>, +} + +impl Apps { + + pub fn is_app_installed(&self, app_id: AppId) -> bool { + unsafe { + sys::SteamAPI_ISteamApps_BIsAppInstalled(self.apps, app_id.0) != 0 + } + } + + pub fn is_dlc_installed(&self, app_id: AppId) -> bool { + unsafe { + sys::SteamAPI_ISteamApps_BIsDlcInstalled(self.apps, app_id.0) != 0 + } + } + + pub fn is_subscribed_app(&self, app_id: AppId) -> bool { + unsafe { + sys::SteamAPI_ISteamApps_BIsSubscribedApp(self.apps, app_id.0) != 0 + } + } + + pub fn is_subscribed_from_free_weekend(&self) -> bool { + unsafe { + sys::SteamAPI_ISteamApps_BIsSubscribedFromFreeWeekend(self.apps) != 0 + } + } + + pub fn is_vac_banned(&self) -> bool { + unsafe { + sys::SteamAPI_ISteamApps_BIsVACBanned(self.apps) != 0 + } + } + + pub fn is_cybercafe(&self) -> bool { + unsafe { + sys::SteamAPI_ISteamApps_BIsCybercafe(self.apps) != 0 + } + } + + pub fn is_low_violence(&self) -> bool { + unsafe { + sys::SteamAPI_ISteamApps_BIsLowViolence(self.apps) != 0 + } + } + + pub fn is_subscribed(&self) -> bool { + unsafe { + sys::SteamAPI_ISteamApps_BIsSubscribed(self.apps) != 0 + } + } + + pub fn app_build_id(&self) -> i32 { + unsafe { + sys::SteamAPI_ISteamApps_GetAppBuildId(self.apps) as i32 + } + } + + pub fn app_install_dir(&self, app_id: AppId) -> String { + unsafe { + let buffer = vec![0; 2048]; + sys::SteamAPI_ISteamApps_GetAppInstallDir(self.apps, app_id.0, buffer.as_ptr(), buffer.len() as u32); + let path = CStr::from_ptr(buffer.as_ptr()); + path.to_string_lossy().into_owned() + } + } + + pub fn app_owner(&self) -> SteamId { + unsafe { + SteamId(sys::SteamAPI_ISteamApps_GetAppOwner(self.apps)) + } + } + + pub fn available_game_languages(&self) -> Vec<String> { + unsafe { + let langs = sys::SteamAPI_ISteamApps_GetAvailableGameLanguages(self.apps); + let langs = CStr::from_ptr(langs); + let langs = langs.to_string_lossy(); + langs.split(',') + .map(|v| v.to_owned()) + .collect() + } + } + + pub fn current_game_language(&self) -> Cow<str> { + unsafe { + let lang = sys::SteamAPI_ISteamApps_GetCurrentGameLanguage(self.apps); + let lang = CStr::from_ptr(lang); + lang.to_string_lossy() + } + } + + pub fn current_beta_name(&self) -> Option<String> { + unsafe { + let buffer = vec![0; 256]; + if sys::SteamAPI_ISteamApps_GetCurrentBetaName(self.apps, buffer.as_ptr(), buffer.len() as _) != 0 { + let path = CStr::from_ptr(buffer.as_ptr()); + Some(path.to_string_lossy().into_owned()) + } else { + None + } + } + } +}
\ No newline at end of file diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..6ac1914 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,17 @@ + +error_chain! { + types { + Error, ErrorKind, ResultExt, Result; + } + links { + } + + foreign_links { + } + + errors { + InitFailed { + description("failed to init the steamworks API"), + } + } +} diff --git a/src/friends.rs b/src/friends.rs new file mode 100644 index 0000000..b2e6bf8 --- /dev/null +++ b/src/friends.rs @@ -0,0 +1,100 @@ + +use super::*; + +bitflags! { + #[repr(C)] + pub struct FriendFlags: u16 { + const FRIEND_FLAG_NONE = 0x0000; + const FRIEND_FLAG_BLOCKED = 0x0001; + const FRIEND_FLAG_FRIENDSHIP_REQUESTED = 0x0002; + const FRIEND_FLAG_IMMEDIATE = 0x0004; + const FRIEND_FLAG_CLAN_MEMBER = 0x0008; + const FRIEND_FLAG_ON_GAME_SERVER = 0x0010; + // Unused + // Unused + const FRIEND_FLAG_REQUESTING_FRIENDSHIP = 0x0080; + const FRIEND_FLAG_REQUESTING_INFO = 0x0100; + const FRIEND_FLAG_IGNORED = 0x0200; + const FRIEND_FLAG_IGNORED_FRIEND = 0x0400; + // Unused + const FRIEND_FLAG_CHAT_MEMBER = 0x1000; + const FRIEND_FLAG_ALL = 0xFFFF; + } +} + +pub struct Friends { + pub(crate) friends: *mut sys::ISteamFriends, + pub(crate) _client: Rc<ClientInner>, +} + +impl Friends { + pub fn get_friends(&self, flags: FriendFlags) -> Vec<Friend> { + unsafe { + let count = sys::SteamAPI_ISteamFriends_GetFriendCount(self.friends, flags.bits() as _); + let mut friends = Vec::with_capacity(count as usize); + for idx in 0 .. count { + let friend = SteamId(sys::SteamAPI_ISteamFriends_GetFriendByIndex(self.friends, idx, flags.bits() as _)); + friends.push(Friend { + id: friend, + friends: self.friends, + _client: self._client.clone(), + }); + } + + friends + } + } +} + +pub struct Friend { + id: SteamId, + friends: *mut sys::ISteamFriends, + _client: Rc<ClientInner>, +} + +impl Debug for Friend { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "Friend({:?})", self.id) + } +} + +impl Friend { + pub fn id(&self) -> SteamId { + self.id + } + + pub fn name(&self) -> Cow<str> { + unsafe { + let name = sys::SteamAPI_ISteamFriends_GetFriendPersonaName(self.friends, self.id.0); + let name = CStr::from_ptr(name); + name.to_string_lossy() + } + } + + pub fn state(&self) -> FriendState { + unsafe { + let state = sys::SteamAPI_ISteamFriends_GetFriendPersonaState(self.friends, self.id.0); + match state { + sys::PersonaState::Offline => FriendState::Offline, + sys::PersonaState::Online => FriendState::Online, + sys::PersonaState::Busy => FriendState::Busy, + sys::PersonaState::Away => FriendState::Away, + sys::PersonaState::Snooze => FriendState::Snooze, + sys::PersonaState::LookingToPlay => FriendState::LookingToPlay, + sys::PersonaState::LookingToTrade => FriendState::LookingToTrade, + sys::PersonaState::Max => unreachable!(), + } + } + } +} + +#[derive(Clone, Copy, Debug)] +pub enum FriendState { + Offline, + Online, + Busy, + Away, + Snooze, + LookingToTrade, + LookingToPlay, +}
\ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..73b9c61 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,140 @@ + +extern crate steamworks_sys as sys; +#[macro_use] +extern crate error_chain; +#[macro_use] +extern crate bitflags; + +pub mod error; +pub use error::Result as SResult; +use error::ErrorKind; + +mod utils; +pub use utils::*; +mod app; +pub use app::*; +mod friends; +pub use friends::*; + +use std::rc::Rc; +use std::ffi::CStr; +use std::borrow::Cow; +use std::fmt::{ + Debug, Formatter, self +}; + +pub struct Client { + inner: Rc<ClientInner>, +} + +struct ClientInner { + client: *mut sys::ISteamClient, + pipe: sys::HSteamPipe, +} + +impl Client { + pub fn init() -> SResult<Client> { + unsafe { + if sys::SteamAPI_Init() == 0 { + bail!(ErrorKind::InitFailed); + } + let client = sys::SteamInternal_CreateInterface(sys::STEAMCLIENT_INTERFACE_VERSION.as_ptr() as *const _); + let client = Rc::new(ClientInner { + client: client, + pipe: sys::SteamAPI_ISteamClient_CreateSteamPipe(client), + }); + Ok(Client { + inner: client, + }) + } + } + + pub fn utils(&self) -> Utils { + unsafe { + let utils = sys::SteamAPI_ISteamClient_GetISteamUtils( + self.inner.client, self.inner.pipe, + sys::STEAMUTILS_INTERFACE_VERSION.as_ptr() as *const _ + ); + assert!(!utils.is_null()); + Utils { + utils: utils, + _client: self.inner.clone(), + } + } + } + + pub fn apps(&self) -> Apps { + unsafe { + let user = sys::SteamAPI_ISteamClient_ConnectToGlobalUser(self.inner.client, self.inner.pipe); + let apps = sys::SteamAPI_ISteamClient_GetISteamApps( + self.inner.client, user, self.inner.pipe, + sys::STEAMAPPS_INTERFACE_VERSION.as_ptr() as *const _ + ); + assert!(!apps.is_null()); + Apps { + apps: apps, + _client: self.inner.clone(), + } + } + } + + pub fn friends(&self) -> Friends { + unsafe { + let user = sys::SteamAPI_ISteamClient_ConnectToGlobalUser(self.inner.client, self.inner.pipe); + let friends = sys::SteamAPI_ISteamClient_GetISteamFriends( + self.inner.client, user, self.inner.pipe, + sys::STEAMFRIENDS_INTERFACE_VERSION.as_ptr() as *const _ + ); + assert!(!friends.is_null()); + Friends { + friends: friends, + _client: self.inner.clone(), + } + } + + } +} + +impl Drop for ClientInner { + fn drop(&mut self) { + unsafe { + debug_assert!(sys::SteamAPI_ISteamClient_BReleaseSteamPipe(self.client, self.pipe) != 0); + sys::SteamAPI_Shutdown(); + } + } +} + +#[derive(Clone, Copy, Debug)] +pub struct SteamId(pub(crate) u64); + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn basic_test() { + let client = Client::init().unwrap(); + + let utils = client.utils(); + println!("Utils:"); + println!("AppId: {:?}", utils.app_id()); + println!("UI Language: {}", utils.ui_language()); + + let apps = client.apps(); + println!("Apps"); + println!("IsInstalled(480): {}", apps.is_app_installed(AppId(480))); + println!("InstallDir(480): {}", apps.app_install_dir(AppId(480))); + println!("BuildId: {}", apps.app_build_id()); + println!("AppOwner: {:?}", apps.app_owner()); + println!("Langs: {:?}", apps.available_game_languages()); + println!("Lang: {}", apps.current_game_language()); + println!("Beta: {:?}", apps.current_beta_name()); + + let friends = client.friends(); + println!("Friends"); + let list = friends.get_friends(FRIEND_FLAG_IMMEDIATE); + println!("{:?}", list); + for f in &list { + println!("Friend: {:?} - {}({:?})", f.id(), f.name(), f.state()); + } + } +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..416b9ee --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,23 @@ + +use super::*; + +pub struct Utils { + pub(crate) utils: *mut sys::ISteamUtils, + pub(crate) _client: Rc<ClientInner>, +} + +impl Utils { + pub fn app_id(&self) -> AppId { + unsafe { + AppId(sys::SteamAPI_ISteamUtils_GetAppID(self.utils)) + } + } + + pub fn ui_language(&self) -> Cow<str> { + unsafe { + let lang = sys::SteamAPI_ISteamUtils_GetSteamUILanguage(self.utils); + let lang = CStr::from_ptr(lang); + lang.to_string_lossy() + } + } +}
\ No newline at end of file |