pub mod attributes; mod cond; pub mod game_state; pub mod userinfo; use bitbuffer::{BitRead, BitReadStream, BitWrite, BitWriteStream, Endianness}; use parse_display::Display; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::cmp::Ordering; use std::fmt::{Debug, Display, Formatter}; use std::ops::{Add, Sub}; pub use userinfo::UserInfo; #[derive(Eq, PartialEq, Clone)] pub enum MaybeUtf8String { Valid(String), Invalid(Vec), } impl From<&'_ str> for MaybeUtf8String { fn from(str: &'_ str) -> Self { MaybeUtf8String::Valid(str.into()) } } impl Default for MaybeUtf8String { fn default() -> Self { MaybeUtf8String::Valid(String::new()) } } impl AsRef for MaybeUtf8String { fn as_ref(&self) -> &str { match self { MaybeUtf8String::Valid(s) => s.as_str(), MaybeUtf8String::Invalid(_) => "-- Malformed utf8 --", } } } impl Debug for MaybeUtf8String { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { MaybeUtf8String::Valid(s) => Debug::fmt(s, f), MaybeUtf8String::Invalid(b) => f .debug_struct("MaybeUtf8String::Invalid") .field("data", b) .finish(), } } } impl Display for MaybeUtf8String { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { MaybeUtf8String::Valid(s) => Display::fmt(s, f), MaybeUtf8String::Invalid(_) => write!(f, "-- Malformed utf8 --"), } } } impl MaybeUtf8String { pub fn as_bytes(&self) -> &[u8] { match self { MaybeUtf8String::Valid(s) => s.as_bytes(), MaybeUtf8String::Invalid(b) => b.as_ref(), } } } impl<'a, E: Endianness> BitRead<'a, E> for MaybeUtf8String { fn read(stream: &mut BitReadStream<'a, E>) -> bitbuffer::Result { match String::read(stream) { Ok(str) => Ok(MaybeUtf8String::Valid(str)), Err(bitbuffer::BitError::Utf8Error(_, size)) => { stream.set_pos(stream.pos().saturating_sub(size * 8))?; let mut data: Vec = stream.read_sized(size)?; while data.last() == Some(&0) { data.pop(); } match String::from_utf8(data) { Ok(str) => Ok(MaybeUtf8String::Valid(str)), Err(e) => Ok(MaybeUtf8String::Invalid(e.into_bytes())), } } Err(e) => Err(e), } } } impl BitWrite for MaybeUtf8String { fn write(&self, stream: &mut BitWriteStream) -> bitbuffer::Result<()> { stream.write_bytes(self.as_bytes())?; stream.write(&0u8) } } impl From for String { fn from(str: MaybeUtf8String) -> String { match str { MaybeUtf8String::Valid(s) => s, MaybeUtf8String::Invalid(_) => "-- Malformed utf8 --".into(), } } } impl Serialize for MaybeUtf8String { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.as_ref().serialize(serializer) } } impl<'de> Deserialize<'de> for MaybeUtf8String { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { String::deserialize(deserializer).map(MaybeUtf8String::Valid) } } #[cfg(feature = "schema")] impl schemars::JsonSchema for MaybeUtf8String { fn schema_name() -> std::borrow::Cow<'static, str> { String::schema_name() } fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema { String::json_schema(generator) } } /// Tick relative to the start of the game on the server #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[derive( Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, BitRead, BitWrite, Serialize, Deserialize, Default, Display, )] pub struct ServerTick(u32); impl ServerTick { pub fn range_inclusive(&self, till: Self) -> impl Iterator { (self.0..=till.0).map(Self::from) } } impl PartialEq for ServerTick { fn eq(&self, other: &u32) -> bool { *other == self.0 } } impl PartialOrd for ServerTick { fn partial_cmp(&self, other: &u32) -> Option { self.0.partial_cmp(other) } } impl PartialEq for u32 { fn eq(&self, other: &ServerTick) -> bool { self.eq(&other.0) } } impl PartialOrd for u32 { fn partial_cmp(&self, other: &ServerTick) -> Option { self.partial_cmp(&other.0) } } impl From for ServerTick { fn from(tick: u32) -> Self { ServerTick(tick) } } impl From for u32 { fn from(tick: ServerTick) -> Self { tick.0 } } impl Add for ServerTick { type Output = ServerTick; fn add(self, rhs: u32) -> Self::Output { ServerTick(self.0 + rhs) } } impl Add for ServerTick { type Output = ServerTick; fn add(self, rhs: ServerTick) -> Self::Output { ServerTick(self.0 + rhs.0) } } impl Sub for ServerTick { type Output = ServerTick; fn sub(self, rhs: u32) -> Self::Output { ServerTick(self.0 - rhs) } } impl Sub for ServerTick { type Output = ServerTick; fn sub(self, rhs: ServerTick) -> Self::Output { ServerTick(self.0 - rhs.0) } } /// Tick relative to the start of the demo #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[derive( Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, BitRead, BitWrite, Serialize, Deserialize, Default, Display, )] pub struct DemoTick(u32); impl DemoTick { pub fn range_inclusive(&self, till: Self) -> impl Iterator { (self.0..=till.0).map(Self::from) } } impl PartialEq for DemoTick { fn eq(&self, other: &u32) -> bool { *other == self.0 } } impl PartialOrd for DemoTick { fn partial_cmp(&self, other: &u32) -> Option { self.0.partial_cmp(other) } } impl PartialEq for u32 { fn eq(&self, other: &DemoTick) -> bool { self.eq(&other.0) } } impl PartialOrd for u32 { fn partial_cmp(&self, other: &DemoTick) -> Option { self.partial_cmp(&other.0) } } impl From for DemoTick { fn from(tick: u32) -> Self { DemoTick(tick) } } impl From for u32 { fn from(tick: DemoTick) -> Self { tick.0 } } impl Add for DemoTick { type Output = DemoTick; fn add(self, rhs: u32) -> Self::Output { DemoTick(self.0 + rhs) } } impl Add for DemoTick { type Output = DemoTick; fn add(self, rhs: DemoTick) -> Self::Output { DemoTick(self.0 + rhs.0) } } impl Sub for DemoTick { type Output = DemoTick; fn sub(self, rhs: u32) -> Self::Output { DemoTick(self.0 - rhs) } } impl Sub for DemoTick { type Output = DemoTick; fn sub(self, rhs: DemoTick) -> Self::Output { DemoTick(self.0 - rhs.0) } }