use vtable_rs::VPtr;
use shared::{OwnedPtr, Subclass, Superclass};
#[vtable_rs::vtable]
pub trait CSRandVmt {
fn destructor(&mut self, should_free: bool);
fn next_uint(&mut self) -> u32;
fn next_long(&mut self) -> u64;
}
#[repr(C)]
#[derive(Superclass)]
#[superclass(children(CSRandXorshift, CSRandSFMT))]
pub struct CSRand {
pub vftable: VPtr<dyn CSRandVmt, Self>,
}
impl CSRand {
pub fn next_uint(&mut self) -> u32 {
(self.vftable.next_uint)(self)
}
pub fn next_long(&mut self) -> u64 {
(self.vftable.next_long)(self)
}
pub fn rand_uint_range(&mut self, min: u32, max: u32) -> u32 {
let range = (max - min) + 1;
min + (self.next_uint() % range)
}
pub fn rand_int_range(&mut self, min: i32, max: i32) -> i32 {
let range = (max - min) + 1;
if range < 0 {
return min;
}
min + (self.next_uint() as i32 % range)
}
pub fn rand_uint_up_to(&mut self, n: u32) -> u32 {
if n == 0 {
return 0;
}
let v = self.next_uint();
v % (n + 1)
}
pub fn rand_float_0_1(&mut self) -> f32 {
let u = self.next_uint();
let mantissa = u >> 9; let float_bits = 0x3f800000 | mantissa; f32::from_bits(float_bits) - 1.0 }
pub fn rand_float_open_0_1(&mut self) -> f32 {
let u = self.next_uint();
let temp = (u >> 9) + 1; let carry = temp >> 23; let mantissa = temp & 0x7fffff; let float_bits = 0x3f800000 + carry + mantissa;
f32::from_bits(float_bits) - 1.0 }
pub fn rand_float_0_1_inclusive(&mut self) -> f32 {
let u = self.next_uint();
let mantissa = u >> 9; let extra_bit = (u >> 8) & 1; let float_bits = 0x3f800000 + mantissa + extra_bit;
f32::from_bits(float_bits) - 1.0 }
pub fn rand_float_range(&mut self, min: f32, max: f32) -> f32 {
let range = max - min;
if range <= 0.0 {
return min;
}
range * self.rand_float_0_1() + min
}
pub fn rand_float_open_range(&mut self, min: f32, max: f32) -> f32 {
let range = max - min;
if range <= 0.0 {
return min;
}
range * self.rand_float_open_0_1() + min
}
}
#[repr(C)]
pub struct DLRandomGeneratorXorshift {
pub state: [u32; 4],
}
#[repr(C)]
#[derive(Subclass)]
#[subclass(base = CSRand)]
pub struct CSRandXorshift {
pub vftable: VPtr<dyn CSRandVmt, Self>,
pub xorshift_state: DLRandomGeneratorXorshift,
}
impl CSRandXorshift {
pub fn new(seed: u64) -> Self {
let mut state = [0u32; 4];
let mut lcg_state = (seed & 0xffff_ffff) * 0x5deece66d + 0xb;
for item in state.iter_mut() {
*item = (lcg_state >> 32) as u32;
lcg_state = lcg_state.wrapping_mul(0x5deece66d).wrapping_add(0xb);
}
CSRandXorshift {
vftable: VPtr::<dyn CSRandVmt, CSRandXorshift>::new(),
xorshift_state: DLRandomGeneratorXorshift { state },
}
}
}
impl CSRandVmt for CSRandXorshift {
extern "C" fn destructor(&mut self, _should_free: bool) {}
extern "C" fn next_uint(&mut self) -> u32 {
let s1 = self.xorshift_state.state[0];
let s2 = self.xorshift_state.state[1];
let s3 = self.xorshift_state.state[2];
let s4 = self.xorshift_state.state[3];
let mut t = s1 ^ (s1 << 11);
t ^= t >> 8;
let new_s4 = s4 ^ (s4 >> 11) ^ t ^ s2;
self.xorshift_state.state[0] = s2;
self.xorshift_state.state[1] = s3;
self.xorshift_state.state[2] = s4;
self.xorshift_state.state[3] = new_s4;
new_s4
}
extern "C" fn next_long(&mut self) -> u64 {
let s1 = self.xorshift_state.state[0];
let s2 = self.xorshift_state.state[1];
let s3 = self.xorshift_state.state[2];
let s4 = self.xorshift_state.state[3];
let mut t1 = s1 ^ (s1 << 11);
t1 ^= t1 >> 8;
let new_s3 = s4 ^ (s4 >> 11) ^ t1 ^ s2;
let mut t2 = s2 ^ (s2 << 11);
t2 ^= t2 >> 8;
let new_s4 = new_s3 ^ (new_s3 >> 11) ^ t2 ^ s3;
self.xorshift_state.state[0] = s2;
self.xorshift_state.state[1] = s3;
self.xorshift_state.state[2] = new_s3;
self.xorshift_state.state[3] = new_s4;
((new_s3 as u64) << 32) | (new_s4 as u64)
}
}
#[repr(C)]
#[derive(Subclass)]
pub struct CSRandSFMT {
pub base: CSRand,
unk8: usize,
pub state: DLRandomGeneratorSFMT,
}
#[repr(C)]
pub struct DLRandomGeneratorSFMT {
pub state: [u32; 624],
pub index: u32,
pub mt_state_ptr: OwnedPtr<u32>,
pub mt_state_end_ptr: OwnedPtr<u32>,
}
impl CSRandVmt for CSRandSFMT {
extern "C" fn destructor(&mut self, _should_free: bool) {}
extern "C" fn next_uint(&mut self) -> u32 {
unimplemented!()
}
extern "C" fn next_long(&mut self) -> u64 {
unimplemented!()
}
}