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