diff --git a/src/ecs/mod.rs b/src/ecs/mod.rs index 4dd4196..fdd7b56 100644 --- a/src/ecs/mod.rs +++ b/src/ecs/mod.rs @@ -84,6 +84,7 @@ pub trait System { struct EntityState { last_components: BSet, components: BSet, + removed: bool, } /// Stores and manages a collection of entities. @@ -99,7 +100,6 @@ pub struct Manager { render_systems: Vec>, changed_entity_components: HashSet>, - removed_entities: HashSet>, } impl Manager { @@ -110,6 +110,7 @@ impl Manager { entities: vec![(Some(EntityState { last_components: BSet::new(0), components: BSet::new(0), + removed: false, }), 0)], // Has the world entity pre-defined free_entities: vec![], components: vec![], @@ -119,7 +120,6 @@ impl Manager { render_systems: vec![], changed_entity_components: HashSet::with_hasher(BuildHasherDefault::default()), - removed_entities: HashSet::with_hasher(BuildHasherDefault::default()), } } @@ -179,7 +179,7 @@ impl Manager { } } - if self.removed_entities.remove(&entity) { + if state.removed { self.free_entities.push(entity.id); self.entities[entity.id].0 = None; } else { @@ -195,7 +195,7 @@ impl Manager { // Skip the world entity. for (i, &(ref set, gen)) in self.entities[1..].iter().enumerate() { if let Some(set) = set.as_ref() { - if set.components.includes_set(&filter.bits) { + if !set.removed && set.components.includes_set(&filter.bits) { ret.push(Entity { id: i + 1, generation: gen, @@ -213,6 +213,7 @@ impl Manager { entity.0 = Some(EntityState { last_components: BSet::new(self.num_components), components: BSet::new(self.num_components), + removed: false, }); entity.1 += 1; return Entity { @@ -225,6 +226,7 @@ impl Manager { Some(EntityState { last_components: BSet::new(self.num_components), components: BSet::new(self.num_components), + removed: false, }), 0 )); @@ -238,10 +240,21 @@ impl Manager { pub fn remove_entity(&mut self, e: Entity) { if let Some(set) = self.entities[e.id].0.as_mut() { set.components = BSet::new(self.components.len()); - self.removed_entities.insert(e); + set.removed = true; } } + /// Deallocates all entities/components excluding the world entity + pub fn remove_all_entities(&mut self) { + for e in &mut self.entities[1..] { + if let Some(set) = e.0.as_mut() { + set.components = BSet::new(self.components.len()); + set.removed = true; + } + } + self.process_entity_changes(); + } + /// Returns whether an entity reference is valid. pub fn is_entity_valid(&self, e: Entity) -> bool { match self.entities.get(e.id) { diff --git a/src/entity/mod.rs b/src/entity/mod.rs index 2187023..b07d121 100644 --- a/src/entity/mod.rs +++ b/src/entity/mod.rs @@ -114,6 +114,14 @@ impl ::std::ops::Deref for Proxy { } } +impl ::std::ops::DerefMut for Proxy { + + fn deref_mut(&mut self) -> &mut T { + self.inner.as_mut().unwrap() + } +} + + impl Proxy { pub fn new() -> Proxy { diff --git a/src/entity/player.rs b/src/entity/player.rs index 7b6a272..524c054 100644 --- a/src/entity/player.rs +++ b/src/entity/player.rs @@ -27,7 +27,7 @@ pub fn add_systems(m: &mut ecs::Manager) { pub fn create_local(m: &mut ecs::Manager) -> ecs::Entity { let entity = m.create_entity(); - m.add_component_direct(entity, Position::new(0.5, 13.2, 0.5)); + m.add_component_direct(entity, Position::new(0.0, 0.0, 0.0)); m.add_component_direct(entity, Rotation::new(0.0, 0.0)); m.add_component_direct(entity, Velocity::new(0.0, 0.0, 0.0)); m.add_component_direct(entity, Gamemode::Survival); diff --git a/src/main.rs b/src/main.rs index abbe609..8946bfd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -109,10 +109,10 @@ impl Game { pub fn tick(&mut self, delta: f64) { if !self.server.is_connected() { - let rotation = self.server.entities.get_component_mut(self.server.player, self.server.rotation).unwrap(); - rotation.yaw += 0.005 * delta; - if rotation.yaw > ::std::f64::consts::PI * 2.0 { - rotation.yaw = 0.0; + self.renderer.camera.pos = cgmath::Point3::new(0.5, 13.2, 0.5); + self.renderer.camera.yaw += 0.005 * delta; + if self.renderer.camera.yaw > ::std::f64::consts::PI * 2.0 { + self.renderer.camera.yaw = 0.0; } } let mut clear_reply = false; @@ -123,6 +123,7 @@ impl Game { Ok(val) => { self.screen_sys.pop_screen(); self.focused = true; + self.server.remove(&mut self.renderer); self.server = val; }, Err(err) => { @@ -270,16 +271,18 @@ fn handle_window_event(window: &sdl2::video::Window, if !mouse.relative_mouse_mode() { mouse.set_relative_mouse_mode(true); } - let s = 2000.0 + 0.01; - let (rx, ry) = (xrel as f64 / s, yrel as f64 / s); - let rotation = game.server.entities.get_component_mut(game.server.player, game.server.rotation).unwrap(); - rotation.yaw -= rx; - rotation.pitch -= ry; - if rotation.pitch < (PI/2.0) + 0.01 { - rotation.pitch = (PI/2.0) + 0.01; - } - if rotation.pitch > (PI/2.0)*3.0 - 0.01 { - rotation.pitch = (PI/2.0)*3.0 - 0.01; + if let Some(player) = game.server.player { + let s = 2000.0 + 0.01; + let (rx, ry) = (xrel as f64 / s, yrel as f64 / s); + let rotation = game.server.entities.get_component_mut(player, game.server.rotation).unwrap(); + rotation.yaw -= rx; + rotation.pitch -= ry; + if rotation.pitch < (PI/2.0) + 0.01 { + rotation.pitch = (PI/2.0) + 0.01; + } + if rotation.pitch > (PI/2.0)*3.0 - 0.01 { + rotation.pitch = (PI/2.0)*3.0 - 0.01; + } } } else { ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64); diff --git a/src/server.rs b/src/server.rs index be586ee..9b79fd7 100644 --- a/src/server.rs +++ b/src/server.rs @@ -60,11 +60,12 @@ pub struct Server { pub rotation: ecs::Key, // - pub player: ecs::Entity, + pub player: Option, entity_map: HashMap>, pressed_keys: HashMap>, tick_timer: f64, + entity_tick_timer: f64, } macro_rules! handle_packet { @@ -177,7 +178,6 @@ impl Server { } } } - *server.entities.get_component_mut(server.player, server.gamemode).unwrap() = Gamemode::Spectator; server } @@ -188,7 +188,6 @@ impl Server { let mut entities = ecs::Manager::new(); entity::add_systems(&mut entities); - let player = entity::player::create_local(&mut entities); let world_entity = entities.get_world(); let world_proxy = entities.get_key(); entities.add_component(world_entity, world_proxy, entity::Proxy::new()); @@ -226,10 +225,11 @@ impl Server { // entities: entities, - player: player, + player: None, entity_map: HashMap::with_hasher(BuildHasherDefault::default()), tick_timer: 0.0, + entity_tick_timer: 0.0, } } @@ -244,6 +244,40 @@ impl Server { self.world.flag_dirty_all(); } + self.entity_tick(renderer, delta); + + self.tick_timer += delta; + while self.tick_timer >= 3.0 && self.is_connected() { + self.minecraft_tick(); + self.tick_timer -= 3.0; + } + + self.update_time(renderer, delta); + + // Copy to camera + if let Some(player) = self.player { + let position = self.entities.get_component(player, self.position).unwrap(); + let rotation = self.entities.get_component(player, self.rotation).unwrap(); + renderer.camera.pos = cgmath::Point::from_vec(position.position + cgmath::Vector3::new(0.0, 1.62, 0.0)); + renderer.camera.yaw = rotation.yaw; + renderer.camera.pitch = rotation.pitch; + } + } + + fn entity_tick(&mut self, renderer: &mut render::Renderer, delta: f64) { + let world_entity = self.entities.get_world(); + // Borrow the world and renderer + self.entities.get_component_mut(world_entity, self.world_proxy) + .unwrap() + .give(&mut self.world); + self.entities.get_component_mut(world_entity, self.renderer_proxy) + .unwrap() + .give(renderer); + // Update the game's state for entities to read + self.entities.get_component_mut(world_entity, self.game_info) + .unwrap().delta = delta; + + // Packets modify entities so need to handled here if let Some(rx) = self.read_queue.take() { while let Ok(pck) = rx.try_recv() { match pck { @@ -265,25 +299,24 @@ impl Server { self.read_queue = Some(rx); } - self.tick_timer += delta; - while self.tick_timer >= 3.0 && self.is_connected() { - self.minecraft_tick(); - self.tick_timer -= 3.0; + self.entity_tick_timer += delta; + while self.entity_tick_timer >= 3.0 && self.is_connected() { + self.entities.tick(); + self.entity_tick_timer -= 3.0; } - self.render_tick(renderer, delta); + self.entities.render_tick(); - self.update_time(renderer, delta); - - // Copy to camera - let position = self.entities.get_component(self.player, self.position).unwrap(); - let rotation = self.entities.get_component(self.player, self.rotation).unwrap(); - renderer.camera.pos = cgmath::Point::from_vec(position.position + cgmath::Vector3::new(0.0, 1.62, 0.0)); - renderer.camera.yaw = rotation.yaw; - renderer.camera.pitch = rotation.pitch; + // Return what we borrowed + self.entities.get_component_mut(world_entity, self.world_proxy) + .unwrap() + .take(&mut self.world); + self.entities.get_component_mut(world_entity, self.renderer_proxy) + .unwrap() + .take(renderer); } - fn render_tick(&mut self, renderer: &mut render::Renderer, delta: f64) { + pub fn remove(&mut self, renderer: &mut render::Renderer) { let world_entity = self.entities.get_world(); // Borrow the world and renderer self.entities.get_component_mut(world_entity, self.world_proxy) @@ -292,12 +325,10 @@ impl Server { self.entities.get_component_mut(world_entity, self.renderer_proxy) .unwrap() .give(renderer); - // Update the game's state for entities to read - self.entities.get_component_mut(world_entity, self.game_info) - .unwrap().delta = delta; - self.entities.render_tick(); + self.entities.remove_all_entities(); + // Return what we borrowed self.entities.get_component_mut(world_entity, self.world_proxy) .unwrap() .take(&mut self.world); @@ -348,47 +379,42 @@ impl Server { } pub fn minecraft_tick(&mut self) { - let world_entity = self.entities.get_world(); - self.entities.get_component_mut(world_entity, self.world_proxy) - .unwrap() - .give(&mut self.world); - self.entities.tick(); - self.entities.get_component_mut(world_entity, self.world_proxy) - .unwrap() - .take(&mut self.world); + if let Some(player) = self.player { + let movement = self.entities.get_component_mut(player, self.player_movement).unwrap(); + let on_ground = self.entities.get_component(player, self.gravity).map_or(false, |v| v.on_ground); + let position = self.entities.get_component(player, self.position).unwrap(); + let rotation = self.entities.get_component(player, self.rotation).unwrap(); - let movement = self.entities.get_component_mut(self.player, self.player_movement).unwrap(); - let on_ground = self.entities.get_component(self.player, self.gravity).map_or(false, |v| v.on_ground); - let position = self.entities.get_component(self.player, self.position).unwrap(); - let rotation = self.entities.get_component(self.player, self.rotation).unwrap(); + // Force the server to know when touched the ground + // otherwise if it happens between ticks the server + // will think we are flying. + let on_ground = if movement.did_touch_ground { + movement.did_touch_ground = false; + true + } else { + on_ground + }; - // Force the server to know when touched the ground - // otherwise if it happens between ticks the server - // will think we are flying. - let on_ground = if movement.did_touch_ground { - movement.did_touch_ground = false; - true - } else { - on_ground - }; - - // Sync our position to the server - // Use the smaller packets when possible - let packet = packet::play::serverbound::PlayerPositionLook { - x: position.position.x, - y: position.position.y, - z: position.position.z, - yaw: rotation.yaw as f32, - pitch: rotation.pitch as f32, - on_ground: on_ground, - }; - self.write_packet(packet); + // Sync our position to the server + // Use the smaller packets when possible + let packet = packet::play::serverbound::PlayerPositionLook { + x: position.position.x, + y: position.position.y, + z: position.position.z, + yaw: rotation.yaw as f32, + pitch: rotation.pitch as f32, + on_ground: on_ground, + }; + self.write_packet(packet); + } } pub fn key_press(&mut self, down: bool, key: Keycode) { self.pressed_keys.insert(key, down); - if let Some(movement) = self.entities.get_component_mut(self.player, self.player_movement) { - movement.pressed_keys.insert(key, down); + if let Some(player) = self.player { + if let Some(movement) = self.entities.get_component_mut(player, self.player_movement) { + movement.pressed_keys.insert(key, down); + } } } @@ -408,19 +434,24 @@ impl Server { fn on_game_join(&mut self, join: packet::play::clientbound::JoinGame) { let gamemode = Gamemode::from_int((join.gamemode & 0x7) as i32); - *self.entities.get_component_mut(self.player, self.gamemode).unwrap() = gamemode; + let player = entity::player::create_local(&mut self.entities); + *self.entities.get_component_mut(player, self.gamemode).unwrap() = gamemode; // TODO: Temp - self.entities.get_component_mut(self.player, self.player_movement).unwrap().flying = gamemode.can_fly(); + self.entities.get_component_mut(player, self.player_movement).unwrap().flying = gamemode.can_fly(); - self.entity_map.insert(join.entity_id, self.player); + self.entity_map.insert(join.entity_id, player); + self.player = Some(player); } fn on_respawn(&mut self, respawn: packet::play::clientbound::Respawn) { self.world = world::World::new(); let gamemode = Gamemode::from_int((respawn.gamemode & 0x7) as i32); - *self.entities.get_component_mut(self.player, self.gamemode).unwrap() = gamemode; - // TODO: Temp - self.entities.get_component_mut(self.player, self.player_movement).unwrap().flying = gamemode.can_fly(); + + if let Some(player) = self.player { + *self.entities.get_component_mut(player, self.gamemode).unwrap() = gamemode; + // TODO: Temp + self.entities.get_component_mut(player, self.player_movement).unwrap().flying = gamemode.can_fly(); + } } fn on_time_update(&mut self, time_update: packet::play::clientbound::TimeUpdate) { @@ -437,32 +468,38 @@ impl Server { fn on_game_state_change(&mut self, game_state: packet::play::clientbound::ChangeGameState) { match game_state.reason { 3 => { - let gamemode = Gamemode::from_int(game_state.value as i32); - *self.entities.get_component_mut(self.player, self.gamemode).unwrap() = gamemode; - // TODO: Temp - self.entities.get_component_mut(self.player, self.player_movement).unwrap().flying = gamemode.can_fly(); + if let Some(player) = self.player { + let gamemode = Gamemode::from_int(game_state.value as i32); + *self.entities.get_component_mut(player, self.gamemode).unwrap() = gamemode; + // TODO: Temp + self.entities.get_component_mut(player, self.player_movement).unwrap().flying = gamemode.can_fly(); + } }, _ => {}, } } fn on_teleport(&mut self, teleport: packet::play::clientbound::TeleportPlayer) { - let position = self.entities.get_component_mut(self.player, self.position).unwrap(); - let rotation = self.entities.get_component_mut(self.player, self.rotation).unwrap(); + if let Some(player) = self.player { + let position = self.entities.get_component_mut(player, self.position).unwrap(); + let rotation = self.entities.get_component_mut(player, self.rotation).unwrap(); - position.position.x = calculate_relative_teleport(TeleportFlag::RelX, teleport.flags, position.position.x, teleport.x); - position.position.y = calculate_relative_teleport(TeleportFlag::RelY, teleport.flags, position.position.y, teleport.y); - position.position.z = calculate_relative_teleport(TeleportFlag::RelZ, teleport.flags, position.position.z, teleport.z); - rotation.yaw = calculate_relative_teleport(TeleportFlag::RelYaw, teleport.flags, rotation.yaw, teleport.yaw as f64); - rotation.pitch = calculate_relative_teleport(TeleportFlag::RelPitch, teleport.flags, rotation.pitch, teleport.pitch as f64); + position.position.x = calculate_relative_teleport(TeleportFlag::RelX, teleport.flags, position.position.x, teleport.x); + position.position.y = calculate_relative_teleport(TeleportFlag::RelY, teleport.flags, position.position.y, teleport.y); + position.position.z = calculate_relative_teleport(TeleportFlag::RelZ, teleport.flags, position.position.z, teleport.z); + rotation.yaw = calculate_relative_teleport(TeleportFlag::RelYaw, teleport.flags, rotation.yaw, teleport.yaw as f64); + rotation.pitch = calculate_relative_teleport(TeleportFlag::RelPitch, teleport.flags, rotation.pitch, teleport.pitch as f64); - self.write_packet(packet::play::serverbound::TeleportConfirm { - teleport_id: teleport.teleport_id, - }); + self.write_packet(packet::play::serverbound::TeleportConfirm { + teleport_id: teleport.teleport_id, + }); + } } fn on_chunk_data(&mut self, chunk_data: packet::play::clientbound::ChunkData) { - self.world.load_chunk( + let world_entity = self.entities.get_world(); + let world = self.entities.get_component_mut(world_entity, self.world_proxy).unwrap(); + world.load_chunk( chunk_data.chunk_x, chunk_data.chunk_z, chunk_data.new, @@ -472,7 +509,9 @@ impl Server { } fn on_chunk_unload(&mut self, chunk_unload: packet::play::clientbound::ChunkUnload) { - self.world.unload_chunk(chunk_unload.x, chunk_unload.z); + let world_entity = self.entities.get_world(); + let world = self.entities.get_component_mut(world_entity, self.world_proxy).unwrap(); + world.unload_chunk(chunk_unload.x, chunk_unload.z); } }