1use crate::error::AnyResult;
5use crate::world::WorldOptions;
6use derive_more::{Deref, Display, Into};
7use serde::{Deserialize, Serialize};
8use std::sync::Arc;
9use uuid::Uuid;
10
11#[derive(Clone, Debug, Deserialize, Serialize)]
12#[serde(rename_all = "camelCase")]
13pub struct WorldConfig {
14 id: WorldId,
15 name: WorldName,
16 locale: Locale,
17 allow_cheats: bool,
18 bot_density: BotDensity,
19 bot_advanced_start_ratio: BotAdvancedStartRatio,
20}
21
22impl WorldConfig {
23 pub fn new(options: &WorldOptions) -> Self {
24 Self {
25 id: WorldId::new(),
26 name: options.name.clone(),
27 locale: options.locale,
28 allow_cheats: options.allow_cheats,
29 bot_density: options.bot_density,
30 bot_advanced_start_ratio: options.bot_advanced_start_ratio,
31 }
32 }
33
34 #[inline]
35 pub fn id(&self) -> WorldId {
36 self.id
37 }
38
39 #[inline]
40 pub fn name(&self) -> WorldName {
41 self.name.clone()
42 }
43
44 #[inline]
45 pub fn locale(&self) -> Locale {
46 self.locale
47 }
48
49 #[inline]
50 pub fn are_cheats_allowed(&self) -> bool {
51 self.allow_cheats
52 }
53
54 #[inline]
55 pub fn bot_density(&self) -> BotDensity {
56 self.bot_density
57 }
58
59 #[inline]
60 pub fn bot_advanced_start_ratio(&self) -> BotAdvancedStartRatio {
61 self.bot_advanced_start_ratio
62 }
63}
64
65#[derive(
66 Clone, Copy, Debug, Deref, Display, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize,
67)]
68pub struct WorldId(Uuid);
69
70impl WorldId {
71 #[must_use]
72 pub fn new() -> Self {
73 Self(Uuid::now_v7())
74 }
75}
76
77impl Default for WorldId {
78 fn default() -> Self {
79 Self::new()
80 }
81}
82
83impl TryFrom<&str> for WorldId {
84 type Error = anyhow::Error;
85
86 fn try_from(value: &str) -> AnyResult<Self> {
87 Ok(Self(Uuid::try_parse(value)?))
88 }
89}
90
91#[derive(Clone, Debug, Deserialize, Serialize)]
92pub struct WorldName(Arc<str>);
93
94impl<T: AsRef<str>> From<T> for WorldName {
95 fn from(value: T) -> Self {
96 Self(Arc::from(value.as_ref()))
97 }
98}
99
100#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
101pub enum Locale {
102 #[default]
103 #[serde(rename = "en-US")]
104 English,
105
106 #[serde(rename = "pt-BR")]
107 Portuguese,
108}
109
110#[derive(Clone, Copy, Debug, Deref, Into, Deserialize, Serialize)]
111pub struct BotDensity(f64);
112
113impl BotDensity {
114 pub const MIN: Self = BotDensity(0.0);
115 pub const MAX: Self = BotDensity(3.0);
116
117 #[inline]
118 pub const fn new(density: f64) -> Self {
119 debug_assert!(density.is_finite());
120 debug_assert!(!density.is_subnormal());
121 Self(density.clamp(Self::MIN.0, Self::MAX.0))
122 }
123}
124
125impl Default for BotDensity {
126 fn default() -> Self {
127 if cfg!(target_os = "android") { Self::new(1.0) } else { Self::new(2.0) }
128 }
129}
130
131#[derive(Clone, Copy, Debug, Deref, Into, Deserialize, Serialize)]
133pub struct BotAdvancedStartRatio(f64);
134
135impl BotAdvancedStartRatio {
136 pub const MIN: Self = BotAdvancedStartRatio(0.0);
137 pub const MAX: Self = BotAdvancedStartRatio(1.0);
138
139 #[inline]
140 pub const fn new(ratio: f64) -> Self {
141 debug_assert!(ratio.is_finite());
142 debug_assert!(!ratio.is_subnormal());
143 Self(ratio.clamp(Self::MIN.0, Self::MAX.0))
144 }
145}
146
147impl Default for BotAdvancedStartRatio {
148 fn default() -> Self {
149 Self::new(0.2)
150 }
151}