Skip to main content

nil_core/npc/bot/
mod.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use crate::error::{Error, Result};
5use crate::ethic::Ethics;
6use crate::resources::Resources;
7use crate::resources::influence::Influence;
8use crate::ruler::Ruler;
9use derive_more::{Display, From, Into};
10use serde::{Deserialize, Serialize};
11use std::borrow::{Borrow, Cow};
12use std::collections::HashMap;
13use std::ops::Deref;
14use std::sync::Arc;
15
16#[derive(Clone, Debug, Default, Deserialize, Serialize)]
17#[serde(rename_all = "camelCase")]
18pub struct BotManager(HashMap<BotId, Bot>);
19
20impl BotManager {
21  pub(crate) fn manage(&mut self, id: BotId) -> Result<()> {
22    if self.0.contains_key(&id) {
23      return Err(Error::BotAlreadySpawned(id));
24    }
25
26    self.0.insert(id.clone(), Bot::new(id));
27
28    Ok(())
29  }
30
31  pub fn bot(&self, id: &BotId) -> Result<&Bot> {
32    self
33      .0
34      .get(id)
35      .ok_or_else(|| Error::BotNotFound(id.clone()))
36  }
37
38  pub(crate) fn bot_mut(&mut self, id: &BotId) -> Result<&mut Bot> {
39    self
40      .0
41      .get_mut(id)
42      .ok_or_else(|| Error::BotNotFound(id.clone()))
43  }
44
45  pub fn bots(&self) -> impl Iterator<Item = &Bot> {
46    self.0.values()
47  }
48}
49
50#[derive(Clone, Debug, Deserialize, Serialize)]
51#[serde(rename_all = "camelCase")]
52#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
53pub struct Bot {
54  id: BotId,
55  ethics: Ethics,
56  resources: Resources,
57  influence: Influence,
58}
59
60impl Bot {
61  pub(crate) fn new(id: BotId) -> Self {
62    Self {
63      id,
64      ethics: Ethics::random(),
65      resources: Resources::BOT.clone(),
66      influence: Influence::MIN,
67    }
68  }
69
70  #[inline]
71  pub fn id(&self) -> BotId {
72    self.id.clone()
73  }
74
75  #[inline]
76  pub fn ethics(&self) -> &Ethics {
77    &self.ethics
78  }
79
80  #[inline]
81  pub(crate) fn ethics_mut(&mut self) -> &mut Ethics {
82    &mut self.ethics
83  }
84
85  #[inline]
86  pub fn resources(&self) -> &Resources {
87    &self.resources
88  }
89
90  pub(crate) fn resources_mut(&mut self) -> &mut Resources {
91    &mut self.resources
92  }
93
94  #[inline]
95  pub fn influence(&self) -> Influence {
96    self.influence
97  }
98}
99
100#[derive(Debug, Display, PartialEq, Eq, Hash, From, Into, Deserialize, Serialize)]
101#[from(String, &str, Arc<str>, Box<str>, Cow<'_, str>)]
102#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
103pub struct BotId(Arc<str>);
104
105impl Clone for BotId {
106  fn clone(&self) -> Self {
107    Self(Arc::clone(&self.0))
108  }
109}
110
111impl AsRef<str> for BotId {
112  fn as_ref(&self) -> &str {
113    self.0.as_str()
114  }
115}
116
117impl Deref for BotId {
118  type Target = str;
119
120  fn deref(&self) -> &Self::Target {
121    self.0.as_str()
122  }
123}
124
125impl Borrow<str> for BotId {
126  fn borrow(&self) -> &str {
127    self.0.as_str()
128  }
129}
130
131impl From<BotId> for String {
132  fn from(value: BotId) -> Self {
133    String::from(value.0.as_ref())
134  }
135}
136
137impl PartialEq<Ruler> for BotId {
138  fn eq(&self, other: &Ruler) -> bool {
139    if let Ruler::Bot { id } = other { self.eq(id) } else { false }
140  }
141}
142
143#[derive(Clone, Debug, Deserialize, Serialize)]
144#[serde(rename_all = "camelCase")]
145#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
146pub struct PublicBot {
147  id: BotId,
148}
149
150impl From<&Bot> for PublicBot {
151  fn from(bot: &Bot) -> Self {
152    Self { id: bot.id.clone() }
153  }
154}