blizzard_engine/core/
network_application.rs

1//! # Network Application
2//!
3//! This application runs the game, with messaging capabilities that come from the server.
4
5use std::sync::mpsc::Receiver;
6use std::sync::{Arc, Mutex};
7use std::thread;
8use std::time::{Duration, Instant};
9
10use crate::core::logger::initialize_logging;
11use crate::game::Game;
12
13/// Application that runs the app.
14/// App will handle all engine features.
15/// Missing:
16/// * Renderer
17/// * Window abstraction
18/// * Event handler
19/// * Many, many more features...
20///
21/// # Type definitions
22/// * T: Game type
23/// * K: Shared state between client
24/// * I: Input for handling client
25/// * M: Message for sharing between app and server controller
26pub struct Application<T: Game<K, I>, K, I> {
27    pub is_running: bool,
28    pub shared_state: Arc<Mutex<K>>,
29    is_suspended: bool,
30    last_time: Instant,
31    frames_per_second: Duration,
32    input: Arc<Mutex<I>>,
33    game: T,
34}
35
36impl<T: Game<K, I>, K, I> Clone for Application<T, K, I>
37where
38    T: Clone,
39    K: Copy,
40    I: Copy,
41{
42    fn clone(&self) -> Application<T, K, I> {
43        Application {
44            is_running: self.is_running,
45            shared_state: Arc::new(Mutex::new(*self.shared_state.lock().unwrap())),
46            is_suspended: self.is_suspended,
47            last_time: self.last_time,
48            frames_per_second: self.frames_per_second,
49            input: Arc::new(Mutex::new(*self.input.lock().unwrap())),
50            game: self.game.clone(),
51        }
52    }
53}
54
55impl<T: Game<K, I>, K, I> Application<T, K, I> {
56    /// Create application
57    /// Starts logging
58    fn create(game: T, shared_state: K, input: I, game_update_rate: i32) -> Application<T, K, I> {
59        // Start logging
60        initialize_logging();
61
62        // Return app
63        Application {
64            is_running: false,
65            is_suspended: false,
66            last_time: Instant::now(),
67            frames_per_second: Duration::from_millis((1000 / game_update_rate) as u64), // 1000 / millis = frames per sec
68            input: Arc::new(Mutex::new(input)),
69            shared_state: Arc::new(Mutex::new(shared_state)),
70            game,
71        }
72    }
73
74    /// Run the app
75    /// Starts the game loop
76    pub fn start<M>(
77        &mut self,
78        receiver: Receiver<M>,
79        handle_input: &'static (dyn Fn(Receiver<M>, Arc<Mutex<I>>) -> I + Sync),
80    ) where
81        M: Send,
82        I: Send + Copy,
83    {
84        self.is_running = true;
85
86        // game configuration
87        self.game.world_config();
88
89        let input_copy = Arc::clone(&self.input);
90
91        // Spawn a handler for client input
92        thread::spawn(move || {
93            handle_input(receiver, input_copy);
94        });
95
96        // game loop
97        while self.is_running {
98            // self.last_time += 1.0;
99            let sleep_time = self.frames_per_second - self.last_time.elapsed();
100            thread::sleep(sleep_time);
101
102            // initial time
103            self.last_time = Instant::now();
104
105            // update
106            self.game
107                .update(*self.input.lock().unwrap(), Arc::clone(&self.shared_state));
108
109            // Reset input
110            self.game.reset_input(Arc::clone(&self.input));
111            // render
112
113            // End the game
114            self.is_running = !self.game.end_game();
115        }
116    }
117}
118
119/// Create app and return it
120pub fn create_app<T: Game<K, I>, K, I>(
121    game: T,
122    shared_state: K,
123    input: I,
124    game_update_rate: i32,
125) -> Application<T, K, I> {
126    Application::create(game, shared_state, input, game_update_rate)
127}