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 bon::Builder;
37use config::{BotAdvancedStartRatio, BotDensity, Locale, WorldConfig, WorldId, WorldName};
38use serde::{Deserialize, Serialize};
39use stats::WorldStats;
40
41#[derive(Debug)]
42pub struct World {
43  round: Round,
44  continent: Continent,
45  player_manager: PlayerManager,
46  bot_manager: BotManager,
47  precursor_manager: PrecursorManager,
48  military: Military,
49  ranking: Ranking,
50  report: ReportManager,
51  config: WorldConfig,
52  stats: WorldStats,
53  chat: Chat,
54
55  // These are not included in the savedata.
56  emitter: Emitter,
57  save_handle: Option<SaveHandle>,
58  on_next_round: Option<OnNextRound>,
59}
60
61impl World {
62  pub fn new(options: &WorldOptions) -> Result<Self> {
63    let config = WorldConfig::new(options);
64    let continent = Continent::new(options.size.get());
65    let precursor_manager = PrecursorManager::new(continent.size());
66    let military = Military::new(continent.size());
67
68    let mut world = Self {
69      round: Round::default(),
70      continent,
71      player_manager: PlayerManager::default(),
72      bot_manager: BotManager::default(),
73      precursor_manager,
74      military,
75      ranking: Ranking::default(),
76      report: ReportManager::default(),
77      config,
78      stats: WorldStats::new(),
79      chat: Chat::default(),
80
81      emitter: Emitter::default(),
82      save_handle: None,
83      on_next_round: None,
84    };
85
86    world.spawn_precursors()?;
87    world.spawn_bots()?;
88    world.update_ranking()?;
89
90    Ok(world)
91  }
92
93  #[inline]
94  pub fn with_savedata(savedata: Savedata) -> Self {
95    Self::from(savedata)
96  }
97
98  pub fn load(bytes: &[u8]) -> Result<Self> {
99    let savedata = Savedata::read(bytes)?;
100    Ok(Self::with_savedata(savedata))
101  }
102
103  #[inline]
104  pub fn id(&self) -> WorldId {
105    self.config.id()
106  }
107
108  #[inline]
109  pub fn config(&self) -> &WorldConfig {
110    &self.config
111  }
112
113  #[inline]
114  pub fn stats(&self) -> WorldStats {
115    self.stats.clone()
116  }
117
118  #[inline]
119  pub fn report(&self) -> &ReportManager {
120    &self.report
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)
157  where
158    F: FnOnce(Vec<u8>) + Send + Sync + 'static,
159  {
160    self.save_handle = Some(SaveHandle::new(f));
161  }
162
163  pub fn on_next_round<F>(&mut self, f: F)
164  where
165    F: Fn(&mut World) + Send + Sync + 'static,
166  {
167    self.on_next_round = Some(OnNextRound::new(f));
168  }
169}
170
171impl Drop for World {
172  fn drop(&mut self) {
173    self.emit_drop();
174  }
175}
176
177#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
178#[serde(rename_all = "camelCase")]
179pub struct WorldOptions {
180  #[builder(start_fn, into)]
181  pub name: WorldName,
182
183  #[serde(default)]
184  #[builder(default)]
185  pub size: ContinentSize,
186
187  #[serde(default)]
188  #[builder(default)]
189  pub locale: Locale,
190
191  #[serde(default)]
192  #[builder(default)]
193  pub allow_cheats: bool,
194
195  #[serde(default)]
196  #[builder(default)]
197  pub bot_density: BotDensity,
198
199  #[serde(default)]
200  #[builder(default)]
201  pub bot_advanced_start_ratio: BotAdvancedStartRatio,
202}
203
204impl WorldOptions {
205  pub fn to_world(&self) -> Result<World> {
206    World::try_from(self)
207  }
208}
209
210impl TryFrom<&WorldOptions> for World {
211  type Error = Error;
212
213  fn try_from(options: &WorldOptions) -> Result<Self> {
214    Self::new(options)
215  }
216}