bones_framework/networking/
random.rs

1//! Global, deterministic RNG generation resource.
2
3use crate::prelude::*;
4#[cfg(feature = "scripting")]
5use crate::{
6    prelude::bindings::EcsRef,
7    scripting::lua::{
8        bindings::SchemaLuaEcsRefMetatable,
9        piccolo::{self as lua, Callback},
10    },
11};
12use core::ops::RangeBounds;
13use std::collections::VecDeque;
14use turborand::prelude::*;
15
16/// Resource that produces deterministic pseudo-random numbers/strings.
17///
18/// Access in a system with [`Res<RngGenerator>`].
19#[derive(Clone, HasSchema)]
20#[type_data(SchemaLuaEcsRefMetatable(lua_metatable))]
21pub struct RngGenerator {
22    internal_generator: AtomicRng,
23}
24
25impl Default for RngGenerator {
26    /// Creates a new `RngGenerator`, initializing it with a harcoded seed
27    fn default() -> Self {
28        Self {
29            internal_generator: AtomicRng::with_seed(7),
30        }
31    }
32}
33
34impl RngGenerator {
35    /// Creates a new `RngGenerator`, initializing it with the provided seed
36    pub fn new(seed: u64) -> Self {
37        Self {
38            internal_generator: AtomicRng::with_seed(seed),
39        }
40    }
41
42    /// Generate a random u8
43    pub fn gen_u8(&mut self) -> u8 {
44        self.internal_generator.gen_u8()
45    }
46
47    /// Generate a random u8 within the given range
48    pub fn gen_u8_range<R: RangeBounds<u8>>(&mut self, range: R) -> u8 {
49        self.internal_generator.u8(range)
50    }
51
52    /// Generate a random i8
53    pub fn gen_i8(&mut self) -> i8 {
54        self.internal_generator.gen_i8()
55    }
56
57    /// Generate a random i8 within the given range
58    pub fn gen_i8_range<R: RangeBounds<i8>>(&mut self, range: R) -> i8 {
59        self.internal_generator.i8(range)
60    }
61
62    /// Generate a random u16
63    pub fn gen_u16(&mut self) -> u16 {
64        self.internal_generator.gen_u16()
65    }
66
67    /// Generate a random u16 within the given range
68    pub fn gen_u16_range<R: RangeBounds<u16>>(&mut self, range: R) -> u16 {
69        self.internal_generator.u16(range)
70    }
71
72    /// Generate a random i16
73    pub fn gen_i16(&mut self) -> i16 {
74        self.internal_generator.gen_i16()
75    }
76
77    /// Generate a random i16 within the given range
78    pub fn gen_i16_range<R: RangeBounds<i16>>(&mut self, range: R) -> i16 {
79        self.internal_generator.i16(range)
80    }
81
82    /// Generate a random u32
83    pub fn gen_u32(&mut self) -> u32 {
84        self.internal_generator.gen_u32()
85    }
86
87    /// Generate a random u32 within the given range
88    pub fn gen_u32_range<R: RangeBounds<u32>>(&mut self, range: R) -> u32 {
89        self.internal_generator.u32(range)
90    }
91
92    /// Generate a random i32
93    pub fn gen_i32(&mut self) -> i32 {
94        self.internal_generator.gen_i32()
95    }
96
97    /// Generate a random i32 within the given range
98    pub fn gen_i32_range<R: RangeBounds<i32>>(&mut self, range: R) -> i32 {
99        self.internal_generator.i32(range)
100    }
101
102    /// Generate a random u64
103    pub fn gen_u64(&mut self) -> u64 {
104        self.internal_generator.gen_u64()
105    }
106
107    /// Generate a random u64 within the given range
108    pub fn gen_u64_range<R: RangeBounds<u64>>(&mut self, range: R) -> u64 {
109        self.internal_generator.u64(range)
110    }
111
112    /// Generate a random i64
113    pub fn gen_i64(&mut self) -> i64 {
114        self.internal_generator.gen_i64()
115    }
116
117    /// Generate a random i64 within the given range
118    pub fn gen_i64_range<R: RangeBounds<i64>>(&mut self, range: R) -> i64 {
119        self.internal_generator.i64(range)
120    }
121
122    /// Generate a random usize
123    pub fn gen_usize(&mut self) -> usize {
124        self.internal_generator.gen_usize()
125    }
126
127    /// Generate a random usize within the given range
128    pub fn gen_usize_range<R: RangeBounds<usize>>(&mut self, range: R) -> usize {
129        self.internal_generator.usize(range)
130    }
131
132    /// Generate a random isize
133    pub fn gen_isize(&mut self) -> isize {
134        self.internal_generator.gen_isize()
135    }
136
137    /// Generate a random isize within the given range
138    pub fn gen_isize_range<R: RangeBounds<isize>>(&mut self, range: R) -> isize {
139        self.internal_generator.isize(range)
140    }
141
142    /// Generate a random f32
143    pub fn gen_f32(&mut self) -> f32 {
144        self.internal_generator.f32()
145    }
146
147    /// Generate a random f32 within the given range
148    pub fn gen_f32_range<R: RangeBounds<f32>>(&mut self, range: R) -> f32 {
149        let start = match range.start_bound() {
150            std::ops::Bound::Included(&n) => n,
151            std::ops::Bound::Excluded(&n) => n,
152            std::ops::Bound::Unbounded => 0.0,
153        };
154        let end = match range.end_bound() {
155            std::ops::Bound::Included(&n) => n,
156            std::ops::Bound::Excluded(&n) => n,
157            std::ops::Bound::Unbounded => 1.0,
158        };
159        loop {
160            let n = self.gen_f32();
161            if n >= start && n <= end {
162                return n;
163            }
164        }
165    }
166
167    /// Generate a random f64
168    pub fn gen_f64(&mut self) -> f64 {
169        self.internal_generator.f64()
170    }
171
172    /// Generate a random f64 within the given range
173    pub fn gen_f64_range<R: RangeBounds<f64>>(&mut self, range: R) -> f64 {
174        let start = match range.start_bound() {
175            std::ops::Bound::Included(&n) => n,
176            std::ops::Bound::Excluded(&n) => n,
177            std::ops::Bound::Unbounded => 0.0,
178        };
179        let end = match range.end_bound() {
180            std::ops::Bound::Included(&n) => n,
181            std::ops::Bound::Excluded(&n) => n,
182            std::ops::Bound::Unbounded => 1.0,
183        };
184        loop {
185            let n = self.gen_f64();
186            if n >= start && n <= end {
187                return n;
188            }
189        }
190    }
191
192    /// Generate a random bool
193    pub fn gen_bool(&mut self) -> bool {
194        self.internal_generator.bool()
195    }
196
197    /// Generate a random Vec2
198    pub fn gen_vec2(&mut self) -> Vec2 {
199        Vec2::new(self.gen_f32(), self.gen_f32())
200    }
201
202    /// Generate a random Vec2 within the given ranges for each component
203    pub fn gen_vec2_range<R1: RangeBounds<f32>, R2: RangeBounds<f32>>(
204        &mut self,
205        x_range: R1,
206        y_range: R2,
207    ) -> Vec2 {
208        Vec2::new(self.gen_f32_range(x_range), self.gen_f32_range(y_range))
209    }
210
211    /// Generate a random Vec3
212    pub fn gen_vec3(&mut self) -> Vec3 {
213        Vec3::new(self.gen_f32(), self.gen_f32(), self.gen_f32())
214    }
215
216    /// Generate a random Vec3 within the given ranges for each component
217    pub fn gen_vec3_range<R1: RangeBounds<f32>, R2: RangeBounds<f32>, R3: RangeBounds<f32>>(
218        &mut self,
219        x_range: R1,
220        y_range: R2,
221        z_range: R3,
222    ) -> Vec3 {
223        Vec3::new(
224            self.gen_f32_range(x_range),
225            self.gen_f32_range(y_range),
226            self.gen_f32_range(z_range),
227        )
228    }
229
230    /// Shuffle a Vec in place
231    pub fn shuffle_vec<T>(&mut self, vec: &mut [T]) {
232        self.internal_generator.shuffle(vec);
233    }
234
235    /// Shuffle an SVec in place
236    pub fn shuffle_svec<T: HasSchema>(&mut self, svec: &mut SVec<T>) {
237        for i in (1..svec.len()).rev() {
238            let j = self.gen_usize_range(0..=i);
239            svec.swap(i, j);
240        }
241    }
242
243    /// Shuffle a VecDeque in place
244    pub fn shuffle_vecdeque<T>(&mut self, deque: &mut VecDeque<T>) {
245        let len = deque.len();
246        for i in (1..len).rev() {
247            let j = self.gen_usize_range(0..=i);
248            deque.swap(i, j);
249        }
250    }
251
252    /// Generates a random `char` in ranges a-z and A-Z.
253    pub fn gen_alphabetic(&mut self) -> char {
254        self.internal_generator.alphabetic()
255    }
256
257    /// Generates a random `char` in ranges a-z, A-Z and 0-9.
258    pub fn gen_alphanumeric(&mut self) -> char {
259        self.internal_generator.alphanumeric()
260    }
261
262    /// Generates a random `char` in the range a-z.
263    pub fn gen_lowercase(&mut self) -> char {
264        self.internal_generator.lowercase()
265    }
266
267    /// Generates a random `char` in the range A-Z.
268    pub fn gen_uppercase(&mut self) -> char {
269        self.internal_generator.uppercase()
270    }
271
272    /// Generate a random digit in the given `radix`.
273    /// Digits are represented by `char`s in ranges 0-9 and a-z.
274    ///
275    /// # Panics
276    /// Panics if the `radix` is zero or greater than 36.
277    pub fn gen_digit(&mut self, radix: u8) -> char {
278        self.internal_generator.digit(radix)
279    }
280
281    /// Generates a random `char` in the given range.
282    ///
283    /// # Panics
284    /// Panics if the range is empty.
285    pub fn gen_char<R: RangeBounds<char>>(&mut self, bounds: R) -> char {
286        self.internal_generator.char(bounds)
287    }
288
289    /// Generate a random printable ASCII character
290    pub fn gen_random_ascii_char(&mut self) -> char {
291        self.gen_u8_range(33..=126) as char
292    }
293
294    /// Generate a random ASCII string of the specified length
295    pub fn gen_random_ascii_string(&mut self, length: u64) -> String {
296        (0..length).map(|_| self.gen_random_ascii_char()).collect()
297    }
298
299    /// Returns a boolean, where `success_rate` represents the chance to return a true value,
300    /// with 0.0 being no chance and 1.0 will always return true.
301    pub fn gen_chance(&mut self, success_rate: f64) -> bool {
302        let clamped_rate = success_rate.clamp(0.0, 1.0);
303        self.internal_generator.chance(clamped_rate)
304    }
305
306    /// Samples a random item from a slice of values.
307    pub fn gen_sample<'a, T>(&mut self, list: &'a [T]) -> Option<&'a T> {
308        self.internal_generator.sample(list)
309    }
310
311    /// Samples a random item from an iterator of values.
312    pub fn gen_sample_iter<T: Iterator>(&mut self, list: T) -> Option<T::Item> {
313        self.internal_generator.sample_iter(list)
314    }
315
316    /// Samples a random &mut item from a slice of values.
317    pub fn gen_sample_mut<'a, T>(&mut self, list: &'a mut [T]) -> Option<&'a mut T> {
318        self.internal_generator.sample_mut(list)
319    }
320
321    /// Samples multiple unique items from a slice of values.
322    pub fn gen_sample_multiple<'a, T>(&mut self, list: &'a [T], amount: usize) -> Vec<&'a T> {
323        self.internal_generator.sample_multiple(list, amount)
324    }
325
326    /// Samples multiple unique items from a mutable slice of values.
327    pub fn gen_sample_multiple_mut<'a, T>(
328        &mut self,
329        list: &'a mut [T],
330        amount: usize,
331    ) -> Vec<&'a mut T> {
332        self.internal_generator.sample_multiple_mut(list, amount)
333    }
334
335    /// Samples multiple unique items from an iterator of values.
336    pub fn gen_sample_multiple_iter<T: Iterator>(
337        &mut self,
338        list: T,
339        amount: usize,
340    ) -> Vec<T::Item> {
341        self.internal_generator.sample_multiple_iter(list, amount)
342    }
343
344    /// Stochastic Acceptance implementation of Roulette Wheel weighted selection.
345    pub fn gen_weighted_sample<'a, T, F>(
346        &mut self,
347        list: &'a [T],
348        weight_sampler: F,
349    ) -> Option<&'a T>
350    where
351        F: Fn((&T, usize)) -> f64,
352    {
353        self.internal_generator
354            .weighted_sample(list, weight_sampler)
355    }
356
357    /// Stochastic Acceptance implementation of Roulette Wheel weighted selection for mutable references.
358    pub fn gen_weighted_sample_mut<'a, T, F>(
359        &mut self,
360        list: &'a mut [T],
361        weight_sampler: F,
362    ) -> Option<&'a mut T>
363    where
364        F: Fn((&T, usize)) -> f64,
365    {
366        self.internal_generator
367            .weighted_sample_mut(list, weight_sampler)
368    }
369}
370
371#[cfg(feature = "scripting")]
372fn lua_metatable(ctx: lua::Context) -> lua::Table {
373    let metatable = lua::Table::new(&ctx);
374
375    let f32_fn = ctx.registry().stash(
376        &ctx,
377        Callback::from_fn(&ctx, |ctx, _fuel, mut stack| {
378            let this: &EcsRef = stack.consume(ctx)?;
379            let mut b = this.borrow_mut();
380            let rng_generator = b.schema_ref_mut()?.cast_into_mut::<RngGenerator>();
381            let n = rng_generator.internal_generator.f32();
382            stack.replace(ctx, n);
383            Ok(lua::CallbackReturn::Return)
384        }),
385    );
386    metatable
387        .set(
388            ctx,
389            "__index",
390            Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
391                let (_this, key): (lua::Value, lua::String) = stack.consume(ctx)?;
392
393                #[allow(clippy::single_match)]
394                match key.as_bytes() {
395                    b"f32" => {
396                        stack.push_front(ctx.registry().fetch(&f32_fn).into());
397                    }
398                    _ => (),
399                }
400                Ok(lua::CallbackReturn::Return)
401            }),
402        )
403        .unwrap();
404
405    metatable
406}