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 report;
17mod resources;
18mod round;
19mod savedata;
20pub mod stats;
21
22use crate::chat::Chat;
23use crate::continent::{Continent, ContinentSize};
24use crate::error::{Error, Result};
25use crate::event::Emitter;
26use crate::hooks::OnNextRound;
27use crate::military::Military;
28use crate::npc::bot::BotManager;
29use crate::npc::precursor::PrecursorManager;
30use crate::player::PlayerManager;
31use crate::ranking::Ranking;
32use crate::report::ReportManager;
33use crate::round::Round;
34use crate::ruler::{Ruler, RulerRef, RulerRefMut};
35use crate::savedata::{SaveHandle, Savedata};
36use crate::world::config::{WorldSpeed, WorldUnitSpeed};
37use bon::Builder;
38use config::{BotAdvancedStartRatio, BotDensity, Locale, WorldConfig, WorldId, WorldName};
39use serde::{Deserialize, Serialize};
40use stats::WorldStats;
41use std::sync::Arc;
42
43#[derive(Debug)]
44pub struct World {
45  round: Round,
46  continent: Continent,
47  player_manager: PlayerManager,
48  bot_manager: BotManager,
49  precursor_manager: PrecursorManager,
50  military: Military,
51  ranking: Ranking,
52  report: ReportManager,
53  chat: Chat,
54
55  config: Arc<WorldConfig>,
56  stats: WorldStats,
57
58  // These are not included in the savedata.
59  emitter: Emitter,
60  save_handle: Option<SaveHandle>,
61  on_next_round: Option<OnNextRound>,
62}
63
64impl World {
65  pub fn new(options: &WorldOptions) -> Result<Self> {
66    let config = WorldConfig::new(options);
67    let stats = WorldStats::new(&config);
68    let continent = Continent::new(options.size.get());
69    let precursor_manager = PrecursorManager::new(continent.size());
70    let military = Military::new(continent.size());
71
72    let mut world = Self {
73      round: Round::default(),
74      continent,
75      player_manager: PlayerManager::default(),
76      bot_manager: BotManager::default(),
77      precursor_manager,
78      military,
79      ranking: Ranking::default(),
80      report: ReportManager::default(),
81      config: Arc::new(config),
82      stats,
83      chat: Chat::default(),
84
85      emitter: Emitter::default(),
86      save_handle: None,
87      on_next_round: None,
88    };
89
90    world.spawn_precursors()?;
91    world.spawn_bots()?;
92    world.update_ranking()?;
93
94    Ok(world)
95  }
96
97  #[inline]
98  pub fn with_savedata(savedata: Savedata) -> Self {
99    Self::from(savedata)
100  }
101
102  pub fn load(bytes: &[u8]) -> Result<Self> {
103    let savedata = Savedata::read(bytes)?;
104    Ok(Self::with_savedata(savedata))
105  }
106
107  #[inline]
108  pub fn id(&self) -> WorldId {
109    self.config.id()
110  }
111
112  #[inline]
113  pub fn config(&self) -> Arc<WorldConfig> {
114    Arc::clone(&self.config)
115  }
116
117  #[inline]
118  pub fn stats(&self) -> WorldStats {
119    self.stats.clone()
120  }
121
122  #[inline]
123  pub fn report(&self) -> &ReportManager {
124    &self.report
125  }
126
127  pub fn ruler(&self, ruler: &Ruler) -> Result<RulerRef<'_>> {
128    let ruler = match ruler {
129      Ruler::Bot { id } => RulerRef::Bot(self.bot(id)?),
130      Ruler::Player { id } => RulerRef::Player(self.player(id)?),
131      Ruler::Precursor { id } => RulerRef::Precursor(self.precursor(*id)),
132    };
133
134    Ok(ruler)
135  }
136
137  fn ruler_mut(&mut self, ruler: &Ruler) -> Result<RulerRefMut<'_>> {
138    let ruler = match ruler {
139      Ruler::Bot { id } => RulerRefMut::Bot(self.bot_mut(id)?),
140      Ruler::Player { id } => RulerRefMut::Player(self.player_mut(id)?),
141      Ruler::Precursor { id } => RulerRefMut::Precursor(self.precursor_mut(*id)),
142    };
143
144    Ok(ruler)
145  }
146
147  pub fn rulers(&self) -> impl Iterator<Item = RulerRef<'_>> {
148    self
149      .players()
150      .map(RulerRef::from)
151      .chain(self.bots().map(RulerRef::from))
152      .chain(self.precursors().map(RulerRef::from))
153  }
154
155  #[inline]
156  pub fn military(&self) -> &Military {
157    &self.military
158  }
159
160  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)
168  where
169    F: Fn(&mut World) + Send + Sync + 'static,
170  {
171    self.on_next_round = Some(OnNextRound::new(f));
172  }
173}
174
175impl Drop for World {
176  fn drop(&mut self) {
177    self.emit_drop();
178  }
179}
180
181#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
182#[serde(rename_all = "camelCase")]
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}