Skip to main content

nil_core/world/
config.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use crate::error::AnyResult;
5use crate::world::WorldOptions;
6use bon::Builder;
7use nil_util::{ClampNew, ConstDeref, F64Math};
8use serde::{Deserialize, Serialize};
9use std::ops::Deref;
10use strum::EnumString;
11use uuid::Uuid;
12
13#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
14#[serde(rename_all = "camelCase")]
15#[builder(builder_type(vis = "pub(crate)"))]
16#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
17pub struct WorldConfig {
18  #[builder(start_fn, into)]
19  name: WorldName,
20
21  #[builder(skip)]
22  id: WorldId,
23
24  #[serde(default)]
25  #[builder(default)]
26  locale: Locale,
27
28  #[serde(default)]
29  #[builder(default)]
30  allow_cheats: bool,
31
32  #[serde(default)]
33  #[builder(default, into)]
34  speed: WorldSpeed,
35
36  #[serde(default)]
37  #[builder(default, into)]
38  unit_speed: WorldUnitSpeed,
39
40  #[serde(default)]
41  #[builder(default, into)]
42  bot_density: BotDensity,
43
44  #[serde(default)]
45  #[builder(default, into)]
46  bot_advanced_start_ratio: BotAdvancedStartRatio,
47}
48
49impl WorldConfig {
50  pub fn new(options: &WorldOptions) -> Self {
51    Self {
52      id: WorldId::new(),
53      name: options.name.clone(),
54      locale: options.locale.unwrap_or_default(),
55      allow_cheats: options.allow_cheats.unwrap_or_default(),
56      speed: options.speed.unwrap_or_default(),
57      unit_speed: options.unit_speed.unwrap_or_default(),
58      bot_density: options.bot_density.unwrap_or_default(),
59      bot_advanced_start_ratio: options
60        .bot_advanced_start_ratio
61        .unwrap_or_default(),
62    }
63  }
64
65  #[inline]
66  pub fn id(&self) -> WorldId {
67    self.id
68  }
69
70  #[inline]
71  pub fn name(&self) -> WorldName {
72    self.name.clone()
73  }
74
75  #[inline]
76  pub fn locale(&self) -> Locale {
77    self.locale
78  }
79
80  #[inline]
81  pub fn are_cheats_allowed(&self) -> bool {
82    self.allow_cheats
83  }
84
85  #[inline]
86  pub fn speed(&self) -> WorldSpeed {
87    self.speed
88  }
89
90  #[inline]
91  pub fn unit_speed(&self) -> WorldUnitSpeed {
92    self.unit_speed
93  }
94
95  #[inline]
96  pub fn bot_density(&self) -> BotDensity {
97    self.bot_density
98  }
99
100  #[inline]
101  pub fn bot_advanced_start_ratio(&self) -> BotAdvancedStartRatio {
102    self.bot_advanced_start_ratio
103  }
104}
105
106#[derive(
107  Clone,
108  Copy,
109  Debug,
110  derive_more::Deref,
111  derive_more::Display,
112  PartialEq,
113  Eq,
114  PartialOrd,
115  Ord,
116  Hash,
117  Deserialize,
118  Serialize,
119)]
120#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
121pub struct WorldId(Uuid);
122
123impl WorldId {
124  #[must_use]
125  pub fn new() -> Self {
126    Self(Uuid::now_v7())
127  }
128}
129
130impl Default for WorldId {
131  fn default() -> Self {
132    Self::new()
133  }
134}
135
136impl TryFrom<&str> for WorldId {
137  type Error = anyhow::Error;
138
139  fn try_from(value: &str) -> AnyResult<Self> {
140    Ok(Self(Uuid::try_parse(value)?))
141  }
142}
143
144#[derive(Clone, Debug, derive_more::Display, PartialEq, Eq, Deserialize, Serialize)]
145#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
146pub struct WorldName(Box<str>);
147
148impl Deref for WorldName {
149  type Target = str;
150
151  fn deref(&self) -> &Self::Target {
152    self.0.as_str()
153  }
154}
155
156impl<T: AsRef<str>> From<T> for WorldName {
157  fn from(value: T) -> Self {
158    Self(Box::from(value.as_ref()))
159  }
160}
161
162#[derive(Copy, Debug, strum::Display, EnumString, Deserialize, Serialize)]
163#[derive_const(Clone, Default)]
164#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
165pub enum Locale {
166  #[default]
167  #[serde(rename = "en-US")]
168  #[strum(serialize = "en-US")]
169  English,
170
171  #[serde(rename = "pt-BR")]
172  #[strum(serialize = "pt-BR")]
173  Portuguese,
174}
175
176macro_rules! impl_f64_newtype {
177  ($name:ident, min = $min:expr, max = $max:expr) => {
178    impl $name {
179      pub const MIN: Self = $name($min);
180      pub const MAX: Self = $name($max);
181
182      #[inline]
183      pub const fn new(value: f64) -> Self {
184        debug_assert!(value.is_finite());
185        debug_assert!(!value.is_subnormal());
186        Self(value.clamp(Self::MIN.0, Self::MAX.0))
187      }
188    }
189
190    const impl From<f64> for $name {
191      fn from(value: f64) -> Self {
192        Self::new(value)
193      }
194    }
195
196    const impl From<$name> for f64 {
197      fn from(value: $name) -> Self {
198        value.0
199      }
200    }
201  };
202  ($name:ident, min = $min:expr, max = $max:expr, default = $default:expr) => {
203    impl_f64_newtype!($name, min = $min, max = $max);
204
205    const impl Default for $name {
206      fn default() -> Self {
207        Self::new($default)
208      }
209    }
210  };
211}
212
213#[derive(
214  Copy, Debug, derive_more::Display, Deserialize, Serialize, ClampNew, ConstDeref, F64Math,
215)]
216#[derive_const(Clone, PartialEq, PartialOrd)]
217#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
218pub struct WorldSpeed(f64);
219
220impl_f64_newtype!(WorldSpeed, min = 0.1, max = 10.0, default = 1.0);
221
222#[derive(
223  Copy, Debug, derive_more::Display, Deserialize, Serialize, ClampNew, ConstDeref, F64Math,
224)]
225#[derive_const(Clone, PartialEq, PartialOrd)]
226#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
227pub struct WorldUnitSpeed(f64);
228
229impl_f64_newtype!(WorldUnitSpeed, min = 0.1, max = 10.0, default = 1.0);
230
231#[derive(
232  Copy, Debug, derive_more::Display, Deserialize, Serialize, ClampNew, ConstDeref, F64Math,
233)]
234#[derive_const(Clone, PartialEq, PartialOrd)]
235#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
236pub struct BotDensity(f64);
237
238impl_f64_newtype!(BotDensity, min = 0.0, max = 3.0, default = 2.0);
239
240/// Proportion of bots that will have an advanced start with higher level infrastructure.
241#[derive(
242  Copy, Debug, derive_more::Display, Deserialize, Serialize, ClampNew, ConstDeref, F64Math,
243)]
244#[derive_const(Clone, PartialEq, PartialOrd)]
245#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
246pub struct BotAdvancedStartRatio(f64);
247
248impl_f64_newtype!(BotAdvancedStartRatio, min = 0.0, max = 1.0, default = 0.2);