Various bug fixes for entity handling. TODO: Smite this system from orbit, it sucks

This commit is contained in:
Thinkofname 2016-03-27 17:08:38 +01:00
parent 347244c65c
commit e36a0f4579
5 changed files with 162 additions and 99 deletions

View File

@ -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<Box<System + Send>>,
changed_entity_components: HashSet<Entity, BuildHasherDefault<FNVHash>>,
removed_entities: HashSet<Entity, BuildHasherDefault<FNVHash>>,
}
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) {

View File

@ -114,6 +114,14 @@ impl <T> ::std::ops::Deref for Proxy<T> {
}
}
impl <T> ::std::ops::DerefMut for Proxy<T> {
fn deref_mut(&mut self) -> &mut T {
self.inner.as_mut().unwrap()
}
}
impl <T> Proxy<T> {
pub fn new() -> Proxy<T> {

View File

@ -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);

View File

@ -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);

View File

@ -60,11 +60,12 @@ pub struct Server {
pub rotation: ecs::Key<entity::Rotation>,
//
pub player: ecs::Entity,
pub player: Option<ecs::Entity>,
entity_map: HashMap<i32, ecs::Entity, BuildHasherDefault<FNVHash>>,
pressed_keys: HashMap<Keycode, bool, BuildHasherDefault<FNVHash>>,
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);
}
}