1use std::cell::Cell;
8use std::collections::HashMap;
9use std::sync::{Arc, OnceLock, RwLock};
10
11pub use yog_registry::{Loot, LootAdd, LootModifier, LootScale, LootStack};
12
13use yog_core::Server;
14
15pub(crate) type LootFunction = Arc<dyn Fn(&dyn Server, &mut LootStack, &Loot) + Send + Sync>;
17
18pub(crate) fn functions() -> &'static RwLock<HashMap<String, LootFunction>> {
20 static FUNCTIONS: OnceLock<RwLock<HashMap<String, LootFunction>>> = OnceLock::new();
21 FUNCTIONS.get_or_init(Default::default)
22}
23
24thread_local! {
25 static SEED: Cell<u64> = Cell::new({
26 let t = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map_or(0, |d| d.as_nanos() as u64);
27 t ^ 0x9e37_79b9_7f4a_7c15
28 });
29}
30
31pub fn random() -> f64 {
33 SEED.with(|s| {
34 let mut x = s.get() | 1;
36 x ^= x >> 12;
37 x ^= x << 25;
38 x ^= x >> 27;
39 s.set(x);
40 (x.wrapping_mul(0x2545_f491_4f6c_dd1d) >> 11) as f64 / (1u64 << 53) as f64
41 })
42}
43
44pub(crate) fn apply(srv: &dyn Server, modifier: &LootModifier, loot: &mut Loot) {
46 let functions = functions().read().map(|f| f.clone()).unwrap_or_default();
47 modifier.apply(loot, &mut random, &mut |name, stack, loot| match functions.get(name) {
48 Some(f) => f(srv, stack, loot),
49 None => crate::error!("loot modifier {}: no loot function {name} (registry.loot_function)", modifier.id),
50 });
51}