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