diff --git a/client/src/lib.rs b/client/src/lib.rs
index f8001fa101..d9038df8da 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -294,14 +294,6 @@ impl Client {
             .ecs_mut()
             .write_storage::<comp::Jumping>()
             .remove(self.entity);
-        self.state
-            .ecs_mut()
-            .write_storage::<comp::Dying>()
-            .remove(self.entity);
-        self.state
-            .ecs_mut()
-            .write_storage::<comp::Respawning>()
-            .remove(self.entity);
 
         self.tick += 1;
         Ok(frontend_events)
diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs
index f5a7494bb2..08a0559f4d 100644
--- a/common/src/comp/stats.rs
+++ b/common/src/comp/stats.rs
@@ -19,10 +19,12 @@ impl Health {
 pub struct Stats {
     pub hp: Health,
     pub xp: u32,
+    pub is_dead: bool,
 }
 
 impl Stats {
-    pub fn is_dead(&self) -> bool {
+    pub fn should_die(&self) -> bool {
+        // TODO: Remove
         self.hp.current == 0
     }
 }
@@ -36,6 +38,7 @@ impl Default for Stats {
                 last_change: None,
             },
             xp: 0,
+            is_dead: false,
         }
     }
 }
diff --git a/common/src/state.rs b/common/src/state.rs
index 61278edca3..66984551f5 100644
--- a/common/src/state.rs
+++ b/common/src/state.rs
@@ -103,21 +103,24 @@ impl State {
         ecs.register_synced::<comp::Actor>();
         ecs.register_synced::<comp::Player>();
         ecs.register_synced::<comp::Stats>();
-        ecs.register_synced::<comp::Attacking>();
+        ecs.register_synced::<comp::Attacking>(); // TODO: Don't send this to the client?
         ecs.register::<comp::phys::ForceUpdate>();
 
-        // Register unsynced (or synced by other means) components.
+        // Register components synced by other means
         ecs.register::<comp::phys::Pos>();
         ecs.register::<comp::phys::Vel>();
         ecs.register::<comp::phys::Dir>();
         ecs.register::<comp::AnimationInfo>();
-        ecs.register::<comp::Attacking>();
+
+        // Register client-local components
         ecs.register::<comp::Control>();
         ecs.register::<comp::Jumping>();
+
+        // Register server-local components
+        ecs.register::<comp::Agent>();
         ecs.register::<comp::Respawning>();
         ecs.register::<comp::Gliding>();
         ecs.register::<comp::Dying>();
-        ecs.register::<comp::Agent>();
         ecs.register::<inventory::Inventory>();
 
         // Register synced resources used by the ECS.
diff --git a/common/src/sys/inputs.rs b/common/src/sys/inputs.rs
index 1f3c74abb3..0ed148a774 100644
--- a/common/src/sys/inputs.rs
+++ b/common/src/sys/inputs.rs
@@ -149,7 +149,7 @@ impl<'a> System<'a> for Sys {
                 {
                     // Check if it is a hit
                     if entity != b
-                        && !stat_b.is_dead()
+                        && !stat_b.is_dead
                         && pos.0.distance_squared(pos_b.0) < 50.0
                         && dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0
                     {
diff --git a/common/src/sys/stats.rs b/common/src/sys/stats.rs
index 96eacddb7a..5a37c23401 100644
--- a/common/src/sys/stats.rs
+++ b/common/src/sys/stats.rs
@@ -21,8 +21,10 @@ impl<'a> System<'a> for Sys {
 
     fn run(&mut self, (entities, dt, mut stats, mut dyings): Self::SystemData) {
         for (entity, mut stat) in (&entities, &mut stats).join() {
-            if stat.hp.current == 0 {
+            if stat.should_die() && !stat.is_dead {
+                // TODO: Replace is_dead with client states
                 dyings.insert(entity, Dying);
+                stat.is_dead = true;
             }
             if let Some(change) = &mut stat.hp.last_change {
                 change.1 += dt.0 as f64;
diff --git a/server/src/lib.rs b/server/src/lib.rs
index ca9e52afa2..1f7205c7dc 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -39,9 +39,16 @@ const CLIENT_TIMEOUT: f64 = 20.0; // Seconds
 const DEFAULT_WORLD_SEED: u32 = 1337;
 
 pub enum Event {
-    ClientConnected { entity: EcsEntity },
-    ClientDisconnected { entity: EcsEntity },
-    Chat { entity: EcsEntity, msg: String },
+    ClientConnected {
+        entity: EcsEntity,
+    },
+    ClientDisconnected {
+        entity: EcsEntity,
+    },
+    Chat {
+        entity: Option<EcsEntity>,
+        msg: String,
+    },
 }
 
 #[derive(Copy, Clone)]
@@ -220,6 +227,12 @@ impl Server {
                 client.force_state(ClientState::Dead);
             } else {
                 self.state.ecs_mut().delete_entity_synced(entity);
+                continue;
+            }
+
+            if let Some(player) = self.state.ecs().read_storage::<comp::Player>().get(entity) {
+                self.clients
+                    .notify_registered(ServerMsg::Chat(format!("{} died", &player.alias)));
             }
         }
 
@@ -316,8 +329,6 @@ impl Server {
         // Cleanup
         let ecs = self.state.ecs_mut();
         for entity in ecs.entities().join() {
-            ecs.write_storage::<comp::Jumping>().remove(entity);
-            ecs.write_storage::<comp::Gliding>().remove(entity);
             ecs.write_storage::<comp::Dying>().remove(entity);
             ecs.write_storage::<comp::Respawning>().remove(entity);
         }
@@ -415,7 +426,13 @@ impl Server {
                         },
                         ClientMsg::Register { player } => match client.client_state {
                             ClientState::Connected => {
-                                Self::initialize_player(state, entity, client, player)
+                                Self::initialize_player(state, entity, client, player);
+                                if let Some(player) =
+                                    state.ecs().read_storage::<comp::Player>().get(entity)
+                                {
+                                    new_chat_msgs
+                                        .push((None, format!("{} logged in", &player.alias)));
+                                }
                             }
                             // Use RequestState instead (No need to send `player` again).
                             _ => client.error_state(RequestStateError::Impossible),
@@ -464,7 +481,7 @@ impl Server {
                             ClientState::Registered
                             | ClientState::Spectator
                             | ClientState::Dead
-                            | ClientState::Character => new_chat_msgs.push((entity, msg)),
+                            | ClientState::Character => new_chat_msgs.push((Some(entity), msg)),
                             ClientState::Pending => {}
                         },
                         ClientMsg::PlayerAnimation(animation_info) => {
@@ -507,7 +524,9 @@ impl Server {
                         // Always possible.
                         ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong),
                         ClientMsg::Pong => {}
-                        ClientMsg::Disconnect => disconnect = true,
+                        ClientMsg::Disconnect => {
+                            disconnect = true;
+                        }
                     }
                 }
             } else if state.get_time() - client.last_ping > CLIENT_TIMEOUT || // Timeout
@@ -521,6 +540,9 @@ impl Server {
             }
 
             if disconnect {
+                if let Some(player) = state.ecs().read_storage::<comp::Player>().get(entity) {
+                    new_chat_msgs.push((None, format!("{} disconnected", &player.alias)));
+                }
                 disconnected_clients.push(entity);
                 client.postbox.send_message(ServerMsg::Disconnect);
                 true
@@ -531,20 +553,23 @@ impl Server {
 
         // Handle new chat messages.
         for (entity, msg) in new_chat_msgs {
-            // Handle chat commands.
-            if msg.starts_with("/") && msg.len() > 1 {
-                let argv = String::from(&msg[1..]);
-                self.process_chat_cmd(entity, argv);
+            if let Some(entity) = entity {
+                // Handle chat commands.
+                if msg.starts_with("/") && msg.len() > 1 {
+                    let argv = String::from(&msg[1..]);
+                    self.process_chat_cmd(entity, argv);
+                } else {
+                    self.clients.notify_registered(ServerMsg::Chat(
+                        match self.state.ecs().read_storage::<comp::Player>().get(entity) {
+                            Some(player) => format!("[{}] {}", &player.alias, msg),
+                            None => format!("[<anon>] {}", msg),
+                        },
+                    ));
+                }
             } else {
-                self.clients.notify_registered(ServerMsg::Chat(
-                    match self.state.ecs().read_storage::<comp::Player>().get(entity) {
-                        Some(player) => format!("[{}] {}", &player.alias, msg),
-                        None => format!("[<anon>] {}", msg),
-                    },
-                ));
-
-                frontend_events.push(Event::Chat { entity, msg });
+                self.clients.notify_registered(ServerMsg::Chat(msg.clone()));
             }
+            frontend_events.push(Event::Chat { entity, msg });
         }
 
         // Handle client disconnects.
diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs
index 954ed65235..5cacd0bb26 100644
--- a/voxygen/src/hud/mod.rs
+++ b/voxygen/src/hud/mod.rs
@@ -307,7 +307,7 @@ impl Hud {
             let mut health_back_id_walker = self.ids.health_bar_backs.walk();
             for (pos, name) in (&entities, &pos, &actor, &stats, player.maybe())
                 .join()
-                .filter(|(entity, _, _, stats, _)| *entity != me && !stats.is_dead())
+                .filter(|(entity, _, _, stats, _)| *entity != me && !stats.is_dead)
                 .map(|(entity, pos, actor, _, player)| match actor {
                     comp::Actor::Character {
                         name: char_name, ..
@@ -338,7 +338,7 @@ impl Hud {
 
             for (entity, pos, stats) in (&entities, &pos, &stats)
                 .join()
-                .filter(|(entity, _, stats)| *entity != me && !stats.is_dead())
+                .filter(|(entity, _, stats)| *entity != me && !stats.is_dead)
             {
                 let back_id = health_back_id_walker.next(
                     &mut self.ids.health_bar_backs,
diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs
index 2824511ae4..cb67afaa33 100644
--- a/voxygen/src/scene/figure.rs
+++ b/voxygen/src/scene/figure.rs
@@ -617,7 +617,7 @@ impl FigureMgr {
         )
             .join()
         {
-            if stat.is_dead() {
+            if stat.is_dead {
                 continue;
             }