use crate::error::AnyResult;
use crate::world::WorldOptions;
use bon::Builder;
use derive_more::Deref;
use nil_util::{ConstDeref, F64Math};
use serde::{Deserialize, Serialize};
use strum::EnumString;
use uuid::Uuid;
#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct WorldConfig {
#[builder(start_fn, into)]
name: WorldName,
#[builder(skip)]
id: WorldId,
#[serde(default)]
#[builder(default)]
locale: Locale,
#[serde(default)]
#[builder(default)]
allow_cheats: bool,
#[serde(default)]
#[builder(default, into)]
speed: WorldSpeed,
#[serde(default)]
#[builder(default, into)]
unit_speed: WorldUnitSpeed,
#[serde(default)]
#[builder(default, into)]
bot_density: BotDensity,
#[serde(default)]
#[builder(default, into)]
bot_advanced_start_ratio: BotAdvancedStartRatio,
}
impl WorldConfig {
pub fn new(options: &WorldOptions) -> Self {
Self {
id: WorldId::new(),
name: options.name.clone(),
locale: options.locale,
allow_cheats: options.allow_cheats,
speed: options.speed,
unit_speed: options.unit_speed,
bot_density: options.bot_density,
bot_advanced_start_ratio: options.bot_advanced_start_ratio,
}
}
#[inline]
pub fn id(&self) -> WorldId {
self.id
}
#[inline]
pub fn name(&self) -> WorldName {
self.name.clone()
}
#[inline]
pub fn locale(&self) -> Locale {
self.locale
}
#[inline]
pub fn are_cheats_allowed(&self) -> bool {
self.allow_cheats
}
#[inline]
pub fn speed(&self) -> WorldSpeed {
self.speed
}
#[inline]
pub fn unit_speed(&self) -> WorldUnitSpeed {
self.unit_speed
}
#[inline]
pub fn bot_density(&self) -> BotDensity {
self.bot_density
}
#[inline]
pub fn bot_advanced_start_ratio(&self) -> BotAdvancedStartRatio {
self.bot_advanced_start_ratio
}
}
#[derive(
Clone,
Copy,
Debug,
Deref,
derive_more::Display,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Deserialize,
Serialize,
)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct WorldId(Uuid);
impl WorldId {
#[must_use]
pub fn new() -> Self {
Self(Uuid::now_v7())
}
}
impl Default for WorldId {
fn default() -> Self {
Self::new()
}
}
impl TryFrom<&str> for WorldId {
type Error = anyhow::Error;
fn try_from(value: &str) -> AnyResult<Self> {
Ok(Self(Uuid::try_parse(value)?))
}
}
#[derive(Clone, Debug, derive_more::Display, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct WorldName(Box<str>);
impl<T: AsRef<str>> From<T> for WorldName {
fn from(value: T) -> Self {
Self(Box::from(value.as_ref()))
}
}
#[derive(Copy, Debug, strum::Display, EnumString, Deserialize, Serialize)]
#[derive_const(Clone, Default)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub enum Locale {
#[default]
#[serde(rename = "en-US")]
#[strum(serialize = "en-US")]
English,
#[serde(rename = "pt-BR")]
#[strum(serialize = "pt-BR")]
Portuguese,
}
macro_rules! impl_f64_newtype {
($name:ident, min = $min:expr, max = $max:expr) => {
impl $name {
pub const MIN: Self = $name($min);
pub const MAX: Self = $name($max);
#[inline]
pub const fn new(value: f64) -> Self {
debug_assert!(value.is_finite());
debug_assert!(!value.is_subnormal());
Self(value.clamp(Self::MIN.0, Self::MAX.0))
}
}
impl const From<f64> for $name {
fn from(value: f64) -> Self {
Self::new(value)
}
}
impl const From<$name> for f64 {
fn from(value: $name) -> Self {
value.0
}
}
};
($name:ident, min = $min:expr, max = $max:expr, default = $default:expr) => {
impl_f64_newtype!($name, min = $min, max = $max);
impl const Default for $name {
fn default() -> Self {
Self::new($default)
}
}
};
}
#[derive(Copy, Debug, derive_more::Display, Deserialize, Serialize, ConstDeref, F64Math)]
#[derive_const(Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct WorldSpeed(f64);
impl_f64_newtype!(WorldSpeed, min = 0.1, max = 10.0, default = 1.0);
#[derive(Copy, Debug, derive_more::Display, Deserialize, Serialize, ConstDeref, F64Math)]
#[derive_const(Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct WorldUnitSpeed(f64);
impl_f64_newtype!(WorldUnitSpeed, min = 0.1, max = 10.0, default = 1.0);
#[derive(Copy, Debug, derive_more::Display, Deserialize, Serialize, ConstDeref, F64Math)]
#[derive_const(Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct BotDensity(f64);
impl_f64_newtype!(
BotDensity,
min = 0.0,
max = 3.0,
default = if cfg!(target_os = "android") { 1.0 } else { 2.0 }
);
#[derive(Copy, Debug, derive_more::Display, Deserialize, Serialize, ConstDeref, F64Math)]
#[derive_const(Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct BotAdvancedStartRatio(f64);
impl_f64_newtype!(BotAdvancedStartRatio, min = 0.0, max = 1.0, default = 0.2);