use std::cell::Cell;
use std::collections::HashMap;
use std::sync::{Arc, OnceLock, RwLock};
pub use yog_registry::{Loot, LootAdd, LootModifier, LootScale, LootStack};
use yog_core::Server;
pub(crate) type LootFunction = Arc<dyn Fn(&dyn Server, &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(srv: &dyn Server, modifier: &LootModifier, loot: &mut Loot) {
let functions = functions().read().map(|f| f.clone()).unwrap_or_default();
modifier.apply(loot, &mut random, &mut |name, stack, loot| match functions.get(name) {
Some(f) => f(srv, stack, loot),
None => crate::error!("loot modifier {}: no loot function {name} (registry.loot_function)", modifier.id),
});
}