Skip to main content

steamkit/types/
game_id.rs

1//! Game ids: the 64-bit id of an app, mod, shortcut or P2P file.
2
3use std::fmt;
4
5use crate::types::steam_id::BitVector64;
6
7/// The kind of game a [`GameID`] refers to.
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
9pub enum GameType {
10    /// A Steam application.
11    #[default]
12    App = 0,
13    /// A game modification.
14    GameMod = 1,
15    /// A shortcut to a program.
16    Shortcut = 2,
17    /// A peer-to-peer file.
18    P2P = 3,
19}
20
21impl GameType {
22    /// The numeric value of this game type.
23    pub const fn value(self) -> u32 {
24        self as u32
25    }
26
27    /// Maps a raw value to a game type. Unknown values become [`GameType::App`].
28    pub const fn from_raw(raw: u32) -> GameType {
29        match raw {
30            1 => GameType::GameMod,
31            2 => GameType::Shortcut,
32            3 => GameType::P2P,
33            _ => GameType::App,
34        }
35    }
36}
37
38/// A 64-bit id of an app, mod, shortcut or P2P file on the Steam network.
39#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
40pub struct GameID {
41    gameid: BitVector64,
42}
43
44impl GameID {
45    /// Creates a zero game id.
46    pub fn new() -> GameID {
47        GameID::from_value(0)
48    }
49
50    /// Creates a game id from its 64-bit value.
51    pub fn from_value(id: u64) -> GameID {
52        GameID {
53            gameid: BitVector64::new(id),
54        }
55    }
56
57    /// Creates a game id for an app.
58    pub fn from_app_id(n_app_id: i32) -> GameID {
59        GameID::from_value(n_app_id as u64)
60    }
61
62    /// Creates a game id for a mod.
63    pub fn from_mod(n_app_id: u32, mod_path: &str) -> GameID {
64        let mut game_id = GameID::from_value(0);
65        game_id.set_app_id(n_app_id);
66        game_id.set_app_type(GameType::GameMod);
67        game_id.set_mod_id(crc32_of(mod_path.as_bytes()));
68        game_id
69    }
70
71    /// Creates a game id for an application shortcut.
72    pub fn from_shortcut(exe_path: &str, app_name: &str) -> GameID {
73        let mut combined = String::with_capacity(exe_path.len() + app_name.len());
74        combined.push_str(exe_path);
75        combined.push_str(app_name);
76
77        let mut game_id = GameID::from_value(0);
78        game_id.set_app_id(0);
79        game_id.set_app_type(GameType::Shortcut);
80        game_id.set_mod_id(crc32_of(combined.as_bytes()));
81        game_id
82    }
83
84    /// Sets the whole id from its 64-bit value.
85    pub fn set(&mut self, game_id: u64) {
86        self.gameid.set_data(game_id);
87    }
88
89    /// The 64-bit value.
90    pub fn to_u64(&self) -> u64 {
91        self.gameid.data()
92    }
93
94    /// The app id.
95    pub fn app_id(&self) -> u32 {
96        self.gameid.get(0, 0xFF_FFFF) as u32
97    }
98
99    /// Sets the app id.
100    pub fn set_app_id(&mut self, value: u32) {
101        self.gameid.set(0, 0xFF_FFFF, value as u64);
102    }
103
104    /// The type of the game.
105    pub fn app_type(&self) -> GameType {
106        GameType::from_raw(self.gameid.get(24, 0xFF) as u32)
107    }
108
109    /// Sets the type of the game.
110    pub fn set_app_type(&mut self, value: GameType) {
111        self.gameid.set(24, 0xFF, value.value() as u64);
112    }
113
114    /// The mod id.
115    pub fn mod_id(&self) -> u32 {
116        self.gameid.get(32, 0xFFFF_FFFF) as u32
117    }
118
119    /// Sets the mod id. Also sets bit 63.
120    pub fn set_mod_id(&mut self, value: u32) {
121        self.gameid.set(32, 0xFFFF_FFFF, value as u64);
122        self.gameid.set(63, 0xFF, 1);
123    }
124
125    /// Whether this is a mod.
126    pub fn is_mod(&self) -> bool {
127        self.app_type() == GameType::GameMod
128    }
129
130    /// Whether this is a shortcut.
131    pub fn is_shortcut(&self) -> bool {
132        self.app_type() == GameType::Shortcut
133    }
134
135    /// Whether this is a P2P file.
136    pub fn is_p2p_file(&self) -> bool {
137        self.app_type() == GameType::P2P
138    }
139
140    /// Whether this is a Steam app.
141    pub fn is_steam_app(&self) -> bool {
142        self.app_type() == GameType::App
143    }
144}
145
146impl fmt::Display for GameID {
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        write!(f, "{}", self.to_u64())
149    }
150}
151
152impl fmt::Debug for GameID {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        fmt::Display::fmt(self, f)
155    }
156}
157
158impl From<GameID> for u64 {
159    fn from(gid: GameID) -> u64 {
160        gid.to_u64()
161    }
162}
163
164impl From<u64> for GameID {
165    fn from(id: u64) -> GameID {
166        GameID::from_value(id)
167    }
168}
169
170impl From<GameID> for String {
171    fn from(gid: GameID) -> String {
172        gid.to_u64().to_string()
173    }
174}
175
176/// CRC-32 (IEEE 802.3).
177fn crc32_of(data: &[u8]) -> u32 {
178    crc32fast::hash(data)
179}