1mod battle;
5mod chat;
6mod city;
7mod continent;
8mod event;
9mod infrastructure;
10mod market;
11mod military;
12mod npc;
13mod player;
14mod ranking;
15mod report;
16mod resources;
17mod round;
18mod savedata;
19
20pub mod cheat;
21pub mod config;
22pub mod stats;
23
24use crate::chat::Chat;
25use crate::continent::Continent;
26use crate::continent::size::ContinentSize;
27use crate::error::{Error, Result};
28use crate::event::Emitter;
29use crate::hooks::OnNextRound;
30use crate::market::Market;
31use crate::market::fee::MarketFee;
32use crate::military::Military;
33use crate::npc::bot::BotManager;
34use crate::npc::precursor::PrecursorManager;
35use crate::player::PlayerManager;
36use crate::ranking::Ranking;
37use crate::round::Round;
38use crate::ruler::{Ruler, RulerRef, RulerRefMut};
39use crate::savedata::{SaveHandle, Savedata};
40use crate::world::config::{WorldSpeed, WorldUnitSpeed};
41use bon::Builder;
42use config::{BotAdvancedStartRatio, BotDensity, Locale, WorldConfig, WorldId, WorldName};
43use serde::{Deserialize, Serialize};
44use stats::WorldStats;
45use std::sync::Arc;
46
47#[derive(Debug)]
48pub struct World {
49 round: Round,
50 continent: Continent,
51 player_manager: PlayerManager,
52 bot_manager: BotManager,
53 precursor_manager: PrecursorManager,
54 military: Military,
55 market: Market,
56 ranking: Ranking,
57 chat: Chat,
58
59 config: Arc<WorldConfig>,
60 stats: WorldStats,
61
62 emitter: Emitter,
64 save_handle: Option<SaveHandle>,
65 on_next_round: Option<OnNextRound>,
66}
67
68impl World {
69 pub fn new(mut options: WorldOptions) -> Result<Self> {
70 WorldOptions::clamp(&mut options);
71 options.name = options.name.trim().into();
72
73 let config = WorldConfig::new(&options);
74 let stats = WorldStats::new(&config);
75 let continent = Continent::new(options.size.unwrap_or_default());
76 let precursor_manager = PrecursorManager::new(continent.size());
77 let military = Military::new(continent.size());
78 let market = Market::new(options.market_fee.unwrap_or_default());
79
80 let mut world = Self {
81 round: Round::default(),
82 continent,
83 player_manager: PlayerManager::default(),
84 bot_manager: BotManager::default(),
85 precursor_manager,
86 military,
87 market,
88 ranking: Ranking::default(),
89 config: Arc::new(config),
90 stats,
91 chat: Chat::default(),
92
93 emitter: Emitter::default(),
94 save_handle: None,
95 on_next_round: None,
96 };
97
98 world.spawn_precursors()?;
99 world.spawn_bots()?;
100 world.update_ranking()?;
101
102 Ok(world)
103 }
104
105 #[inline]
106 pub fn with_savedata(savedata: Savedata) -> Self {
107 Self::from(savedata)
108 }
109
110 pub fn load(bytes: &[u8]) -> Result<Self> {
111 let savedata = Savedata::read(bytes)?;
112 Ok(Self::with_savedata(savedata))
113 }
114
115 #[inline]
116 pub fn id(&self) -> WorldId {
117 self.config.id()
118 }
119
120 #[inline]
121 pub fn config(&self) -> Arc<WorldConfig> {
122 Arc::clone(&self.config)
123 }
124
125 #[inline]
126 pub fn stats(&self) -> WorldStats {
127 self.stats.clone()
128 }
129
130 pub fn ruler(&self, ruler: &Ruler) -> Result<RulerRef<'_>> {
131 let ruler = match ruler {
132 Ruler::Bot { id } => RulerRef::Bot(self.bot(id)?),
133 Ruler::Player { id } => RulerRef::Player(self.player(id)?),
134 Ruler::Precursor { id } => RulerRef::Precursor(self.precursor(*id)),
135 };
136
137 Ok(ruler)
138 }
139
140 fn ruler_mut(&mut self, ruler: &Ruler) -> Result<RulerRefMut<'_>> {
141 let ruler = match ruler {
142 Ruler::Bot { id } => RulerRefMut::Bot(self.bot_mut(id)?),
143 Ruler::Player { id } => RulerRefMut::Player(self.player_mut(id)?),
144 Ruler::Precursor { id } => RulerRefMut::Precursor(self.precursor_mut(*id)),
145 };
146
147 Ok(ruler)
148 }
149
150 pub fn rulers(&self) -> impl Iterator<Item = RulerRef<'_>> {
151 self
152 .players()
153 .map(RulerRef::from)
154 .chain(self.bots().map(RulerRef::from))
155 .chain(self.precursors().map(RulerRef::from))
156 }
157
158 pub fn save<F>(&mut self, f: F)
161 where
162 F: FnOnce(Vec<u8>) + Send + Sync + 'static,
163 {
164 self.save_handle = Some(SaveHandle::new(f));
165 }
166
167 pub fn on_next_round<F>(&mut self, f: F)
169 where
170 F: Fn(&mut World) + Send + Sync + 'static,
171 {
172 self.on_next_round = Some(OnNextRound::new(f));
173 }
174}
175
176impl Drop for World {
177 fn drop(&mut self) {
178 let _ = self.emit_drop();
179 }
180}
181
182impl TryFrom<WorldOptions> for World {
183 type Error = Error;
184
185 fn try_from(options: WorldOptions) -> Result<Self> {
186 Self::new(options)
187 }
188}
189
190#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
191#[serde(rename_all = "camelCase")]
192#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
193#[cfg_attr(feature = "typescript", ts(optional_fields = nullable))]
194pub struct WorldOptions {
195 #[builder(start_fn, into)]
196 pub name: WorldName,
197
198 #[serde(default)]
199 #[builder(into)]
200 pub size: Option<ContinentSize>,
201
202 #[serde(default)]
203 pub locale: Option<Locale>,
204
205 #[serde(default)]
206 pub allow_cheats: Option<bool>,
207
208 #[serde(default)]
209 #[builder(into)]
210 pub speed: Option<WorldSpeed>,
211
212 #[serde(default)]
213 #[builder(into)]
214 pub unit_speed: Option<WorldUnitSpeed>,
215
216 #[serde(default)]
217 #[builder(into)]
218 pub bot_density: Option<BotDensity>,
219
220 #[serde(default)]
221 #[builder(into)]
222 pub bot_advanced_start_ratio: Option<BotAdvancedStartRatio>,
223
224 #[serde(default)]
225 #[builder(into)]
226 pub market_fee: Option<MarketFee>,
227}
228
229impl WorldOptions {
230 pub fn clamp(&mut self) {
231 macro_rules! clamp {
232 ($($field_ty:ident => $field:ident),* $(,)?) => {
233 $(
234 if let Some(value) = self.$field.as_mut() {
235 $field_ty::clamp(value);
236 }
237 )*
238 };
239 }
240
241 clamp!(
242 ContinentSize => size,
243 WorldSpeed => speed,
244 WorldUnitSpeed => unit_speed,
245 BotDensity => bot_density,
246 BotAdvancedStartRatio => bot_advanced_start_ratio,
247 MarketFee => market_fee,
248 );
249 }
250}