1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//!
//! Nate's Game Engine
//! 
//! # Creating Worlds
//! ```
//! #[world(singular=[canvas])]
//! pub struct World {
//!     position: (isize, isize),
//!     velocity: (isize, isize),
//!     health: usize,
//!     health_changes: isize,
//!     canvas: [[bool; 10]; 10],
//! }
//! ```
//! 
//! Creates a world named World, where every entity has the possibility of having a
//! position, velocity, health, and health_change, but the world has a singular canvas.
//! This will also generate getters and setters for each component as well as a default
//! initializer for the world.
//! 
//! # Declaring Systems
//! ```
//! #[system(world=World, read=[velocity], write=[position], _read=[game_state], _write=[canvas])]
//! pub fn some_system() {
//!     ...
//! }
//! ```
//! 
//! The above example creates a system named some_system that operates on a world of type World.
//! This system will operate on each entity that has a velocity and position component, such that
//! the entity's positions are mutable and their velocities are immutable.  The world game_state is
//! also readable and the world canvas is writable.
//! 
//! # Examples
//! 
//! One example of using the engine is accessible [here](examples/toy_example.rs).
//! An even simpler example is as follows:
//! ```
//! use nate_engine::{Engine, Renderer, system, world};
//! 
//! // Game State Enum
//! #[derive(Clone, Copy, Debug, PartialEq, Eq)]
//! pub enum GameState {
//!     Paused,
//!     Playing,
//!     Stopped,
//! }
//! 
//! // World where every entity can have a position, velocity, health, and health_change and
//! // canvas and game_state are singular components (i.e. components on the world)
//! #[world(singular=[canvas, game_state])]
//! pub struct ExampleWorld {
//!     position: (isize, isize),
//!     velocity: (isize, isize),
//!     health: usize,
//!     health_changes: isize,
//! 
//!     canvas: [[bool; 10]; 10],
//!     game_state: GameState,
//! }
//! 
//! // If the game is playing, update the position of every entity with both and position and
//! // velocity based on the velocity.
//! #[system(world=ExampleWorld, read=[velocity], write=[position], _read=[game_state])]
//! pub fn position_update_system() {
//!     if game_state == GameState::Playing {
//!         *position = (position.0 + velocity.0, position.1 + velocity.1);
//!     }
//! }
//! 
//! // If the game is playing, update the health of every entity with a health change
//! #[system(world=ExampleWorld, read=[health_changes], write=[health], _read=[game_state])]
//! pub fn health_update_system() {
//!     if game_state == GameState::Playing {
//!         *health = health.saturating_add_signed(*health_changes);
//!     }
//! }
//! 
//! // Write the positions of entities to the canvas
//! #[system(world=ExampleWorld, read=[position], _write=[canvas = [[false; 10]; 10])]
//! pub fn canvas_update_system() {
//!     let x = position.0.clamp(0.0, 9.0) as usize;
//!     let y = position.1.clamp(0.0, 9.0) as usize;
//!     canvas[y][x] = true;
//! }
//! 
//! // Renderer that will print to the console
//! pub struct ExampleRenderer {}
//! 
//! // Make sure the renderer is compatible with the game engine
//! impl Renderer<ExampleWorld> for ExampleRenderer {
//!     type Error = String;
//! 
//!     fn render(&mut self, world: Arc<RwLock<ExampleWorld>>) -> Result<(), Self::Error> {
//!         let world = world.read.unwrap();
//!         let canvas = (*world.canvas.read().unwrap()).unwrap();
//!         
//!         
//!         for y in 0..10 {
//!             for x in 0..10 {
//!                 if canvas[y][x] {
//!                     print!("X");
//!                 } else {
//!                     print!("_");
//!                 }
//!             }
//!             print!("\n");
//!         }
//! 
//!         // Handle Ctrl-c or Events to exit the loop
//!         Ok(())
//!     }
//! }
//! 
//! // The Frame Rate for the Rendering Engine
//! const FRAME_RATE: u32 = 30;
//! // The Number of CPU workers to Compute Systems (1 will be reserved for the rendering engine)
//! const WORKERS: usize = 2;
//! 
//! fn main() {
//!     let world = ExampleWorld::new();
//! 
//!     {
//!         let mut world = world.write().unwrap();
//!         // Create Entities in the World
//!         let entity_ids = world.add_entities(100);
//! 
//!         // Add Components to Entities
//!         world.set_positions(&entity_ids, ...);
//!         ...
//! 
//!         // Initialize Singular Components
//!         world.set_game_state(GameState::Playing);
//!         world.set_canvas([[false; 10]; 10]);
//!     }
//! 
//!     let mut engine = Engine::new(
//!         FRAME_RATE,
//!         WORKERS,
//!         world,
//!         vec![
//!             // position update system will run every 100ms
//!             (position_update_system, 100_000),
//!             // health update system will run every 1s
//!             (health_update_system, 1_000_000),
//!             // canvas update system will run every 100ms
//!             (canvas_update_system, 100_000),
//!         ],
//!         Box::new(ExampleRenderer{}),
//!     );
//! 
//!     engine.run();
//! }
//! ```
//! 

#[allow(rustdoc::invalid_rust_codeblocks)]

/// Re-export of Nate's Engine Core
pub use nate_engine_core::{Engine, Renderer};
/// Re-export of Nate's Engine Macros
pub use nate_engine_macros::{world, system};