pub mod robot;
use crate::robot_service::robot::Robot;
use crate::services::LotteryInfo;
use crate::static_def::{game_slot_bet_ratios, get_game_setting, CONFIG, DATABASE};
use anyhow::Result;
use aqueue::Actor;
use rand::prelude::IndexedRandom;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha20Rng;
use std::time::Instant;
pub trait IRobotService {
async fn robot_seat(
&self,
robot_id: i32,
nickname: String,
avatar_id: i32,
) -> Option<(usize, usize)>;
async fn robot_remove_seat(&self, table_id: usize, seat_index: usize) -> Result<()>;
async fn get_lottery_info(&self) -> Vec<LotteryInfo>;
}
pub struct RobotManager {
rand: ChaCha20Rng,
robots: Vec<Robot>,
}
impl Default for RobotManager {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl RobotManager {
pub fn new() -> Self {
let rand = ChaCha20Rng::from_os_rng();
Self {
rand,
robots: vec![],
}
}
async fn init(&mut self, robot_service: &impl IRobotService) -> Result<()> {
if get_game_setting().robot_max == 0 {
log::info!("not enable robot_service");
return Ok(());
}
if get_game_setting().robot_max < get_game_setting().robot_min {
log::error!("robot_service max < min");
return Ok(());
}
let robot_size = self
.rand
.random_range(get_game_setting().robot_min..=get_game_setting().robot_max);
let max_vip_level = DATABASE.get_max_vip_level().await?;
self.robots = (0..robot_size)
.map(|_| {
let id = self.rand.random_range(10000000..100000000);
let seating_time = self.rand.random_range(
CONFIG.game.robot_seating_min_time..=CONFIG.game.robot_seating_max_time,
);
let leave_time = self.rand.random_range(
CONFIG.game.robot_leave_min_time..=CONFIG.game.robot_seating_max_time,
);
let spin_time = self.rand.random_range(
CONFIG.game.robot_spin_min_time..=CONFIG.game.robot_spin_max_time,
);
Robot {
id,
nickname: id.to_string(),
avatar_id: self.rand.random_range(0..10),
vip_level: self.rand.random_range(0..=max_vip_level),
bet_info: game_slot_bet_ratios()
.choose(&mut self.rand)
.unwrap()
.clone(),
seating_time,
leave_time,
spin_time,
last_seating_time: Instant::now(),
last_leave_time: Instant::now(),
last_spin_time_time: Instant::now(),
state: Default::default(),
}
})
.collect();
if robot_service.get_lottery_info().await.is_empty() {
log::debug!(
"robot_service not found lottery id by:{}",
get_game_setting().game_id
);
}
log::debug!("robot_service init ok size:{robot_size}");
Ok(())
}
#[inline]
async fn update(&mut self, robot_service: &impl IRobotService) -> Result<()> {
let lottery_info = robot_service.get_lottery_info().await;
for robot in self.robots.iter_mut() {
robot
.update(&mut self.rand, &lottery_info, robot_service)
.await?;
}
Ok(())
}
}
pub trait IRobotManager {
async fn init(&self, robot_service: &impl IRobotService) -> Result<()>;
async fn update(&self, robot_service: &impl IRobotService) -> Result<()>;
}
impl IRobotManager for Actor<RobotManager> {
#[inline]
async fn init(&self, robot_service: &impl IRobotService) -> Result<()> {
self.inner_call(|inner| async move { inner.get_mut().init(robot_service).await })
.await
}
#[inline]
async fn update(&self, robot_service: &impl IRobotService) -> Result<()> {
self.inner_call(|inner| async move { inner.get_mut().update(robot_service).await })
.await
}
}