use std::cell::Cell;
use std::collections::HashMap;
use yog_sync::{Arc, OnceLock, RwLock};
pub use yog_registry::{Loot, LootAdd, LootModifier, LootScale, LootStack};
pub(crate) type LootFunction = Arc<dyn Fn(&mut LootStack, &Loot) + Send + Sync>;
pub(crate) fn functions() -> &'static RwLock<HashMap<String, LootFunction>> {
static FUNCTIONS: OnceLock<RwLock<HashMap<String, LootFunction>>> = OnceLock::new();
FUNCTIONS.get_or_init(Default::default)
}
thread_local! {
static SEED: Cell<u64> = Cell::new({
let t = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map_or(0, |d| d.as_nanos() as u64);
t ^ 0x9e37_79b9_7f4a_7c15
});
}
pub fn random() -> f64 {
SEED.with(|s| {
let mut x = s.get() | 1;
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
s.set(x);
(x.wrapping_mul(0x2545_f491_4f6c_dd1d) >> 11) as f64 / (1u64 << 53) as f64
})
}
pub(crate) fn apply(modifier: &LootModifier, loot: &mut Loot) {
let functions = functions().read().clone();
modifier.apply(
loot,
&mut random,
&mut |name, stack, loot| match functions.get(name) {
Some(f) => f(stack, loot),
None => crate::error!(
"loot modifier {}: no loot function {name} (registry.loot_function)",
modifier.id
),
},
);
}