perovskite_client 0.0.3

Multiplayer voxel game written in Rust - Game client
Documentation
use arc_swap::ArcSwap;
use cgmath::{vec3, Vector3, Zero};
use perovskite_core::coordinates::{BlockCoordinate, PlayerPositionUpdate};
use rand::{self, Rng};
use std::{sync::Arc, time::Duration};
use tokio::{sync::watch, task::JoinHandle};
use tokio_util::sync::CancellationToken;

use winit::event_loop::EventLoop;

use crate::{
    game_state::{settings::GameSettings, DigTapAction},
    net_client,
    vulkan::VulkanWindow,
};

pub struct Loadtester {
    runtime: tokio::runtime::Runtime,
    workers: Vec<JoinHandle<()>>,
    vk_ctx: Arc<VulkanWindow>,
    settings: Arc<ArcSwap<GameSettings>>,
    cancel: CancellationToken,
}
impl Loadtester {
    pub fn new() -> Self {
        let settings = Arc::new(ArcSwap::new(GameSettings::default().into()));
        Self {
            runtime: tokio::runtime::Builder::new_multi_thread()
                .enable_all()
                .build()
                .unwrap(),
            workers: vec![],
            vk_ctx: Arc::new(
                VulkanWindow::create(
                    Box::<EventLoop<()>>::leak(Box::new(EventLoop::new())),
                    &settings,
                )
                .unwrap(),
            ),
            settings,
            cancel: CancellationToken::new(),
        }
    }
    pub fn start_worker(&mut self, addr: String, username: String) {
        let vk_ctx = self.vk_ctx.clone();
        let cancel = self.cancel.clone();
        let settings = self.settings.clone();
        self.workers.push(self.runtime.spawn(async move {
            let mut progress = watch::channel((0.0, "Connecting to server...".to_string()));
            let cs = net_client::connect_game(
                addr,
                username,
                "test_pass".to_string(),
                true,
                settings,
                &vk_ctx,
                &mut progress.0,
            )
            .await
            .unwrap();
            log::info!("Loadtest worker connected");
            {
                let mut rng = rand::thread_rng();
                cs.physics_state.lock().set_position(vec3(
                    rng.gen_range(-1000000.0..1000000.0),
                    rng.gen_range(-1000000.0..1000000.0),
                    rng.gen_range(-1000000.0..1000000.0),
                ));
            }
            while !cancel.is_cancelled() {
                tokio::time::sleep(Duration::from_secs_f32(0.1)).await;
                let pos = {
                    let mut phys = cs.physics_state.lock();
                    let mut rng = rand::thread_rng();
                    let pos = phys.pos();
                    let new_pos = pos
                        + vec3(
                            rng.gen_range(-0.5..0.5),
                            rng.gen_range(-0.5..0.5),
                            rng.gen_range(-0.5..0.5),
                        );
                    phys.set_position(new_pos);
                    pos
                };
                cs.actions
                    .send(crate::game_state::GameAction::Dig(DigTapAction {
                        target: BlockCoordinate::new(pos.x as i32, pos.y as i32, pos.z as i32),
                        prev: None,
                        item_slot: 0,
                        player_pos: PlayerPositionUpdate {
                            position: pos,
                            velocity: Vector3::zero(),
                            face_direction: (0., 0.),
                        },
                    }))
                    .await
                    .unwrap();
            }
            panic!();
        }))
    }
}
impl Default for Loadtester {
    fn default() -> Self {
        Self::new()
    }
}