Skip to main content

nil_core/world/
mod.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4mod battle;
5mod chat;
6mod cheat;
7mod city;
8pub mod config;
9mod continent;
10mod event;
11mod infrastructure;
12mod military;
13mod npc;
14mod player;
15mod ranking;
16mod resources;
17mod round;
18mod savedata;
19pub mod stats;
20
21use crate::chat::Chat;
22use crate::city::City;
23use crate::continent::{Continent, ContinentSize, Coord};
24use crate::error::{Error, Result};
25use crate::event::Emitter;
26use crate::hooks::OnNextRound;
27use crate::infrastructure::Infrastructure;
28use crate::military::Military;
29use crate::npc::bot::{Bot, BotId, BotManager};
30use crate::npc::precursor::{Precursor, PrecursorId, PrecursorManager};
31use crate::player::{Player, PlayerId, 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 bon::Builder;
38use config::{BotAdvancedStartRatio, BotDensity, Locale, WorldConfig, WorldId, WorldName};
39use serde::{Deserialize, Serialize};
40use stats::WorldStats;
41
42#[derive(Debug)]
43pub struct World {
44  round: Round,
45  continent: Continent,
46  player_manager: PlayerManager,
47  bot_manager: BotManager,
48  precursor_manager: PrecursorManager,
49  military: Military,
50  ranking: Ranking,
51  report: ReportManager,
52  config: WorldConfig,
53  stats: WorldStats,
54  chat: Chat,
55
56  // These are not included in the savedata.
57  emitter: Emitter,
58  save_handle: Option<SaveHandle>,
59  on_next_round: Option<OnNextRound>,
60}
61
62impl World {
63  pub fn new(options: &WorldOptions) -> Result<Self> {
64    let config = WorldConfig::new(options);
65    let continent = Continent::new(options.size.get());
66    let precursor_manager = PrecursorManager::new(continent.size());
67    let military = Military::new(continent.size());
68
69    let mut world = Self {
70      round: Round::default(),
71      continent,
72      player_manager: PlayerManager::default(),
73      bot_manager: BotManager::default(),
74      precursor_manager,
75      military,
76      ranking: Ranking::default(),
77      report: ReportManager::default(),
78      config,
79      stats: WorldStats::new(),
80      chat: Chat::default(),
81
82      emitter: Emitter::default(),
83      save_handle: None,
84      on_next_round: None,
85    };
86
87    world.spawn_precursors()?;
88    world.spawn_bots()?;
89    world.update_ranking()?;
90
91    Ok(world)
92  }
93
94  #[inline]
95  pub fn with_savedata(savedata: Savedata) -> Self {
96    Self::from(savedata)
97  }
98
99  pub fn load(bytes: &[u8]) -> Result<Self> {
100    let savedata = Savedata::read(bytes)?;
101    Ok(Self::with_savedata(savedata))
102  }
103
104  #[inline]
105  pub fn id(&self) -> WorldId {
106    self.config.id()
107  }
108
109  #[inline]
110  pub fn config(&self) -> &WorldConfig {
111    &self.config
112  }
113
114  #[inline]
115  pub fn stats(&self) -> WorldStats {
116    self.stats.clone()
117  }
118
119  #[inline]
120  pub fn continent(&self) -> &Continent {
121    &self.continent
122  }
123
124  #[inline]
125  pub fn city(&self, coord: Coord) -> Result<&City> {
126    self.continent.city(coord)
127  }
128
129  #[inline]
130  pub(crate) fn city_mut(&mut self, coord: Coord) -> Result<&mut City> {
131    self.continent.city_mut(coord)
132  }
133
134  #[inline]
135  pub fn infrastructure(&self, coord: Coord) -> Result<&Infrastructure> {
136    self.city(coord).map(City::infrastructure)
137  }
138
139  #[inline]
140  pub fn round(&self) -> &Round {
141    &self.round
142  }
143
144  #[inline]
145  pub fn chat(&self) -> &Chat {
146    &self.chat
147  }
148
149  #[inline]
150  pub fn ranking(&self) -> &Ranking {
151    &self.ranking
152  }
153
154  #[inline]
155  pub fn report(&self) -> &ReportManager {
156    &self.report
157  }
158
159  #[inline]
160  pub fn player_manager(&self) -> &PlayerManager {
161    &self.player_manager
162  }
163
164  #[inline]
165  pub fn player(&self, id: &PlayerId) -> Result<&Player> {
166    self.player_manager.player(id)
167  }
168
169  #[inline]
170  fn player_mut(&mut self, id: &PlayerId) -> Result<&mut Player> {
171    self.player_manager.player_mut(id)
172  }
173
174  pub fn players(&self) -> impl Iterator<Item = &Player> {
175    self.player_manager.players()
176  }
177
178  #[inline]
179  pub fn bot_manager(&self) -> &BotManager {
180    &self.bot_manager
181  }
182
183  #[inline]
184  pub fn bot(&self, id: &BotId) -> Result<&Bot> {
185    self.bot_manager.bot(id)
186  }
187
188  #[inline]
189  fn bot_mut(&mut self, id: &BotId) -> Result<&mut Bot> {
190    self.bot_manager.bot_mut(id)
191  }
192
193  pub fn bots(&self) -> impl Iterator<Item = &Bot> {
194    self.bot_manager.bots()
195  }
196
197  #[inline]
198  pub fn precursor_manager(&self) -> &PrecursorManager {
199    &self.precursor_manager
200  }
201
202  #[inline]
203  pub fn precursor(&self, id: PrecursorId) -> &dyn Precursor {
204    self.precursor_manager.precursor(id)
205  }
206
207  #[inline]
208  fn precursor_mut(&mut self, id: PrecursorId) -> &mut dyn Precursor {
209    self.precursor_manager.precursor_mut(id)
210  }
211
212  pub fn precursors(&self) -> impl Iterator<Item = &dyn Precursor> {
213    self.precursor_manager.precursors()
214  }
215
216  pub fn ruler(&self, ruler: &Ruler) -> Result<RulerRef<'_>> {
217    let ruler = match ruler {
218      Ruler::Bot { id } => RulerRef::Bot(self.bot(id)?),
219      Ruler::Player { id } => RulerRef::Player(self.player(id)?),
220      Ruler::Precursor { id } => RulerRef::Precursor(self.precursor(*id)),
221    };
222
223    Ok(ruler)
224  }
225
226  fn ruler_mut(&mut self, ruler: &Ruler) -> Result<RulerRefMut<'_>> {
227    let ruler = match ruler {
228      Ruler::Bot { id } => RulerRefMut::Bot(self.bot_mut(id)?),
229      Ruler::Player { id } => RulerRefMut::Player(self.player_mut(id)?),
230      Ruler::Precursor { id } => RulerRefMut::Precursor(self.precursor_mut(*id)),
231    };
232
233    Ok(ruler)
234  }
235
236  pub fn rulers(&self) -> impl Iterator<Item = RulerRef<'_>> {
237    self
238      .players()
239      .map(RulerRef::from)
240      .chain(self.bots().map(RulerRef::from))
241      .chain(self.precursors().map(RulerRef::from))
242  }
243
244  #[inline]
245  pub fn military(&self) -> &Military {
246    &self.military
247  }
248
249  pub fn save<F>(&mut self, f: F)
250  where
251    F: FnOnce(Vec<u8>) + Send + Sync + 'static,
252  {
253    self.save_handle = Some(SaveHandle::new(f));
254  }
255
256  pub fn on_next_round<F>(&mut self, f: F)
257  where
258    F: Fn(&mut World) + Send + Sync + 'static,
259  {
260    self.on_next_round = Some(OnNextRound::new(f));
261  }
262}
263
264#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
265#[serde(rename_all = "camelCase")]
266pub struct WorldOptions {
267  #[builder(start_fn, into)]
268  pub name: WorldName,
269
270  #[serde(default)]
271  #[builder(default)]
272  pub size: ContinentSize,
273
274  #[serde(default)]
275  #[builder(default)]
276  pub locale: Locale,
277
278  #[serde(default)]
279  #[builder(default)]
280  pub allow_cheats: bool,
281
282  #[serde(default)]
283  #[builder(default)]
284  pub bot_density: BotDensity,
285
286  #[serde(default)]
287  #[builder(default)]
288  pub bot_advanced_start_ratio: BotAdvancedStartRatio,
289}
290
291impl WorldOptions {
292  pub fn to_world(&self) -> Result<World> {
293    World::try_from(self)
294  }
295}
296
297impl TryFrom<&WorldOptions> for World {
298  type Error = Error;
299
300  fn try_from(options: &WorldOptions) -> Result<Self> {
301    Self::new(options)
302  }
303}