From 1052c46f2c492844a313a0750eb485e2050a0bb3 Mon Sep 17 00:00:00 2001 From: ldubos Date: Thu, 5 Sep 2024 13:34:05 +0200 Subject: [PATCH 1/2] add timeline api --- src/lib.rs | 16 ++++++ src/timeline.rs | 141 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 src/timeline.rs diff --git a/src/lib.rs b/src/lib.rs index 554db64..a10b2cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,7 @@ pub use steamworks_sys as sys; #[cfg(not(feature = "raw-bindings"))] use steamworks_sys as sys; use sys::{EServerMode, ESteamAPIInitResult, SteamErrMsg}; +use timeline::Timeline; use core::ffi::c_void; use std::collections::HashMap; @@ -33,6 +34,7 @@ pub use crate::networking::*; pub use crate::remote_play::*; pub use crate::remote_storage::*; pub use crate::server::*; +pub use crate::timeline::*; pub use crate::ugc::*; pub use crate::user::*; pub use crate::user_stats::*; @@ -55,6 +57,7 @@ mod remote_play; mod remote_storage; pub mod screenshots; mod server; +pub mod timeline; mod ugc; mod user; mod user_stats; @@ -426,6 +429,19 @@ where } } + /// Returns an accessor to the steam timeline interface + pub fn timeline(&self) -> Timeline { + unsafe { + let timeline = sys::SteamAPI_SteamTimeline_v001(); + + Timeline { + timeline, + disabled: timeline.is_null(), + _inner: self.inner.clone(), + } + } + } + pub fn networking_messages(&self) -> networking_messages::NetworkingMessages { unsafe { let net = sys::SteamAPI_SteamNetworkingMessages_SteamAPI_v002(); diff --git a/src/timeline.rs b/src/timeline.rs new file mode 100644 index 0000000..391270d --- /dev/null +++ b/src/timeline.rs @@ -0,0 +1,141 @@ +use super::*; +use std::time::Duration; + +pub struct Timeline { + pub(crate) timeline: *mut sys::ISteamTimeline, + /// Whether the client's steam API is not recent enough. + pub(crate) disabled: bool, + pub(crate) _inner: Arc>, +} + +pub enum TimelineGameMode { + /// The player is fully loaded into the game and playing. + Playing, + /// The player is in a multiplayer lobby. + Staging, + /// The player is in the game's main menu or a pause menu. + Menus, + /// The player is waiting for a loading screen. + LoadingScreen, +} + +impl From for sys::ETimelineGameMode { + fn from(mode: TimelineGameMode) -> Self { + match mode { + TimelineGameMode::Playing => sys::ETimelineGameMode::k_ETimelineGameMode_Playing, + TimelineGameMode::Staging => sys::ETimelineGameMode::k_ETimelineGameMode_Staging, + TimelineGameMode::Menus => sys::ETimelineGameMode::k_ETimelineGameMode_Menus, + TimelineGameMode::LoadingScreen => { + sys::ETimelineGameMode::k_ETimelineGameMode_LoadingScreen + } + } + } +} + +pub enum TimelineEventClipPriority { + /// This event is not appropriate as a clip. + None, + /// The user may want to make a clip around this event. + Standard, + /// The player will be likely to want a clip around event, + /// and those clips should be promoted more prominently than clips with the [TimelineEventClipPriority::Standard] priority. + Featured, +} + +impl From for sys::ETimelineEventClipPriority { + fn from(priority: TimelineEventClipPriority) -> Self { + match priority { + TimelineEventClipPriority::None => { + sys::ETimelineEventClipPriority::k_ETimelineEventClipPriority_None + } + TimelineEventClipPriority::Standard => { + sys::ETimelineEventClipPriority::k_ETimelineEventClipPriority_Standard + } + TimelineEventClipPriority::Featured => { + sys::ETimelineEventClipPriority::k_ETimelineEventClipPriority_Featured + } + } + } +} + +impl Timeline { + /// Changes the color of the timeline bar. + pub fn set_timeline_game_mode(&self, mode: TimelineGameMode) { + if self.disabled { + return; + } + + unsafe { + sys::SteamAPI_ISteamTimeline_SetTimelineGameMode(self.timeline, mode.into()); + } + } + + /// Sets a description for the current game state in the timeline. + /// These help the user to find specific moments in the timeline when saving clips. + /// Setting a new state description replaces any previous description. + pub fn set_timeline_state_description(&self, description: &str, duration: Duration) { + if self.disabled { + return; + } + + let description = CString::new(description).unwrap(); + + unsafe { + sys::SteamAPI_ISteamTimeline_SetTimelineStateDescription( + self.timeline, + description.as_ptr(), + duration.as_secs_f32(), + ) + } + } + + /// Clears the previous set game state in the timeline. + pub fn clear_timeline_state_description(&self, duration: Duration) { + if self.disabled { + return; + } + + unsafe { + sys::SteamAPI_ISteamTimeline_ClearTimelineStateDescription( + self.timeline, + duration.as_secs_f32(), + ) + } + } + + /// Use this to mark an event on the Timeline. + /// The event can be instantaneous or take some amount of time to complete, + /// depending on the value passed in `duration`. + pub fn add_timeline_event( + &self, + icon: &str, + title: &str, + description: &str, + priority: u32, + start_offset_seconds: f32, + duration: Duration, + clip_priority: TimelineEventClipPriority, + ) { + if self.disabled { + return; + } + + let icon = CString::new(icon).unwrap(); + let title = CString::new(title).unwrap(); + let description = CString::new(description).unwrap(); + let duration = duration.as_secs_f32(); + + unsafe { + sys::SteamAPI_ISteamTimeline_AddTimelineEvent( + self.timeline, + icon.as_ptr(), + title.as_ptr(), + description.as_ptr(), + priority, + start_offset_seconds, + duration, + clip_priority.into(), + ) + } + } +} From 5abbe1285cfbd6293426464d94cc44c6a1f2964d Mon Sep 17 00:00:00 2001 From: ldubos Date: Thu, 5 Sep 2024 15:36:25 +0200 Subject: [PATCH 2/2] remove redundant use --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index a10b2cf..6cceadb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,6 @@ pub use steamworks_sys as sys; #[cfg(not(feature = "raw-bindings"))] use steamworks_sys as sys; use sys::{EServerMode, ESteamAPIInitResult, SteamErrMsg}; -use timeline::Timeline; use core::ffi::c_void; use std::collections::HashMap;