11use super :: team;
2- use crate :: { GenericClient , GenericServer } ;
3-
4- use crate :: { ClientSlots , GeoInfo , Player , QtvStream , ServerType , SoftwareType , Spectator , Team } ;
2+ use crate :: {
3+ ClientSlots , GenericClient , GenericServer , GeoInfo , Player , QtvStream , ServerType ,
4+ SoftwareType , Spectator , Team ,
5+ } ;
56use quake_serverinfo:: Settings ;
67use quake_text:: unicode;
78
9+ #[ cfg( feature = "serde" ) ]
10+ use serde:: ser:: SerializeStruct ;
11+
812/// Represents a server where clients connect as [`Player`] or [`Spectator`].
913#[ derive( Debug , Clone , PartialEq ) ]
10- #[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde :: Deserialize ) ) ]
14+ #[ cfg_attr( feature = "serde" , derive( serde:: Deserialize ) ) ]
1115pub struct GameServer {
1216 pub ( crate ) software_type : SoftwareType ,
13- pub ( crate ) address : String ,
1417 pub ( crate ) ip : String ,
1518 pub ( crate ) port : u16 ,
1619 pub ( crate ) settings : Settings ,
@@ -31,8 +34,8 @@ impl GameServer {
3134 self . software_type . clone ( )
3235 }
3336
34- pub fn address ( & self ) -> & str {
35- & self . address
37+ pub fn address ( & self ) -> String {
38+ format ! ( "{}:{}" , self . ip ( ) , self . port ( ) )
3639 }
3740
3841 pub fn ip ( & self ) -> & str {
@@ -46,16 +49,16 @@ impl GameServer {
4649 & self . settings
4750 }
4851
49- pub fn teams ( & self ) -> impl Iterator < Item = & Team > {
50- self . teams . iter ( )
52+ pub fn teams ( & self ) -> & [ Team ] {
53+ & self . teams
5154 }
5255
53- pub fn players ( & self ) -> impl Iterator < Item = & Player > {
54- self . players . iter ( )
56+ pub fn players ( & self ) -> & [ Player ] {
57+ & self . players
5558 }
5659
57- pub fn spectators ( & self ) -> impl Iterator < Item = & Spectator > {
58- self . spectators . iter ( )
60+ pub fn spectators ( & self ) -> & [ Spectator ] {
61+ & self . spectators
5962 }
6063
6164 pub fn qtv_stream ( & self ) -> Option < & QtvStream > {
@@ -89,7 +92,7 @@ impl GameServer {
8992
9093impl From < & GenericServer > for GameServer {
9194 fn from ( server : & GenericServer ) -> Self {
92- let mut clients: Vec < GenericClient > = server. clients ( ) . cloned ( ) . collect ( ) ;
95+ let mut clients: Vec < GenericClient > = server. clients ( ) . into ( ) ;
9396 clients. sort ( ) ;
9497
9598 let is_teamplay = server. settings ( ) . teamplay . is_some_and ( |tp| tp > 0 ) ;
@@ -108,7 +111,6 @@ impl From<&GenericServer> for GameServer {
108111
109112 Self {
110113 software_type : server. software_type ( ) ,
111- address : server. address ( ) . to_string ( ) ,
112114 ip : server. ip ( ) . to_string ( ) ,
113115 port : server. port ( ) ,
114116 settings : server. settings ( ) . to_owned ( ) ,
@@ -121,6 +123,29 @@ impl From<&GenericServer> for GameServer {
121123 }
122124}
123125
126+ #[ cfg( feature = "serde" ) ]
127+ impl serde:: Serialize for GameServer {
128+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
129+ where
130+ S : serde:: Serializer ,
131+ {
132+ let mut state = serializer. serialize_struct ( "GameServer" , 12 ) ?;
133+ state. serialize_field ( "server_type" , & self . server_type ( ) ) ?;
134+ state. serialize_field ( "software_type" , & self . software_type ( ) ) ?;
135+ state. serialize_field ( "address" , & self . address ( ) ) ?;
136+ state. serialize_field ( "ip" , self . ip ( ) ) ?;
137+ state. serialize_field ( "port" , & self . port ( ) ) ?;
138+ state. serialize_field ( "settings" , self . settings ( ) ) ?;
139+ state. serialize_field ( "player_slots" , & self . player_slots ( ) ) ?;
140+ state. serialize_field ( "spectator_slots" , & self . spectator_slots ( ) ) ?;
141+ state. serialize_field ( "teams" , self . teams ( ) ) ?;
142+ state. serialize_field ( "players" , self . players ( ) ) ?;
143+ state. serialize_field ( "spectators" , self . spectators ( ) ) ?;
144+ state. serialize_field ( "geo" , self . geo ( ) ) ?;
145+ state. end ( )
146+ }
147+ }
148+
124149#[ cfg( test) ]
125150#[ cfg_attr( coverage_nightly, coverage( off) ) ]
126151mod tests {
@@ -134,7 +159,6 @@ mod tests {
134159 let generic = GenericServer {
135160 server_type : ServerType :: GameServer ,
136161 software_type : SoftwareType :: Mvdsv ,
137- address : "10.10.10.10" . to_string ( ) ,
138162 ip : "10.10.10.10" . to_string ( ) ,
139163 port : 28501 ,
140164 settings : Settings {
@@ -175,9 +199,9 @@ mod tests {
175199 assert_eq ! ( server. port( ) , generic. port( ) ) ;
176200 assert_eq ! ( server. player_slots( ) , ClientSlots :: new( 2 , 4 ) ) ;
177201 assert_eq ! ( server. spectator_slots( ) , ClientSlots :: new( 1 , 8 ) ) ;
178- assert_eq ! ( server. teams( ) . count ( ) , 1 ) ;
179- assert_eq ! ( server. players( ) . count ( ) , 2 ) ;
180- assert_eq ! ( server. spectators( ) . count ( ) , 1 ) ;
202+ assert_eq ! ( server. teams( ) . len ( ) , 1 ) ;
203+ assert_eq ! ( server. players( ) . len ( ) , 2 ) ;
204+ assert_eq ! ( server. spectators( ) . len ( ) , 1 ) ;
181205 assert_eq ! ( server. qtv_stream( ) , None ) ;
182206 assert_eq ! ( server. geo( ) , generic. geo( ) ) ;
183207 assert ! ( !server. is_empty( ) ) ;
@@ -201,6 +225,36 @@ mod tests {
201225 ..Default :: default ( )
202226 } ;
203227 let server = GameServer :: from ( & generic) ;
204- assert_eq ! ( server. teams( ) . count( ) , 0 ) ;
228+ assert_eq ! ( server. teams( ) . len( ) , 0 ) ;
229+ }
230+
231+ #[ cfg( feature = "serde" ) ]
232+ #[ test]
233+ fn test_serialization ( ) -> anyhow:: Result < ( ) > {
234+ let server = GameServer {
235+ software_type : SoftwareType :: Mvdsv ,
236+ ip : "10.10.10.10" . to_string ( ) ,
237+ port : 28000 ,
238+ settings : Settings :: default ( ) ,
239+ teams : vec ! [ ] ,
240+ players : vec ! [ ] ,
241+ spectators : vec ! [ ] ,
242+ qtv_stream : None ,
243+ geo : GeoInfo {
244+ country_code : Some ( "US" . to_string ( ) ) ,
245+ country_name : Some ( "United States" . to_string ( ) ) ,
246+ city : Some ( "New York" . to_string ( ) ) ,
247+ region : Some ( "North America" . to_string ( ) ) ,
248+ coords : Some ( Coords :: new ( 40.7128 , -74.0060 ) ) ,
249+ } ,
250+ } ;
251+
252+ let server_json = r#"{"server_type":"game_server","software_type":"mvdsv","address":"10.10.10.10:28000","ip":"10.10.10.10","port":28000,"settings":{"admin":null,"broadcast":null,"city":null,"coords":null,"countrycode":null,"deathmatch":null,"epoch":null,"fpd":null,"fraglimit":null,"gamedir":null,"hostname":null,"hostport":null,"ktxmode":null,"ktxver":null,"map":null,"matchtag":null,"maxclients":null,"maxfps":null,"maxspectators":null,"mode":null,"needpass":null,"pm_ktjump":null,"progs":null,"qvm":null,"serverdemo":null,"status":null,"sv_antilag":null,"teamplay":null,"timelimit":null,"version":null,"z_ext":null},"player_slots":{"total":0,"used":0,"free":0},"spectator_slots":{"total":0,"used":0,"free":0},"teams":[],"players":[],"spectators":[],"geo":{"country_code":"US","country_name":"United States","city":"New York","region":"North America","coords":{"lat":40.7128,"lng":-74.006}}}"# ;
253+
254+ // ensure round-trip serialization
255+ assert_eq ! ( serde_json:: to_string( & server) ?, server_json) ;
256+ assert_eq ! ( serde_json:: from_str:: <GameServer >( server_json) ?, server) ;
257+
258+ Ok ( ( ) )
205259 }
206260}
0 commit comments