gamedig/services/valve_master_server/
types.rs1use std::collections::HashMap;
2use std::mem::Discriminant;
3
4#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
6pub enum Filter {
7 IsSecured(bool),
8 RunsMap(String),
9 CanHavePassword(bool),
10 CanBeEmpty(bool),
11 IsEmpty(bool),
12 CanBeFull(bool),
13 RunsAppID(u32),
14 NotAppID(u32),
15 HasTags(Vec<String>),
16 MatchName(String),
17 MatchVersion(String),
18 RestrictUniqueIP(bool),
21 OnAddress(String),
23 Whitelisted(bool),
24 SpectatorProxy(bool),
25 IsDedicated(bool),
26 RunsLinux(bool),
27 HasGameDir(String),
28}
29
30const fn bool_as_char_u8(b: &bool) -> u8 {
31 match b {
32 true => b'1',
33 false => b'0',
34 }
35}
36
37impl Filter {
38 pub(crate) fn to_bytes(&self) -> Vec<u8> {
39 let mut bytes: Vec<u8> = Vec::new();
40
41 match self {
42 Self::IsSecured(secured) => {
43 bytes = b"\\secure\\".to_vec();
44 bytes.extend([bool_as_char_u8(secured)]);
45 }
46 Self::RunsMap(map) => {
47 bytes = b"\\map\\".to_vec();
48 bytes.extend(map.as_bytes());
49 }
50 Self::CanHavePassword(password) => {
51 bytes = b"\\password\\".to_vec();
52 bytes.extend([bool_as_char_u8(password)]);
53 }
54 Self::CanBeEmpty(empty) => {
55 bytes = b"\\empty\\".to_vec();
56 bytes.extend([bool_as_char_u8(empty)]);
57 }
58 Self::CanBeFull(full) => {
59 bytes = b"\\full\\".to_vec();
60 bytes.extend([bool_as_char_u8(full)]);
61 }
62 Self::RunsAppID(id) => {
63 bytes = b"\\appid\\".to_vec();
64 bytes.extend(id.to_string().as_bytes());
65 }
66 Self::HasTags(tags) => {
67 if !tags.is_empty() {
68 bytes = b"\\gametype\\".to_vec();
69 for tag in tags.iter() {
70 bytes.extend(tag.as_bytes());
71 bytes.extend([b',']);
72 }
73
74 bytes.pop();
75 }
76 }
77 Self::NotAppID(id) => {
78 bytes = b"\\napp\\".to_vec();
79 bytes.extend(id.to_string().as_bytes());
80 }
81 Self::IsEmpty(empty) => {
82 bytes = b"\\noplayers\\".to_vec();
83 bytes.extend([bool_as_char_u8(empty)]);
84 }
85 Self::MatchName(name) => {
86 bytes = b"\\name_match\\".to_vec();
87 bytes.extend(name.as_bytes());
88 }
89 Self::MatchVersion(version) => {
90 bytes = b"\\version_match\\".to_vec();
91 bytes.extend(version.as_bytes());
92 }
93 Self::RestrictUniqueIP(unique) => {
94 bytes = b"\\collapse_addr_hash\\".to_vec();
95 bytes.extend([bool_as_char_u8(unique)]);
96 }
97 Self::OnAddress(address) => {
98 bytes = b"\\gameaddr\\".to_vec();
99 bytes.extend(address.as_bytes());
100 }
101 Self::Whitelisted(whitelisted) => {
102 bytes = b"\\white\\".to_vec();
103 bytes.extend([bool_as_char_u8(whitelisted)]);
104 }
105 Self::SpectatorProxy(condition) => {
106 bytes = b"\\proxy\\".to_vec();
107 bytes.extend([bool_as_char_u8(condition)]);
108 }
109 Self::IsDedicated(dedicated) => {
110 bytes = b"\\dedicated\\".to_vec();
111 bytes.extend([bool_as_char_u8(dedicated)]);
112 }
113 Self::RunsLinux(linux) => {
114 bytes = b"\\linux\\".to_vec();
115 bytes.extend([bool_as_char_u8(linux)]);
116 }
117 Self::HasGameDir(game_dir) => {
118 bytes = b"\\gamedir\\".to_vec();
119 bytes.extend(game_dir.as_bytes());
120 }
121 }
122
123 bytes
124 }
125}
126
127#[derive(Debug, Clone, PartialEq, Eq)]
140pub struct SearchFilters {
141 filters: HashMap<Discriminant<Filter>, Filter>,
142 nor_filters: HashMap<Discriminant<Filter>, Filter>,
143 nand_filters: HashMap<Discriminant<Filter>, Filter>,
144}
145
146impl Default for SearchFilters {
147 fn default() -> Self { Self::new() }
148}
149
150impl SearchFilters {
151 pub fn new() -> Self {
152 Self {
153 filters: HashMap::new(),
154 nor_filters: HashMap::new(),
155 nand_filters: HashMap::new(),
156 }
157 }
158
159 pub fn insert(self, filter: Filter) -> Self {
160 let mut updated_fitler = self.filters;
161 updated_fitler.insert(std::mem::discriminant(&filter), filter);
162
163 Self {
164 filters: updated_fitler,
165 nand_filters: self.nand_filters,
166 nor_filters: self.nor_filters,
167 }
168 }
169
170 pub fn insert_nand(self, filter: Filter) -> Self {
171 let mut updated_fitler = self.nor_filters;
172 updated_fitler.insert(std::mem::discriminant(&filter), filter);
173
174 Self {
175 filters: self.filters,
176 nand_filters: self.nand_filters,
177 nor_filters: updated_fitler,
178 }
179 }
180
181 pub fn insert_nor(self, filter: Filter) -> Self {
182 let mut updated_fitler = self.nand_filters;
183 updated_fitler.insert(std::mem::discriminant(&filter), filter);
184
185 Self {
186 filters: self.filters,
187 nand_filters: updated_fitler,
188 nor_filters: self.nor_filters,
189 }
190 }
191
192 fn special_filter_to_bytes(name: &str, filters: &HashMap<Discriminant<Filter>, Filter>) -> Vec<u8> {
193 let mut bytes = Vec::new();
194
195 if !filters.is_empty() {
196 bytes.extend(name.as_bytes());
197 bytes.extend(filters.len().to_string().as_bytes());
198 for filter in filters.values() {
199 bytes.extend(filter.to_bytes());
200 }
201 }
202
203 bytes
204 }
205
206 pub(crate) fn to_bytes(&self) -> Vec<u8> {
207 let mut bytes: Vec<u8> = Vec::new();
208
209 for filter in self.filters.values() {
210 bytes.extend(filter.to_bytes())
211 }
212
213 bytes.extend(Self::special_filter_to_bytes("nand", &self.nand_filters));
214 bytes.extend(Self::special_filter_to_bytes("nor", &self.nor_filters));
215
216 bytes.extend([0x00]);
217 bytes
218 }
219}
220
221#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
223#[repr(u8)]
224pub enum Region {
225 UsEast = 0x00,
226 UsWest = 0x01,
227 AmericaSouth = 0x02,
228 Europe = 0x03,
229 Asia = 0x04,
230 Australia = 0x05,
231 MiddleEast = 0x06,
232 Africa = 0x07,
233 Others = 0xFF,
234}