steel_registry/
game_rules.rs1use crate::{RegistryEntry, RegistryExt};
2use rustc_hash::FxHashMap;
3use serde::{Deserialize, Serialize};
4use steel_utils::Identifier;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum GameRuleCategory {
9 Chat,
10 Drops,
11 Misc,
12 Mobs,
13 Player,
14 Spawning,
15 Updates,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum GameRuleType {
21 Bool,
22 Int,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
27#[serde(untagged)]
28pub enum GameRuleValue {
29 Bool(bool),
30 Int(i32),
31}
32
33impl GameRuleValue {
34 #[must_use]
36 pub fn as_bool(&self) -> Option<bool> {
37 match self {
38 Self::Bool(b) => Some(*b),
39 Self::Int(_) => None,
40 }
41 }
42
43 #[must_use]
45 pub fn as_int(&self) -> Option<i32> {
46 match self {
47 Self::Bool(_) => None,
48 Self::Int(i) => Some(*i),
49 }
50 }
51
52 #[must_use]
54 pub fn is_bool(&self) -> bool {
55 matches!(self, Self::Bool(_))
56 }
57
58 #[must_use]
60 pub fn is_int(&self) -> bool {
61 matches!(self, Self::Int(_))
62 }
63
64 #[must_use]
66 pub fn matches_type(&self, value_type: GameRuleType) -> bool {
67 matches!(
68 (self, value_type),
69 (Self::Bool(_), GameRuleType::Bool) | (Self::Int(_), GameRuleType::Int)
70 )
71 }
72}
73
74impl std::fmt::Display for GameRuleValue {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 match self {
77 Self::Bool(b) => write!(f, "{b}"),
78 Self::Int(i) => write!(f, "{i}"),
79 }
80 }
81}
82
83#[derive(Debug)]
85pub struct GameRule {
86 pub key: Identifier,
88 pub category: GameRuleCategory,
90 pub value_type: GameRuleType,
92 pub default_value: GameRuleValue,
94 pub min_value: Option<i32>,
96 pub max_value: Option<i32>,
98}
99
100pub type GameRuleRef = &'static GameRule;
101
102pub struct GameRuleRegistry {
103 game_rules_by_id: Vec<GameRuleRef>,
104 game_rules_by_key: FxHashMap<Identifier, usize>,
105 allows_registering: bool,
106}
107
108impl GameRuleRegistry {
109 #[must_use]
110 pub fn new() -> Self {
111 Self {
112 game_rules_by_id: Vec::new(),
113 game_rules_by_key: FxHashMap::default(),
114 allows_registering: true,
115 }
116 }
117}
118
119crate::impl_standard_methods!(
120 GameRuleRegistry,
121 GameRuleRef,
122 game_rules_by_id,
123 game_rules_by_key,
124 allows_registering
125);
126
127crate::impl_registry!(
128 GameRuleRegistry,
129 GameRule,
130 game_rules_by_id,
131 game_rules_by_key,
132 game_rules
133);
134
135#[derive(Debug, Clone, Default)]
140pub struct GameRuleValues {
141 values: Vec<GameRuleValue>,
143}
144
145impl GameRuleValues {
146 #[must_use]
148 pub fn new(registry: &GameRuleRegistry) -> Self {
149 let values = registry
150 .iter()
151 .map(|(_, rule)| rule.default_value)
152 .collect();
153 Self { values }
154 }
155
156 #[must_use]
158 pub fn get(&self, rule: GameRuleRef, _registry: &GameRuleRegistry) -> GameRuleValue {
159 let id = rule.id();
160 self.values[id]
161 }
162
163 pub fn set(
168 &mut self,
169 rule: GameRuleRef,
170 value: GameRuleValue,
171 _registry: &GameRuleRegistry,
172 ) -> bool {
173 if !value.matches_type(rule.value_type) {
174 return false;
175 }
176 if let GameRuleValue::Int(v) = value {
178 if let Some(min) = rule.min_value
179 && v < min
180 {
181 return false;
182 }
183 if let Some(max) = rule.max_value
184 && v > max
185 {
186 return false;
187 }
188 }
189 let id = rule.id();
190 self.values[id] = value;
191 true
192 }
193
194 #[must_use]
196 pub fn get_by_name(&self, name: &str, registry: &GameRuleRegistry) -> Option<GameRuleValue> {
197 let key = Identifier::vanilla(name.to_string());
198 let id = registry.id_from_key(&key)?;
199 self.values.get(id).copied()
200 }
201
202 pub fn set_by_name(
207 &mut self,
208 name: &str,
209 value: GameRuleValue,
210 registry: &GameRuleRegistry,
211 ) -> bool {
212 let key = Identifier::vanilla(name.to_string());
213 if let Some(rule) = registry.by_key(&key) {
214 self.set(rule, value, registry)
215 } else {
216 false
217 }
218 }
219}