From 34d211d11777dd6e942967d14c6e4f96ff28d922 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Wed, 10 Apr 2019 18:23:27 +0100
Subject: [PATCH 01/16] Integrated Sphynx

Former-commit-id: 5d96983a385bb77a2876aa7439158252b7e2f0fc
---
 chat-cli/src/main.rs         |   7 +-
 client/src/error.rs          |   1 +
 client/src/lib.rs            |  55 ++++++++-------
 common/Cargo.toml            |   2 +
 common/src/comp/character.rs |  26 +++++--
 common/src/comp/mod.rs       |  21 ++----
 common/src/comp/phys.rs      |  21 ++----
 common/src/comp/player.rs    |  18 +++++
 common/src/comp/uid.rs       |  84 ----------------------
 common/src/comp/util.rs      |  12 ----
 common/src/lib.rs            |   2 +-
 common/src/msg/client.rs     |  15 ++--
 common/src/msg/ecs_packet.rs |  29 ++++++++
 common/src/msg/mod.rs        |   6 +-
 common/src/msg/server.rs     |  19 ++---
 common/src/net/post.rs       |  39 ++++++++++
 common/src/state.rs          | 126 +++++++++++++--------------------
 server-cli/src/main.rs       |   6 +-
 server/src/client.rs         |  25 +++++--
 server/src/lib.rs            | 133 +++++++++++++++++------------------
 voxygen/src/menu/main/mod.rs |   9 ++-
 voxygen/src/scene/mod.rs     |   3 +-
 voxygen/src/session.rs       |   2 +
 23 files changed, 317 insertions(+), 344 deletions(-)
 create mode 100644 common/src/comp/player.rs
 delete mode 100644 common/src/comp/uid.rs
 delete mode 100644 common/src/comp/util.rs
 create mode 100644 common/src/msg/ecs_packet.rs

diff --git a/chat-cli/src/main.rs b/chat-cli/src/main.rs
index fa93a3df36..deb5cb126c 100644
--- a/chat-cli/src/main.rs
+++ b/chat-cli/src/main.rs
@@ -1,7 +1,10 @@
 use std::time::Duration;
 use log::info;
 use client::{Input, Client, Event};
-use common::clock::Clock;
+use common::{
+    comp,
+    clock::Clock,
+};
 
 const FPS: u64 = 60;
 
@@ -15,7 +18,7 @@ fn main() {
     let mut clock = Clock::new();
 
     // Create client
-    let mut client = Client::new(([127, 0, 0, 1], 59003))
+    let mut client = Client::new(([127, 0, 0, 1], 59003), comp::Player::new("test".to_string()), None)
         .expect("Failed to create client instance");
 
     client.send_chat("Hello!".to_string());
diff --git a/client/src/error.rs b/client/src/error.rs
index e702a67b0f..b4b3ce4742 100644
--- a/client/src/error.rs
+++ b/client/src/error.rs
@@ -3,6 +3,7 @@ use common::net::PostError;
 #[derive(Debug)]
 pub enum Error {
     Network(PostError),
+    ServerWentMad,
     ServerTimeout,
     ServerShutdown,
     Other(String),
diff --git a/client/src/lib.rs b/client/src/lib.rs
index 0e364d9701..0fcccc1e27 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -50,11 +50,31 @@ pub struct Client {
 impl Client {
     /// Create a new `Client`.
     #[allow(dead_code)]
-    pub fn new<A: Into<SocketAddr>>(addr: A) -> Result<Self, Error> {
-        let state = State::new();
+    pub fn new<A: Into<SocketAddr>>(
+        addr: A,
+        player: comp::Player,
+        character: Option<comp::Character>,
+    ) -> Result<Self, Error> {
 
         let mut postbox = PostBox::to_server(addr)?;
 
+        // Send connection request
+        postbox.send(ClientMsg::Connect {
+            player,
+            character,
+        });
+
+        // Wait for handshake from server
+        let (state, player) = match postbox.next_message() {
+            Some(ServerMsg::Handshake { ecs_state, player_entity }) => {
+                println!("STATE PACKAGE! {:?}", ecs_state);
+                let mut state = State::from_state_package(ecs_state);
+                let player_entity = state.ecs().entity_from_uid(player_entity);
+                (state, player_entity)
+            },
+            _ => return Err(Error::ServerWentMad),
+        };
+
         Ok(Self {
             thread_pool: threadpool::Builder::new()
                 .thread_name("veloren-worker".into())
@@ -65,7 +85,7 @@ impl Client {
 
             tick: 0,
             state,
-            player: None,
+            player,
 
             // Testing
             world: World::new(),
@@ -85,12 +105,6 @@ impl Client {
         self
     }
 
-    // TODO: Get rid of this
-    pub fn load_chunk(&mut self, pos: Vec3<i32>) {
-        self.state.terrain_mut().insert(pos, self.world.generate_chunk(pos));
-        self.state.changes_mut().new_chunks.push(pos);
-    }
-
     /// Get a reference to the client's game state.
     #[allow(dead_code)]
     pub fn state(&self) -> &State { &self.state }
@@ -187,28 +201,15 @@ impl Client {
 
             for msg in new_msgs {
                 match msg {
+                    ServerMsg::Handshake { .. } => return Err(Error::ServerWentMad),
                     ServerMsg::Shutdown => return Err(Error::ServerShutdown),
                     ServerMsg::Ping => self.postbox.send(ClientMsg::Pong),
                     ServerMsg::Pong => {},
                     ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
-                    ServerMsg::SetPlayerEntity(uid) => {
-                        let ecs_entity = self.state
-                            .get_entity(uid)
-                            .unwrap_or_else(|| self.state.build_uid_entity_with_uid(uid).build());
-
-                        self.player = Some(ecs_entity);
-                    },
-                    ServerMsg::EntityPhysics { uid, pos, vel, dir } => {
-                        let ecs_entity = self.state
-                            .get_entity(uid)
-                            .unwrap_or_else(|| self.state.build_uid_entity_with_uid(uid).build());
-
-                        self.state.write_component(ecs_entity, pos);
-                        self.state.write_component(ecs_entity, vel);
-                        self.state.write_component(ecs_entity, dir);
-                    },
-                    ServerMsg::EntityDeleted(uid) => {
-                        self.state.delete_entity(uid);
+                    ServerMsg::SetPlayerEntity(uid) => self.player = Some(self.state.ecs().entity_from_uid(uid).unwrap()), // TODO: Don't unwrap here!
+                    ServerMsg::EcsSync(sync_package) => {
+                        println!("SYNC PACKAGE! {:?}", sync_package);
+                        self.state.ecs_mut().sync_with_package(sync_package)
                     },
                 }
             }
diff --git a/common/Cargo.toml b/common/Cargo.toml
index 3fa8fd33a3..75c032bf18 100644
--- a/common/Cargo.toml
+++ b/common/Cargo.toml
@@ -5,6 +5,8 @@ authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>", "Maciej Ćwięka <mc
 edition = "2018"
 
 [dependencies]
+sphynx = { git = "https://gitlab.com/veloren/sphynx.git", features = ["serde1"] }
+
 specs = { version = "0.14", features = ["serde"] }
 shred = { version = "0.7", features = ["nightly"] }
 vek = { version = "0.9", features = ["serde"] }
diff --git a/common/src/comp/character.rs b/common/src/comp/character.rs
index 090f0e047a..02cef3eff6 100644
--- a/common/src/comp/character.rs
+++ b/common/src/comp/character.rs
@@ -1,9 +1,8 @@
-// Library
-use specs::{Component, VecStorage};
+use specs::{Component, VecStorage, FlaggedStorage};
 use vek::*;
 
 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
-enum Race {
+pub enum Race {
     Danari,
     Dwarf,
     Elf,
@@ -13,7 +12,7 @@ enum Race {
 }
 
 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
-pub struct Gender {
+pub enum Gender {
     Female,
     Male,
     Unspecified,
@@ -30,6 +29,21 @@ pub struct Character {
     feet: (),
 }
 
-impl Component for Character {
-    type Storage = VecStorage<Self>;
+impl Character {
+    // TODO: Remove this
+    pub fn test() -> Self {
+        Self {
+            race: Race::Human,
+            gender: Gender::Unspecified,
+            head: (),
+            chest: (),
+            belt: (),
+            arms: (),
+            feet: (),
+        }
+    }
+}
+
+impl Component for Character {
+    type Storage = FlaggedStorage<Self, VecStorage<Self>>;
 }
diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs
index 776a67485c..f5fa9254b7 100644
--- a/common/src/comp/mod.rs
+++ b/common/src/comp/mod.rs
@@ -1,20 +1,7 @@
+pub mod character;
+pub mod player;
 pub mod phys;
-pub mod uid;
-pub mod util;
 
 // Reexports
-pub use uid::{Uid, UidAllocator};
-
-use specs::World as EcsWorld;
-
-pub fn register_local_components(ecs_world: &mut EcsWorld) {
-    ecs_world.register::<Uid>();
-    ecs_world.add_resource(UidAllocator::new());
-
-    ecs_world.register::<util::New>();
-
-    ecs_world.register::<phys::Pos>();
-    ecs_world.register::<phys::Vel>();
-    ecs_world.register::<phys::Dir>();
-    ecs_world.register::<phys::UpdateKind>();
-}
+pub use character::Character;
+pub use player::Player;
diff --git a/common/src/comp/phys.rs b/common/src/comp/phys.rs
index 3db813276d..20e2b59192 100644
--- a/common/src/comp/phys.rs
+++ b/common/src/comp/phys.rs
@@ -1,5 +1,4 @@
-// Library
-use specs::{Component, VecStorage};
+use specs::{Component, VecStorage, FlaggedStorage};
 use vek::*;
 
 // Pos
@@ -8,7 +7,7 @@ use vek::*;
 pub struct Pos(pub Vec3<f32>);
 
 impl Component for Pos {
-    type Storage = VecStorage<Self>;
+    type Storage = FlaggedStorage<Self, VecStorage<Self>>;
 }
 
 // Vel
@@ -17,7 +16,7 @@ impl Component for Pos {
 pub struct Vel(pub Vec3<f32>);
 
 impl Component for Vel {
-    type Storage = VecStorage<Self>;
+    type Storage = FlaggedStorage<Self, VecStorage<Self>>;
 }
 
 // Dir
@@ -26,17 +25,5 @@ impl Component for Vel {
 pub struct Dir(pub Vec3<f32>);
 
 impl Component for Dir {
-    type Storage = VecStorage<Self>;
-}
-
-// UpdateKind
-
-#[derive(Copy, Clone, Debug)]
-pub enum UpdateKind {
-    Passive,
-    Force,
-}
-
-impl Component for UpdateKind {
-    type Storage = VecStorage<Self>;
+    type Storage = FlaggedStorage<Self, VecStorage<Self>>;
 }
diff --git a/common/src/comp/player.rs b/common/src/comp/player.rs
new file mode 100644
index 0000000000..46f1a048a4
--- /dev/null
+++ b/common/src/comp/player.rs
@@ -0,0 +1,18 @@
+use specs::{Component, VecStorage, FlaggedStorage};
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct Player {
+    pub alias: String,
+}
+
+impl Player {
+    pub fn new(alias: String) -> Self {
+        Self {
+            alias,
+        }
+    }
+}
+
+impl Component for Player {
+    type Storage = FlaggedStorage<Self, VecStorage<Self>>;
+}
diff --git a/common/src/comp/uid.rs b/common/src/comp/uid.rs
deleted file mode 100644
index 6ea657dada..0000000000
--- a/common/src/comp/uid.rs
+++ /dev/null
@@ -1,84 +0,0 @@
-use std::{
-    collections::HashMap,
-    ops::Range,
-    u64,
-    fmt,
-};
-use specs::{
-    saveload::{Marker, MarkerAllocator},
-    world::EntitiesRes,
-    Component,
-    VecStorage,
-    Entity,
-    Join,
-    ReadStorage,
-};
-
-#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
-pub struct Uid(pub u64);
-
-impl Into<u64> for Uid {
-    fn into(self) -> u64 {
-        self.0
-    }
-}
-
-impl fmt::Display for Uid {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.0)
-    }
-}
-
-impl Component for Uid {
-    type Storage = VecStorage<Self>;
-}
-
-impl Marker for Uid {
-    type Identifier = u64;
-    type Allocator = UidAllocator;
-
-    fn id(&self) -> u64 { self.0 }
-
-    fn update(&mut self, update: Self) {
-        assert_eq!(self.0, update.0);
-    }
-}
-
-pub struct UidAllocator {
-    pub(crate) range: Range<u64>,
-    pub(crate) mapping: HashMap<u64, Entity>,
-}
-
-impl UidAllocator {
-    pub fn new() -> Self {
-        Self {
-            range: 0..u64::MAX,
-            mapping: HashMap::new(),
-        }
-    }
-}
-
-impl MarkerAllocator<Uid> for UidAllocator {
-    fn allocate(&mut self, entity: Entity, id: Option<u64>) -> Uid {
-        let id = id.unwrap_or_else(|| {
-            self.range.next().expect("
-                Id range must be effectively endless.
-                Somehow, you ran this program for longer than the lifetime of the universe.
-                It's probably time to stop playing and prepare for your imminent extinction.
-            ")
-        });
-        self.mapping.insert(id, entity);
-        Uid(id)
-    }
-
-    fn retrieve_entity_internal(&self, id: u64) -> Option<Entity> {
-        self.mapping.get(&id).cloned()
-    }
-
-    fn maintain(&mut self, entities: &EntitiesRes, storage: &ReadStorage<Uid>) {
-        self.mapping = (&*entities, storage)
-            .join()
-            .map(|(e, m)| (m.id(), e))
-            .collect();
-    }
-}
diff --git a/common/src/comp/util.rs b/common/src/comp/util.rs
deleted file mode 100644
index 0ea2d35ebc..0000000000
--- a/common/src/comp/util.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Library
-use specs::{Component, NullStorage};
-use vek::*;
-
-// Pos
-
-#[derive(Copy, Clone, Debug, Default)]
-pub struct New;
-
-impl Component for New {
-    type Storage = NullStorage<Self>;
-}
diff --git a/common/src/lib.rs b/common/src/lib.rs
index 9fc68777e4..72bcade3f8 100644
--- a/common/src/lib.rs
+++ b/common/src/lib.rs
@@ -1,4 +1,4 @@
-#![feature(euclidean_division, duration_float, try_from, trait_alias)]
+#![feature(euclidean_division, duration_float, trait_alias)]
 
 #[macro_use]
 extern crate serde_derive;
diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs
index 149cd07ad4..e8b59414ed 100644
--- a/common/src/msg/client.rs
+++ b/common/src/msg/client.rs
@@ -1,17 +1,18 @@
-use crate::comp::{
-    Uid,
-    phys,
-};
+use crate::comp;
 
 #[derive(Clone, Debug, Serialize, Deserialize)]
 pub enum ClientMsg {
+    Connect {
+        player: comp::Player,
+        character: Option<comp::Character>,
+    },
     Ping,
     Pong,
     Chat(String),
     PlayerPhysics {
-        pos: phys::Pos,
-        vel: phys::Vel,
-        dir: phys::Dir,
+        pos: comp::phys::Pos,
+        vel: comp::phys::Vel,
+        dir: comp::phys::Dir,
     },
     Disconnect,
 }
diff --git a/common/src/msg/ecs_packet.rs b/common/src/msg/ecs_packet.rs
new file mode 100644
index 0000000000..a3b4a9e463
--- /dev/null
+++ b/common/src/msg/ecs_packet.rs
@@ -0,0 +1,29 @@
+use std::marker::PhantomData;
+use serde_derive::{Serialize, Deserialize};
+use crate::comp;
+
+// Automatically derive From<T> for Packet for each variant Packet::T(T)
+sphynx::sum_type! {
+    #[derive(Clone, Debug, Serialize, Deserialize)]
+    pub enum EcsPacket {
+        Pos(comp::phys::Pos),
+        Vel(comp::phys::Vel),
+        Dir(comp::phys::Dir),
+        Character(comp::Character),
+        Player(comp::Player),
+    }
+}
+// Automatically derive From<T> for Phantom for each variant Phantom::T(PhantomData<T>)
+sphynx::sum_type! {
+    #[derive(Clone, Debug, Serialize, Deserialize)]
+    pub enum EcsPhantom {
+        Pos(PhantomData<comp::phys::Pos>),
+        Vel(PhantomData<comp::phys::Vel>),
+        Dir(PhantomData<comp::phys::Dir>),
+        Character(PhantomData<comp::Character>),
+        Player(PhantomData<comp::Player>),
+    }
+}
+impl sphynx::Packet for EcsPacket {
+    type Phantom = EcsPhantom;
+}
diff --git a/common/src/msg/mod.rs b/common/src/msg/mod.rs
index ee18da8f4d..b38939eeb2 100644
--- a/common/src/msg/mod.rs
+++ b/common/src/msg/mod.rs
@@ -1,6 +1,8 @@
+pub mod ecs_packet;
 pub mod server;
 pub mod client;
 
 // Reexports
-pub use server::ServerMsg;
-pub use client::ClientMsg;
+pub use self::server::ServerMsg;
+pub use self::client::ClientMsg;
+pub use self::ecs_packet::EcsPacket;
diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs
index 871215138e..21a21f506e 100644
--- a/common/src/msg/server.rs
+++ b/common/src/msg/server.rs
@@ -1,20 +1,15 @@
-use crate::comp::{
-    Uid,
-    phys,
-};
+use super::EcsPacket;
 
 #[derive(Clone, Debug, Serialize, Deserialize)]
 pub enum ServerMsg {
+    Handshake {
+        ecs_state: sphynx::StatePackage<EcsPacket>,
+        player_entity: u64,
+    },
     Shutdown,
     Ping,
     Pong,
     Chat(String),
-    SetPlayerEntity(Uid),
-    EntityPhysics {
-        uid: Uid,
-        pos: phys::Pos,
-        vel: phys::Vel,
-        dir: phys::Dir,
-    },
-    EntityDeleted(Uid),
+    SetPlayerEntity(u64),
+    EcsSync(sphynx::SyncPackage<EcsPacket>),
 }
diff --git a/common/src/net/post.rs b/common/src/net/post.rs
index b9160ec35b..afd3d8956d 100644
--- a/common/src/net/post.rs
+++ b/common/src/net/post.rs
@@ -251,6 +251,45 @@ impl<S: PostSend, R: PostRecv> PostBox<S, R> {
         let _ = self.send_tx.send(data);
     }
 
+    // TODO: This method is super messy
+    pub fn next_message(&mut self) -> Option<R> {
+        if self.err.is_some() {
+            return None;
+        }
+
+        loop {
+            let mut events = Events::with_capacity(10);
+            if let Err(err) = self.poll.poll(
+                &mut events,
+                Some(Duration::new(0, 0)),
+            ) {
+                self.err = Some(err.into());
+                return None;
+            }
+
+            for event in events {
+                match event.token() {
+                    // Keep reading new messages from the channel
+                    RECV_TOK => loop {
+                        match self.recv_rx.try_recv() {
+                            Ok(Ok(msg)) => return Some(msg),
+                            Err(TryRecvError::Empty) => break,
+                            Err(err) => {
+                                self.err = Some(err.into());
+                                return None;
+                            },
+                            Ok(Err(err)) => {
+                                self.err = Some(err);
+                                return None;
+                            },
+                        }
+                    },
+                    tok => panic!("Unexpected event token '{:?}'", tok),
+                }
+            }
+        }
+    }
+
     pub fn new_messages(&mut self) -> impl ExactSizeIterator<Item=R> {
         let mut msgs = VecDeque::new();
 
diff --git a/common/src/state.rs b/common/src/state.rs
index b395dd35de..1e7f9a076d 100644
--- a/common/src/state.rs
+++ b/common/src/state.rs
@@ -6,18 +6,19 @@ use specs::{
     DispatcherBuilder,
     EntityBuilder as EcsEntityBuilder,
     Entity as EcsEntity,
-    World as EcsWorld,
     storage::{
         Storage as EcsStorage,
         MaskedStorage as EcsMaskedStorage,
     },
     saveload::{MarkedBuilder, MarkerAllocator},
 };
+use sphynx;
 use vek::*;
 use crate::{
     comp,
     sys,
     terrain::TerrainMap,
+    msg::EcsPacket,
 };
 
 /// How much faster should an in-game day be compared to a real day?
@@ -59,95 +60,74 @@ impl Changes {
 /// A type used to represent game state stored on both the client and the server. This includes
 /// things like entity components, terrain data, and global state like weather, time of day, etc.
 pub struct State {
-    ecs_world: EcsWorld,
+    ecs: sphynx::World<EcsPacket>,
     changes: Changes,
 }
 
 impl State {
     /// Create a new `State`.
     pub fn new() -> Self {
-        let mut ecs_world = EcsWorld::new();
-
-        // Register resources used by the ECS
-        ecs_world.add_resource(TimeOfDay(0.0));
-        ecs_world.add_resource(Time(0.0));
-        ecs_world.add_resource(DeltaTime(0.0));
-        ecs_world.add_resource(TerrainMap::new());
-
-        // Register common components with the state
-        comp::register_local_components(&mut ecs_world);
-
         Self {
-            ecs_world,
+            ecs: sphynx::World::new(specs::World::new(), Self::setup_sphynx_world),
             changes: Changes::default(),
         }
     }
 
+    /// Create a new `State` from an ECS state package
+    pub fn from_state_package(state_package: sphynx::StatePackage<EcsPacket>) -> Self {
+        Self {
+            ecs: sphynx::World::from_state_package(specs::World::new(), Self::setup_sphynx_world, state_package),
+            changes: Changes::default(),
+        }
+    }
+
+    // Create a new Sphynx ECS world
+    fn setup_sphynx_world(ecs: &mut sphynx::World<EcsPacket>) {
+        // Register synced components
+        ecs.register_synced::<comp::phys::Pos>();
+        ecs.register_synced::<comp::phys::Vel>();
+        ecs.register_synced::<comp::phys::Dir>();
+        ecs.register_synced::<comp::Character>();
+        ecs.register_synced::<comp::Player>();
+
+        // Register resources used by the ECS
+        ecs.internal_mut().add_resource(TimeOfDay(0.0));
+        ecs.internal_mut().add_resource(Time(0.0));
+        ecs.internal_mut().add_resource(DeltaTime(0.0));
+        ecs.internal_mut().add_resource(TerrainMap::new());
+    }
+
     /// Register a component with the state's ECS
     pub fn with_component<T: Component>(mut self) -> Self
         where <T as Component>::Storage: Default
     {
-        self.ecs_world.register::<T>();
+        self.ecs.internal_mut().register::<T>();
         self
     }
 
-    /// Build a new entity with a generated UID
-    pub fn build_uid_entity(&mut self) -> EcsEntityBuilder {
-        self.ecs_world.create_entity()
-            .with(comp::util::New)
-            .marked::<comp::Uid>()
-    }
-
-    /// Build an entity with a specific UID
-    pub fn build_uid_entity_with_uid(&mut self, uid: comp::Uid) -> EcsEntityBuilder {
-        let builder = self.build_uid_entity();
-
-        builder.world
-            .write_resource::<comp::UidAllocator>()
-            .allocate(builder.entity, Some(uid.into()));
-
-        builder
-    }
-
-    /// Get an entity from its UID, if it exists
-    pub fn get_entity(&self, uid: comp::Uid) -> Option<EcsEntity> {
-        // Find the ECS entity from its UID
-        self.ecs_world
-            .read_resource::<comp::UidAllocator>()
-            .retrieve_entity_internal(uid.into())
-    }
-
-    /// Delete an entity from the state's ECS, if it exists
-    pub fn delete_entity(&mut self, uid: comp::Uid) {
-        // Find the ECS entity from its UID
-        let ecs_entity = self.ecs_world
-            .read_resource::<comp::UidAllocator>()
-            .retrieve_entity_internal(uid.into());
-
-        // Delete the ECS entity, if it exists
-        if let Some(ecs_entity) = ecs_entity {
-            let _ = self.ecs_world.delete_entity(ecs_entity);
-        }
-    }
-
     /// Write a component attributed to a particular entity
     pub fn write_component<C: Component>(&mut self, entity: EcsEntity, comp: C) {
-        let _ = self.ecs_world.write_storage().insert(entity, comp);
+        let _ = self.ecs.internal_mut().write_storage().insert(entity, comp);
+    }
+
+    /// Read a component attributed to a particular entity
+    pub fn read_component_cloned<C: Component + Clone>(&self, entity: EcsEntity) -> Option<C> {
+        self.ecs.internal().read_storage().get(entity).cloned()
     }
 
     /// Get a read-only reference to the storage of a particular component type
     pub fn read_storage<C: Component>(&self) -> EcsStorage<C, Fetch<EcsMaskedStorage<C>>> {
-        self.ecs_world.read_storage::<C>()
+        self.ecs.internal().read_storage::<C>()
     }
 
     /// Get a reference to the internal ECS world
-    pub fn ecs_world(&self) -> &EcsWorld {
-        &self.ecs_world
+    pub fn ecs(&self) -> &sphynx::World<EcsPacket> {
+        &self.ecs
     }
 
     /// Get a mutable reference to the internal ECS world
-    pub fn ecs_world_mut(&mut self) -> &mut EcsWorld {
-        &mut self.ecs_world
+    pub fn ecs_mut(&mut self) -> &mut sphynx::World<EcsPacket> {
+        &mut self.ecs
     }
 
     /// Get a reference to the `Changes` structure of the state. This contains
@@ -156,54 +136,46 @@ impl State {
         &self.changes
     }
 
-    // TODO: Get rid of this since it shouldn't be needed
-    pub fn changes_mut(&mut self) -> &mut Changes {
-        &mut self.changes
-    }
-
     /// Get the current in-game time of day.
     ///
     /// Note that this should not be used for physics, animations or other such localised timings.
     pub fn get_time_of_day(&self) -> f64 {
-        self.ecs_world.read_resource::<TimeOfDay>().0
+        self.ecs.internal().read_resource::<TimeOfDay>().0
     }
 
     /// Get the current in-game time.
     ///
     /// Note that this does not correspond to the time of day.
     pub fn get_time(&self) -> f64 {
-        self.ecs_world.read_resource::<Time>().0
+        self.ecs.internal().read_resource::<Time>().0
     }
 
     /// Get a reference to this state's terrain.
     pub fn terrain(&self) -> Fetch<TerrainMap> {
-        self.ecs_world.read_resource::<TerrainMap>()
+        self.ecs.internal().read_resource::<TerrainMap>()
     }
 
     // TODO: Get rid of this since it shouldn't be needed
     pub fn terrain_mut(&mut self) -> FetchMut<TerrainMap> {
-        self.ecs_world.write_resource::<TerrainMap>()
+        self.ecs.internal_mut().write_resource::<TerrainMap>()
     }
 
     /// Execute a single tick, simulating the game state by the given duration.
     pub fn tick(&mut self, dt: Duration) {
-        // First, wipe all temporary marker components
-        self.ecs_world.write_storage::<comp::util::New>().clear();
-
         // Change the time accordingly
-        self.ecs_world.write_resource::<TimeOfDay>().0 += dt.as_secs_f64() * DAY_CYCLE_FACTOR;
-        self.ecs_world.write_resource::<Time>().0 += dt.as_secs_f64();
+        self.ecs.internal_mut().write_resource::<TimeOfDay>().0 += dt.as_secs_f64() * DAY_CYCLE_FACTOR;
+        self.ecs.internal_mut().write_resource::<Time>().0 += dt.as_secs_f64();
 
         // Run systems to update the world
-        self.ecs_world.write_resource::<DeltaTime>().0 = dt.as_secs_f64();
+        self.ecs.internal_mut().write_resource::<DeltaTime>().0 = dt.as_secs_f64();
 
         // Create and run dispatcher for ecs systems
         let mut dispatch_builder = DispatcherBuilder::new();
         sys::add_local_systems(&mut dispatch_builder);
         // This dispatches all the systems in parallel
-        dispatch_builder.build().dispatch(&self.ecs_world.res);
+        dispatch_builder.build().dispatch(&self.ecs.internal_mut().res);
 
-        self.ecs_world.maintain();
+        self.ecs.internal_mut().maintain();
     }
 
     /// Clean up the state after a tick
diff --git a/server-cli/src/main.rs b/server-cli/src/main.rs
index 244f324a3d..1070bbf482 100644
--- a/server-cli/src/main.rs
+++ b/server-cli/src/main.rs
@@ -24,9 +24,9 @@ fn main() {
 
         for event in events {
             match event {
-                Event::ClientConnected { ecs_entity } => info!("Client connected!"),
-                Event::ClientDisconnected { ecs_entity } => info!("Client disconnected!"),
-                Event::Chat { ecs_entity, msg } => info!("[Client] {}", msg),
+                Event::ClientConnected { entity } => info!("Client connected!"),
+                Event::ClientDisconnected { entity } => info!("Client disconnected!"),
+                Event::Chat { entity, msg } => info!("[Client] {}", msg),
             }
         }
 
diff --git a/server/src/client.rs b/server/src/client.rs
index 8030fb03e5..fed88d9ae4 100644
--- a/server/src/client.rs
+++ b/server/src/client.rs
@@ -6,12 +6,25 @@ use common::{
 };
 use crate::Error;
 
+#[derive(PartialEq)]
+pub enum ClientState {
+    Connecting,
+    Connected,
+}
+
 pub struct Client {
-    pub ecs_entity: EcsEntity,
+    pub state: ClientState,
+    pub entity: EcsEntity,
     pub postbox: PostBox<ServerMsg, ClientMsg>,
     pub last_ping: f64,
 }
 
+impl Client {
+    pub fn notify(&mut self, msg: ServerMsg) {
+        self.postbox.send(msg);
+    }
+}
+
 pub struct Clients {
     clients: Vec<Client>,
 }
@@ -31,15 +44,17 @@ impl Clients {
         self.clients.drain_filter(f);
     }
 
-    pub fn notify_all(&mut self, msg: ServerMsg) {
+    pub fn notify_connected(&mut self, msg: ServerMsg) {
         for client in &mut self.clients {
-            client.postbox.send(msg.clone());
+            if client.state == ClientState::Connected {
+                client.postbox.send(msg.clone());
+            }
         }
     }
 
-    pub fn notify_all_except(&mut self, ecs_entity: EcsEntity, msg: ServerMsg) {
+    pub fn notify_connected_except(&mut self, entity: EcsEntity, msg: ServerMsg) {
         for client in &mut self.clients {
-            if client.ecs_entity != ecs_entity {
+            if client.entity != entity && client.state == ClientState::Connected {
                 client.postbox.send(msg.clone());
             }
         }
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 867d4b1b6b..937c70368c 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -30,6 +30,7 @@ use common::{
 };
 use world::World;
 use crate::client::{
+    ClientState,
     Client,
     Clients,
 };
@@ -38,13 +39,13 @@ const CLIENT_TIMEOUT: f64 = 5.0; // Seconds
 
 pub enum Event {
     ClientConnected {
-        ecs_entity: EcsEntity,
+        entity: EcsEntity,
     },
     ClientDisconnected {
-        ecs_entity: EcsEntity,
+        entity: EcsEntity,
     },
     Chat {
-        ecs_entity: EcsEntity,
+        entity: EcsEntity,
         msg: String,
     },
 }
@@ -77,15 +78,6 @@ impl Server {
     #[allow(dead_code)]
     pub fn state_mut(&mut self) -> &mut State { &mut self.state }
 
-    /// Build a new player with a generated UID
-    pub fn build_player(&mut self) -> EcsEntityBuilder {
-        self.state.build_uid_entity()
-            .with(comp::phys::Pos(Vec3::zero()))
-            .with(comp::phys::Vel(Vec3::zero()))
-            .with(comp::phys::Dir(Vec3::unit_y()))
-            .with(comp::phys::UpdateKind::Passive)
-    }
-
     /// Get a reference to the server's world.
     #[allow(dead_code)]
     pub fn world(&self) -> &World { &self.world }
@@ -146,23 +138,20 @@ impl Server {
         let mut frontend_events = Vec::new();
 
         for mut postbox in self.postoffice.new_connections() {
-            let ecs_entity = self.build_player()
-                // When the player is first created, force a physics notification to everyone
-                // including themselves.
-                .with(comp::phys::UpdateKind::Force)
+            let entity = self.state
+                .ecs_mut()
+                .create_entity_synced()
                 .build();
-            let uid = self.state.read_storage().get(ecs_entity).cloned().unwrap();
-
-            postbox.send(ServerMsg::SetPlayerEntity(uid));
 
             self.clients.add(Client {
-                ecs_entity,
+                state: ClientState::Connecting,
+                entity,
                 postbox,
                 last_ping: self.state.get_time(),
             });
 
             frontend_events.push(Event::ClientConnected {
-                ecs_entity,
+                entity,
             });
         }
 
@@ -178,7 +167,7 @@ impl Server {
         let mut disconnected_clients = Vec::new();
 
         self.clients.remove_if(|client| {
-            let mut disconnected = false;
+            let mut disconnect = false;
             let new_msgs = client.postbox.new_messages();
 
             // Update client ping
@@ -187,30 +176,56 @@ impl Server {
 
                 // Process incoming messages
                 for msg in new_msgs {
-                    match msg {
-                        ClientMsg::Ping => client.postbox.send(ServerMsg::Pong),
-                        ClientMsg::Pong => {},
-                        ClientMsg::Chat(msg) => new_chat_msgs.push((client.ecs_entity, msg)),
-                        ClientMsg::PlayerPhysics { pos, vel, dir } => {
-                            state.write_component(client.ecs_entity, pos);
-                            state.write_component(client.ecs_entity, vel);
-                            state.write_component(client.ecs_entity, dir);
+                    match client.state {
+                        ClientState::Connecting => match msg {
+                            ClientMsg::Connect { player, character } => {
+
+                                // Write client components
+                                state.write_component(client.entity, player);
+                                if let Some(character) = character {
+                                    state.write_component(client.entity, character);
+                                }
+
+                                client.state = ClientState::Connected;
+
+                                // Return a handshake with the state of the current world
+                                client.notify(ServerMsg::Handshake {
+                                    ecs_state: state.ecs().gen_state_package(),
+                                    player_entity: state
+                                        .ecs()
+                                        .uid_from_entity(client.entity)
+                                        .unwrap()
+                                        .into(),
+                                });
+                            },
+                            _ => disconnect = true,
+                        },
+                        ClientState::Connected => match msg {
+                            ClientMsg::Connect { .. } => disconnect = true, // Not allowed when already connected
+                            ClientMsg::Ping => client.postbox.send(ServerMsg::Pong),
+                            ClientMsg::Pong => {},
+                            ClientMsg::Chat(msg) => new_chat_msgs.push((client.entity, msg)),
+                            ClientMsg::PlayerPhysics { pos, vel, dir } => {
+                                state.write_component(client.entity, pos);
+                                state.write_component(client.entity, vel);
+                                state.write_component(client.entity, dir);
+                            },
+                            ClientMsg::Disconnect => disconnect = true,
                         },
-                        ClientMsg::Disconnect => disconnected = true,
                     }
                 }
             } else if
                 state.get_time() - client.last_ping > CLIENT_TIMEOUT || // Timeout
                 client.postbox.error().is_some() // Postbox error
             {
-                disconnected = true;
+                disconnect = true;
             } else if state.get_time() - client.last_ping > CLIENT_TIMEOUT * 0.5 {
                 // Try pinging the client if the timeout is nearing
                 client.postbox.send(ServerMsg::Ping);
             }
 
-            if disconnected {
-                disconnected_clients.push(client.ecs_entity);
+            if disconnect {
+                disconnected_clients.push(client.entity);
                 true
             } else {
                 false
@@ -218,24 +233,30 @@ impl Server {
         });
 
         // Handle new chat messages
-        for (ecs_entity, msg) in new_chat_msgs {
-            self.clients.notify_all(ServerMsg::Chat(msg.clone()));
+        for (entity, msg) in new_chat_msgs {
+            self.clients.notify_connected(ServerMsg::Chat(match state
+                .ecs()
+                .internal()
+                .read_storage::<comp::Player>()
+                .get(entity)
+            {
+                Some(player) => format!("[{}] {}", &player.alias, msg),
+                None => format!("[<anon>] {}", msg),
+            }));
 
             frontend_events.push(Event::Chat {
-                ecs_entity,
+                entity,
                 msg,
             });
         }
 
         // Handle client disconnects
-        for ecs_entity in disconnected_clients {
-            self.clients.notify_all(ServerMsg::EntityDeleted(state.read_storage().get(ecs_entity).cloned().unwrap()));
+        for entity in disconnected_clients {
+            state.ecs_mut().delete_entity_synced(entity);
 
             frontend_events.push(Event::ClientDisconnected {
-                ecs_entity,
+                entity,
             });
-
-            state.ecs_world_mut().delete_entity(ecs_entity);
         }
 
         Ok(frontend_events)
@@ -243,36 +264,12 @@ impl Server {
 
     /// Sync client states with the most up to date information
     fn sync_clients(&mut self) {
-        for (entity, &uid, &pos, &vel, &dir, update_kind) in (
-            &self.state.ecs_world().entities(),
-            &self.state.ecs_world().read_storage::<comp::Uid>(),
-            &self.state.ecs_world().read_storage::<comp::phys::Pos>(),
-            &self.state.ecs_world().read_storage::<comp::phys::Vel>(),
-            &self.state.ecs_world().read_storage::<comp::phys::Dir>(),
-            &mut self.state.ecs_world().write_storage::<comp::phys::UpdateKind>(),
-        ).join() {
-            let msg = ServerMsg::EntityPhysics {
-                uid,
-                pos,
-                vel,
-                dir,
-            };
-
-            // Sometimes we need to force updated (i.e: teleporting players). This involves sending
-            // everyone, including the player themselves, of their new physics information.
-            match update_kind {
-                comp::phys::UpdateKind::Force => self.clients.notify_all(msg),
-                comp::phys::UpdateKind::Passive => self.clients.notify_all_except(entity, msg),
-            }
-
-            // Now that the update has occured, default to a passive update
-            *update_kind = comp::phys::UpdateKind::Passive;
-        }
+        self.clients.notify_connected(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package()));
     }
 }
 
 impl Drop for Server {
     fn drop(&mut self) {
-        self.clients.notify_all(ServerMsg::Shutdown);
+        self.clients.notify_connected(ServerMsg::Shutdown);
     }
 }
diff --git a/voxygen/src/menu/main/mod.rs b/voxygen/src/menu/main/mod.rs
index 0dfe93880d..4b95bb6d46 100644
--- a/voxygen/src/menu/main/mod.rs
+++ b/voxygen/src/menu/main/mod.rs
@@ -6,7 +6,10 @@ use crate::{
     GlobalState, PlayState, PlayStateResult,
 };
 use client::{self, Client};
-use common::clock::Clock;
+use common::{
+    comp,
+    clock::Clock,
+};
 use std::time::Duration;
 use ui::{Event as MainMenuEvent, MainMenuUi};
 use vek::*;
@@ -67,12 +70,12 @@ impl PlayState for MainMenuState {
                             Ok(mut socket_adders) => {
                                 while let Some(socket_addr) = socket_adders.next() {
                                     // TODO: handle error
-                                    match Client::new(socket_addr) {
+                                    match Client::new(socket_addr, comp::Player::new(username.clone()), Some(comp::Character::test())) {
                                         Ok(client) => {
                                             return PlayStateResult::Push(
                                                 Box::new(CharSelectionState::new(
                                                     &mut global_state.window,
-                                                    std::rc::Rc::new(std::cell::RefCell::new(client.with_test_state())) // <--- TODO: Remove this
+                                                    std::rc::Rc::new(std::cell::RefCell::new(client)) // <--- TODO: Remove this
                                                 ))
                                             );
                                         }
diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs
index 9513b6f602..e3e885b1ea 100644
--- a/voxygen/src/scene/mod.rs
+++ b/voxygen/src/scene/mod.rs
@@ -139,7 +139,8 @@ impl Scene {
             .player()
             .and_then(|ent| client
                 .state()
-                .ecs_world()
+                .ecs()
+                .internal()
                 .read_storage::<comp::phys::Pos>()
                 .get(ent)
                 .map(|pos| pos.0)
diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs
index 2d4f4911c5..d11a6dfa13 100644
--- a/voxygen/src/session.rs
+++ b/voxygen/src/session.rs
@@ -105,6 +105,7 @@ impl PlayState for SessionState {
         let mut clock = Clock::new();
 
         // Load a few chunks TODO: Remove this
+        /*
         for x in -6..7 {
             for y in -6..7 {
                 for z in -1..2 {
@@ -112,6 +113,7 @@ impl PlayState for SessionState {
                 }
             }
         }
+        */
 
         // Game loop
         loop {

From bd51eddd6223fa30b9909b5f7a044745f2223651 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Wed, 10 Apr 2019 22:51:14 +0100
Subject: [PATCH 02/16] Moved figure rendering to a better place

Former-commit-id: 51ca948e131c20151c97f9f8454c80c47a9154b0
---
 client/src/lib.rs           |  15 +---
 server/src/lib.rs           |   3 +
 voxygen/src/anim/mod.rs     |   2 +-
 voxygen/src/scene/figure.rs | 153 +++++++++++++++++++++++-------------
 voxygen/src/scene/mod.rs    |  60 +++-----------
 voxygen/src/session.rs      |   4 +-
 6 files changed, 119 insertions(+), 118 deletions(-)

diff --git a/client/src/lib.rs b/client/src/lib.rs
index 0fcccc1e27..0101408ed4 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -67,7 +67,6 @@ impl Client {
         // Wait for handshake from server
         let (state, player) = match postbox.next_message() {
             Some(ServerMsg::Handshake { ecs_state, player_entity }) => {
-                println!("STATE PACKAGE! {:?}", ecs_state);
                 let mut state = State::from_state_package(ecs_state);
                 let player_entity = state.ecs().entity_from_uid(player_entity);
                 (state, player_entity)
@@ -99,12 +98,6 @@ impl Client {
     #[allow(dead_code)]
     pub fn thread_pool(&self) -> &threadpool::ThreadPool { &self.thread_pool }
 
-    // TODO: Get rid of this
-    pub fn with_test_state(mut self) -> Self {
-        self.chunk = Some(self.world.generate_chunk(Vec3::zero()));
-        self
-    }
-
     /// Get a reference to the client's game state.
     #[allow(dead_code)]
     pub fn state(&self) -> &State { &self.state }
@@ -158,6 +151,9 @@ impl Client {
             const PLAYER_VELOCITY: f32 = 100.0;
             // TODO: Set acceleration instead
             self.state.write_component(ecs_entity, comp::phys::Vel(Vec3::from(input.move_dir * PLAYER_VELOCITY)));
+            if input.move_dir.magnitude() > 0.01 {
+                self.state.write_component(ecs_entity, comp::phys::Dir(input.move_dir.normalized().into()));
+            }
         }
 
         // Tick the client's LocalState (step 3)
@@ -207,10 +203,7 @@ impl Client {
                     ServerMsg::Pong => {},
                     ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
                     ServerMsg::SetPlayerEntity(uid) => self.player = Some(self.state.ecs().entity_from_uid(uid).unwrap()), // TODO: Don't unwrap here!
-                    ServerMsg::EcsSync(sync_package) => {
-                        println!("SYNC PACKAGE! {:?}", sync_package);
-                        self.state.ecs_mut().sync_with_package(sync_package)
-                    },
+                    ServerMsg::EcsSync(sync_package) => self.state.ecs_mut().sync_with_package(sync_package),
                 }
             }
         } else if let Some(err) = self.postbox.error() {
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 937c70368c..35946c683e 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -182,6 +182,9 @@ impl Server {
 
                                 // Write client components
                                 state.write_component(client.entity, player);
+                                state.write_component(client.entity, comp::phys::Pos(Vec3::zero()));
+                                state.write_component(client.entity, comp::phys::Vel(Vec3::zero()));
+                                state.write_component(client.entity, comp::phys::Dir(Vec3::unit_y()));
                                 if let Some(character) = character {
                                     state.write_component(client.entity, character);
                                 }
diff --git a/voxygen/src/anim/mod.rs b/voxygen/src/anim/mod.rs
index 088f56a4ca..be609f0d59 100644
--- a/voxygen/src/anim/mod.rs
+++ b/voxygen/src/anim/mod.rs
@@ -25,7 +25,7 @@ impl Bone {
     }
 }
 
-pub trait Skeleton {
+pub trait Skeleton: Send + Sync + 'static {
     fn compute_matrices(&self) -> [FigureBoneData; 16];
 }
 
diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs
index 8418ab5850..e0c5ae6ba4 100644
--- a/voxygen/src/scene/figure.rs
+++ b/voxygen/src/scene/figure.rs
@@ -1,5 +1,14 @@
-use specs::{Component, VecStorage};
+use std::{
+    collections::HashMap,
+    f32,
+};
+use specs::{Entity as EcsEntity, Component, VecStorage, Join};
 use vek::*;
+use client::Client;
+use common::{
+    comp,
+    figure::Segment,
+};
 use crate::{
     Error,
     render::{
@@ -12,42 +21,50 @@ use crate::{
         FigureBoneData,
         FigureLocals,
     },
-    anim::Skeleton,
+    anim::{
+        Animation,
+        Skeleton,
+        character::{
+            CharacterSkeleton,
+            RunAnimation,
+        },
+    },
+    mesh::Meshable,
 };
 
-pub struct Figure<S: Skeleton> {
-    // GPU data
-    model: Model<FigurePipeline>,
-    bone_consts: Consts<FigureBoneData>,
-    locals: Consts<FigureLocals>,
-
-    // CPU data
-    bone_meshes: [Option<Mesh<FigurePipeline>>; 16],
-    pub skeleton: S,
+pub struct Figures {
+    test_model: Model<FigurePipeline>,
+    states: HashMap<EcsEntity, FigureState<CharacterSkeleton>>,
 }
 
-impl<S: Skeleton> Figure<S> {
-    pub fn new(
-        renderer: &mut Renderer,
-        bone_meshes: [Option<Mesh<FigurePipeline>>; 16],
-        skeleton: S,
-    ) -> Result<Self, Error> {
-        let mut this = Self {
-            model: renderer.create_model(&Mesh::new())?,
-            bone_consts: renderer.create_consts(&skeleton.compute_matrices())?,
-            locals: renderer.create_consts(&[FigureLocals::default()])?,
+impl Figures {
+    pub fn new(renderer: &mut Renderer) -> Self {
+        // TODO: Make a proper asset loading system
+        fn load_segment(filename: &'static str) -> Segment {
+            Segment::from(dot_vox::load(&(concat!(env!("CARGO_MANIFEST_DIR"), "/../assets/voxygen/voxel/").to_string() + filename)).unwrap())
+        }
 
-            bone_meshes,
-            skeleton,
-        };
-        this.update_model(renderer)?;
-        Ok(this)
-    }
+        let bone_meshes = [
+            Some(load_segment("head.vox").generate_mesh(Vec3::new(-7.0, -6.5, -6.0))),
+            Some(load_segment("chest.vox").generate_mesh(Vec3::new(-6.0, -3.0, 0.0))),
+            Some(load_segment("belt.vox").generate_mesh(Vec3::new(-5.0, -3.0, 0.0))),
+            Some(load_segment("pants.vox").generate_mesh(Vec3::new(-5.0, -3.0, 0.0))),
+            Some(load_segment("hand.vox").generate_mesh(Vec3::new(-2.0, -2.0, -1.0))),
+            Some(load_segment("hand.vox").generate_mesh(Vec3::new(-2.0, -2.0, -1.0))),
+            Some(load_segment("foot.vox").generate_mesh(Vec3::new(-2.5, -3.0, -2.0))),
+            Some(load_segment("foot.vox").generate_mesh(Vec3::new(-2.5, -3.0, -2.0))),
+            Some(load_segment("sword.vox").generate_mesh(Vec3::new(-6.5, -1.0, 0.0))),
+            None,
+            None,
+            None,
+            None,
+            None,
+            None,
+            None,
+        ];
 
-    pub fn update_model(&mut self, renderer: &mut Renderer) -> Result<(), Error> {
         let mut mesh = Mesh::new();
-
-        self.bone_meshes
+        bone_meshes
             .iter()
             .enumerate()
             .filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
@@ -55,39 +72,69 @@ impl<S: Skeleton> Figure<S> {
                 mesh.push_mesh_map(bone_mesh, |vert| vert.with_bone_idx(i as u8))
             });
 
-        self.model = renderer.create_model(&mesh)?;
-        Ok(())
+        Self {
+            test_model: renderer.create_model(&mesh).unwrap(),
+            states: HashMap::new(),
+        }
     }
 
-    pub fn update_skeleton(&mut self, renderer: &mut Renderer) -> Result<(), Error> {
-        renderer.update_consts(&mut self.bone_consts, &self.skeleton.compute_matrices())?;
-        Ok(())
+    pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
+        let time = client.state().get_time();
+        let ecs = client.state_mut().ecs_mut().internal_mut();
+        for (entity, pos, dir, character) in (
+            &ecs.entities(),
+            &ecs.read_storage::<comp::phys::Pos>(),
+            &ecs.read_storage::<comp::phys::Dir>(),
+            &ecs.read_storage::<comp::Character>(),
+        ).join() {
+            let state = self.states
+                .entry(entity)
+                .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
+
+            state.update(renderer, pos.0, dir.0);
+
+            RunAnimation::update_skeleton(&mut state.skeleton, time);
+        }
+
+        self.states.retain(|entity, _| ecs.entities().is_alive(*entity));
     }
 
-    pub fn update_locals(&mut self, renderer: &mut Renderer, locals: FigureLocals) -> Result<(), Error> {
-        renderer.update_consts(&mut self.locals, &[locals])?;
-        Ok(())
-    }
-
-    pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
-        renderer.render_figure(
-            &self.model,
-            globals,
-            &self.locals,
-            &self.bone_consts,
-        );
+    pub fn render(&self, renderer: &mut Renderer, client: &Client, globals: &Consts<Globals>) {
+        for state in self.states.values() {
+            renderer.render_figure(
+                &self.test_model,
+                globals,
+                &state.locals,
+                &state.bone_consts,
+            );
+        }
     }
 }
 
-/*
-#[derive(Copy, Clone, Debug)]
-pub struct Figure<S: Skeleton> {
+pub struct FigureState<S: Skeleton> {
     bone_consts: Consts<FigureBoneData>,
     locals: Consts<FigureLocals>,
     skeleton: S,
 }
 
-impl<S: Skeleton> Component for Figure<S> {
-    type Storage = VecStorage<Self>;
+impl<S: Skeleton> FigureState<S> {
+    pub fn new(renderer: &mut Renderer, skeleton: S) -> Self {
+        Self {
+            bone_consts: renderer.create_consts(&skeleton.compute_matrices()).unwrap(),
+            locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
+            skeleton,
+        }
+    }
+
+    fn update(&mut self, renderer: &mut Renderer, pos: Vec3<f32>, dir: Vec3<f32>) {
+        let mat =
+            Mat4::<f32>::identity() *
+            Mat4::translation_3d(pos) *
+            Mat4::rotation_z(dir.y.atan2(dir.x) + f32::consts::PI / 2.0);
+
+        let locals = FigureLocals::new(mat);
+        renderer.update_consts(&mut self.locals, &[locals]).unwrap();
+
+        renderer.update_consts(&mut self.bone_consts, &self.skeleton.compute_matrices()).unwrap();
+    }
 }
-*/
diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs
index e3e885b1ea..d2324d6758 100644
--- a/voxygen/src/scene/mod.rs
+++ b/voxygen/src/scene/mod.rs
@@ -29,7 +29,7 @@ use crate::{
 };
 use self::{
     camera::Camera,
-    figure::Figure,
+    figure::Figures,
     terrain::Terrain,
 };
 
@@ -47,13 +47,7 @@ pub struct Scene {
 
     skybox: Skybox,
     terrain: Terrain,
-
-    test_figure: Figure<CharacterSkeleton>,
-}
-
-// TODO: Make a proper asset loading system
-fn load_segment(filename: &'static str) -> Segment {
-    Segment::from(dot_vox::load(&(concat!(env!("CARGO_MANIFEST_DIR"), "/../assets/voxygen/voxel/").to_string() + filename)).unwrap())
+    figures: Figures,
 }
 
 impl Scene {
@@ -74,30 +68,7 @@ impl Scene {
                     .unwrap(),
             },
             terrain: Terrain::new(),
-
-            test_figure: Figure::new(
-                renderer,
-                [
-                    Some(load_segment("head.vox").generate_mesh(Vec3::new(-7.0, -6.5, -6.0))),
-                    Some(load_segment("chest.vox").generate_mesh(Vec3::new(-6.0, -3.0, 0.0))),
-                    Some(load_segment("belt.vox").generate_mesh(Vec3::new(-5.0, -3.0, 0.0))),
-                    Some(load_segment("pants.vox").generate_mesh(Vec3::new(-5.0, -3.0, 0.0))),
-                    Some(load_segment("hand.vox").generate_mesh(Vec3::new(-2.0, -2.0, -1.0))),
-                    Some(load_segment("hand.vox").generate_mesh(Vec3::new(-2.0, -2.0, -1.0))),
-                    Some(load_segment("foot.vox").generate_mesh(Vec3::new(-2.5, -3.0, -2.0))),
-                    Some(load_segment("foot.vox").generate_mesh(Vec3::new(-2.5, -3.0, -2.0))),
-                    Some(load_segment("sword.vox").generate_mesh(Vec3::new(-6.5, -1.0, 0.0))),
-                    None,
-                    None,
-                    None,
-                    None,
-                    None,
-                    None,
-                    None,
-                ],
-                CharacterSkeleton::new(),
-            )
-                .unwrap(),
+            figures: Figures::new(renderer),
         }
     }
 
@@ -133,7 +104,7 @@ impl Scene {
     }
 
     /// Maintain data such as GPU constant buffers, models, etc. To be called once per tick.
-    pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
+    pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
         // Get player position
         let player_pos = client
             .player()
@@ -165,24 +136,13 @@ impl Scene {
         )])
             .expect("Failed to update global constants");
 
-        // Maintain the terrain
+        // Maintain the terrain and figures
         self.terrain.maintain(renderer, client);
-
-        // TODO: Don't do this here
-        RunAnimation::update_skeleton(
-            &mut self.test_figure.skeleton,
-            client.state().get_time(),
-        );
-
-        // Calculate player model matrix
-        let model_mat = Mat4::<f32>::translation_3d(player_pos);
-
-        self.test_figure.update_locals(renderer, FigureLocals::new(model_mat)).unwrap();
-        self.test_figure.update_skeleton(renderer).unwrap();
+        self.figures.maintain(renderer, client);
     }
 
     /// Render the scene using the provided `Renderer`
-    pub fn render_to(&self, renderer: &mut Renderer) {
+    pub fn render(&self, renderer: &mut Renderer, client: &Client) {
         // Render the skybox first (it appears over everything else so must be rendered first)
         renderer.render_skybox(
             &self.skybox.model,
@@ -190,10 +150,8 @@ impl Scene {
             &self.skybox.locals,
         );
 
-        // Render terrain
+        // Render terrain and figures
         self.terrain.render(renderer, &self.globals);
-
-        // Render the test figure
-        self.test_figure.render(renderer, &self.globals);
+        self.figures.render(renderer, client, &self.globals);
     }
 }
diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs
index d11a6dfa13..fc9ec54126 100644
--- a/voxygen/src/session.rs
+++ b/voxygen/src/session.rs
@@ -87,7 +87,7 @@ impl SessionState {
         renderer.clear(BG_COLOR);
 
         // Render the screen using the global renderer
-        self.scene.render_to(renderer);
+        self.scene.render(renderer, &self.client.borrow());
         // Draw the UI to the screen
         self.hud.render(renderer);
 
@@ -157,7 +157,7 @@ impl PlayState for SessionState {
                 .expect("Failed to tick the scene");
 
             // Maintain the scene
-            self.scene.maintain(global_state.window.renderer_mut(), &self.client.borrow());
+            self.scene.maintain(global_state.window.renderer_mut(), &mut self.client.borrow_mut());
             // Maintain the UI
             for event in self.hud.maintain(global_state.window.renderer_mut()) {
                 match event {

From 7f6599e95523e972919d632ca0a88cae39c018ba Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Thu, 11 Apr 2019 00:16:29 +0100
Subject: [PATCH 03/16] Started work on server-side chunks

Former-commit-id: 84a6bd7358f67a77043c4b11c787538f073c8d28
---
 client/Cargo.toml             |  1 -
 client/src/lib.rs             | 17 ++++------
 common/src/msg/client.rs      |  2 +-
 common/src/msg/server.rs      |  8 ++++-
 common/src/net/post.rs        |  4 +--
 common/src/state.rs           | 41 ++++++++++++++++-------
 common/src/terrain/biome.rs   |  3 ++
 common/src/terrain/block.rs   |  4 +--
 common/src/terrain/mod.rs     |  6 ++--
 common/src/volumes/chunk.rs   |  2 ++
 common/src/volumes/vol_map.rs |  4 +++
 server/Cargo.toml             |  1 +
 server/src/client.rs          | 32 ++++++++++--------
 server/src/lib.rs             | 63 +++++++++++++++++++++++++++--------
 voxygen/src/menu/main/mod.rs  |  4 +--
 15 files changed, 130 insertions(+), 62 deletions(-)

diff --git a/client/Cargo.toml b/client/Cargo.toml
index ac82be29e1..bc4284934f 100644
--- a/client/Cargo.toml
+++ b/client/Cargo.toml
@@ -6,7 +6,6 @@ edition = "2018"
 
 [dependencies]
 common = { package = "veloren-common", path = "../common" }
-world = { package = "veloren-world", path = "../world" }
 
 specs = "0.14"
 vek = "0.9"
diff --git a/client/src/lib.rs b/client/src/lib.rs
index 0101408ed4..c20cca643c 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -15,7 +15,7 @@ use std::{
     net::SocketAddr,
 };
 use vek::*;
-use threadpool;
+use threadpool::ThreadPool;
 use specs::Builder;
 use common::{
     comp,
@@ -24,7 +24,6 @@ use common::{
     net::PostBox,
     msg::{ClientMsg, ServerMsg},
 };
-use world::World;
 
 const SERVER_TIMEOUT: f64 = 5.0; // Seconds
 
@@ -33,7 +32,7 @@ pub enum Event {
 }
 
 pub struct Client {
-    thread_pool: threadpool::ThreadPool,
+    thread_pool: ThreadPool,
 
     last_ping: f64,
     postbox: PostBox<ClientMsg, ServerMsg>,
@@ -41,10 +40,7 @@ pub struct Client {
     tick: u64,
     state: State,
     player: Option<EcsEntity>,
-
-    // Testing
-    world: World,
-    pub chunk: Option<TerrainChunk>,
+    view_distance: u64,
 }
 
 impl Client {
@@ -54,6 +50,7 @@ impl Client {
         addr: A,
         player: comp::Player,
         character: Option<comp::Character>,
+        view_distance: u64,
     ) -> Result<Self, Error> {
 
         let mut postbox = PostBox::to_server(addr)?;
@@ -85,10 +82,7 @@ impl Client {
             tick: 0,
             state,
             player,
-
-            // Testing
-            world: World::new(),
-            chunk: None,
+            view_distance,
         })
     }
 
@@ -204,6 +198,7 @@ impl Client {
                     ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
                     ServerMsg::SetPlayerEntity(uid) => self.player = Some(self.state.ecs().entity_from_uid(uid).unwrap()), // TODO: Don't unwrap here!
                     ServerMsg::EcsSync(sync_package) => self.state.ecs_mut().sync_with_package(sync_package),
+                    ServerMsg::TerrainChunkUpdate { key, chunk } => self.state.insert_chunk(key, chunk),
                 }
             }
         } else if let Some(err) = self.postbox.error() {
diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs
index e8b59414ed..e2339aada3 100644
--- a/common/src/msg/client.rs
+++ b/common/src/msg/client.rs
@@ -1,6 +1,6 @@
 use crate::comp;
 
-#[derive(Clone, Debug, Serialize, Deserialize)]
+#[derive(Clone, Serialize, Deserialize)]
 pub enum ClientMsg {
     Connect {
         player: comp::Player,
diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs
index 21a21f506e..db0ae2ed81 100644
--- a/common/src/msg/server.rs
+++ b/common/src/msg/server.rs
@@ -1,6 +1,8 @@
+use vek::*;
+use crate::terrain::TerrainChunk;
 use super::EcsPacket;
 
-#[derive(Clone, Debug, Serialize, Deserialize)]
+#[derive(Clone, Serialize, Deserialize)]
 pub enum ServerMsg {
     Handshake {
         ecs_state: sphynx::StatePackage<EcsPacket>,
@@ -12,4 +14,8 @@ pub enum ServerMsg {
     Chat(String),
     SetPlayerEntity(u64),
     EcsSync(sphynx::SyncPackage<EcsPacket>),
+    TerrainChunkUpdate {
+        key: Vec3<i32>,
+        chunk: TerrainChunk,
+    },
 }
diff --git a/common/src/net/post.rs b/common/src/net/post.rs
index afd3d8956d..6338424912 100644
--- a/common/src/net/post.rs
+++ b/common/src/net/post.rs
@@ -56,8 +56,8 @@ impl<T> From<mio_extras::channel::SendError<T>> for Error {
     }
 }
 
-pub trait PostSend = 'static + serde::Serialize + Send + fmt::Debug;
-pub trait PostRecv = 'static + serde::de::DeserializeOwned + Send + fmt::Debug;
+pub trait PostSend = 'static + serde::Serialize + Send;
+pub trait PostRecv = 'static + serde::de::DeserializeOwned + Send;
 
 const TCP_TOK:     Token = Token(0);
 const CTRL_TOK:    Token = Token(1);
diff --git a/common/src/state.rs b/common/src/state.rs
index 1e7f9a076d..6c7a0ba9b9 100644
--- a/common/src/state.rs
+++ b/common/src/state.rs
@@ -1,4 +1,7 @@
-use std::time::Duration;
+use std::{
+    time::Duration,
+    collections::HashSet,
+};
 use shred::{Fetch, FetchMut};
 use specs::{
     Builder,
@@ -17,7 +20,10 @@ use vek::*;
 use crate::{
     comp,
     sys,
-    terrain::TerrainMap,
+    terrain::{
+        TerrainMap,
+        TerrainChunk,
+    },
     msg::EcsPacket,
 };
 
@@ -36,17 +42,17 @@ struct Time(f64);
 pub struct DeltaTime(pub f64);
 
 pub struct Changes {
-    pub new_chunks: Vec<Vec3<i32>>,
-    pub changed_chunks: Vec<Vec3<i32>>,
-    pub removed_chunks: Vec<Vec3<i32>>,
+    pub new_chunks: HashSet<Vec3<i32>>,
+    pub changed_chunks: HashSet<Vec3<i32>>,
+    pub removed_chunks: HashSet<Vec3<i32>>,
 }
 
 impl Changes {
     pub fn default() -> Self {
         Self {
-            new_chunks: vec![],
-            changed_chunks: vec![],
-            removed_chunks: vec![],
+            new_chunks: HashSet::new(),
+            changed_chunks: HashSet::new(),
+            removed_chunks: HashSet::new(),
         }
     }
 
@@ -152,12 +158,23 @@ impl State {
 
     /// Get a reference to this state's terrain.
     pub fn terrain(&self) -> Fetch<TerrainMap> {
-        self.ecs.internal().read_resource::<TerrainMap>()
+        self.ecs
+            .internal()
+            .read_resource::<TerrainMap>()
     }
 
-    // TODO: Get rid of this since it shouldn't be needed
-    pub fn terrain_mut(&mut self) -> FetchMut<TerrainMap> {
-        self.ecs.internal_mut().write_resource::<TerrainMap>()
+    /// Insert the provided chunk into this state's terrain.
+    pub fn insert_chunk(&mut self, key: Vec3<i32>, chunk: TerrainChunk) {
+        if self.ecs
+            .internal_mut()
+            .write_resource::<TerrainMap>()
+            .insert(key, chunk)
+            .is_some()
+        {
+            self.changes.changed_chunks.insert(key);
+        } else {
+            self.changes.new_chunks.insert(key);
+        }
     }
 
     /// Execute a single tick, simulating the game state by the given duration.
diff --git a/common/src/terrain/biome.rs b/common/src/terrain/biome.rs
index 81bd29967d..a177c44158 100644
--- a/common/src/terrain/biome.rs
+++ b/common/src/terrain/biome.rs
@@ -1,3 +1,6 @@
+use serde_derive::{Serialize, Deserialize};
+
+#[derive(Clone, Serialize, Deserialize)]
 pub enum BiomeKind {
     Void,
     Grassland,
diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs
index d24314f2e9..6098a5c5dd 100644
--- a/common/src/terrain/block.rs
+++ b/common/src/terrain/block.rs
@@ -1,10 +1,10 @@
-// Library
 use vek::*;
+use serde_derive::{Serialize, Deserialize};
 
 // Crate
 use crate::vol::Vox;
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
 pub struct Block {
     kind: u8,
     color: [u8; 3],
diff --git a/common/src/terrain/mod.rs b/common/src/terrain/mod.rs
index f860e14bcb..97008cde50 100644
--- a/common/src/terrain/mod.rs
+++ b/common/src/terrain/mod.rs
@@ -7,10 +7,8 @@ pub use self::{
     biome::BiomeKind,
 };
 
-// Library
 use vek::*;
-
-// Crate
+use serde_derive::{Serialize, Deserialize};
 use crate::{
     vol::VolSize,
     volumes::{
@@ -21,6 +19,7 @@ use crate::{
 
 // TerrainChunkSize
 
+#[derive(Clone, Serialize, Deserialize)]
 pub struct TerrainChunkSize;
 
 impl VolSize for TerrainChunkSize {
@@ -29,6 +28,7 @@ impl VolSize for TerrainChunkSize {
 
 // TerrainChunkMeta
 
+#[derive(Clone, Serialize, Deserialize)]
 pub struct TerrainChunkMeta {
     biome: BiomeKind,
 }
diff --git a/common/src/volumes/chunk.rs b/common/src/volumes/chunk.rs
index abdea07997..1c99301b63 100644
--- a/common/src/volumes/chunk.rs
+++ b/common/src/volumes/chunk.rs
@@ -3,6 +3,7 @@ use std::marker::PhantomData;
 
 // Library
 use vek::*;
+use serde_derive::{Serialize, Deserialize};
 
 // Local
 use crate::vol::{
@@ -23,6 +24,7 @@ pub enum ChunkErr {
 // V = Voxel
 // S = Size (replace when const generics are a thing)
 // M = Metadata
+#[derive(Clone, Serialize, Deserialize)]
 pub struct Chunk<V: Vox, S: VolSize, M> {
     vox: Vec<V>,
     meta: M,
diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs
index 954ac5cc16..2060b63989 100644
--- a/common/src/volumes/vol_map.rs
+++ b/common/src/volumes/vol_map.rs
@@ -129,4 +129,8 @@ impl<V: Vox, S: VolSize, M> VolMap<V, S, M> {
     pub fn remove(&mut self, key: &Vec3<i32>) -> Option<Chunk<V, S, M>> {
         self.chunks.remove(key)
     }
+
+    pub fn key_pos(&self, key: Vec3<i32>) -> Vec3<i32> {
+        key * S::SIZE.map(|e| e as i32)
+    }
 }
diff --git a/server/Cargo.toml b/server/Cargo.toml
index f7f9f31dcb..a5b590a902 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -10,3 +10,4 @@ world = { package = "veloren-world", path = "../world" }
 
 specs = "0.14"
 vek = "0.9"
+threadpool = "1.7"
diff --git a/server/src/client.rs b/server/src/client.rs
index fed88d9ae4..71d8aae6ab 100644
--- a/server/src/client.rs
+++ b/server/src/client.rs
@@ -1,3 +1,4 @@
+use std::collections::HashMap;
 use specs::Entity as EcsEntity;
 use common::{
     comp,
@@ -14,7 +15,6 @@ pub enum ClientState {
 
 pub struct Client {
     pub state: ClientState,
-    pub entity: EcsEntity,
     pub postbox: PostBox<ServerMsg, ClientMsg>,
     pub last_ping: f64,
 }
@@ -26,36 +26,42 @@ impl Client {
 }
 
 pub struct Clients {
-    clients: Vec<Client>,
+    clients: HashMap<EcsEntity, Client>,
 }
 
 impl Clients {
     pub fn empty() -> Self {
         Self {
-            clients: Vec::new(),
+            clients: HashMap::new(),
         }
     }
 
-    pub fn add(&mut self, client: Client) {
-        self.clients.push(client);
+    pub fn add(&mut self, entity: EcsEntity, client: Client) {
+        self.clients.insert(entity, client);
     }
 
-    pub fn remove_if<F: FnMut(&mut Client) -> bool>(&mut self, f: F) {
-        self.clients.drain_filter(f);
+    pub fn remove_if<F: FnMut(EcsEntity, &mut Client) -> bool>(&mut self, mut f: F) {
+        self.clients.retain(|entity, client| !f(*entity, client));
+    }
+
+    pub fn notify(&mut self, entity: EcsEntity, msg: ServerMsg) {
+        if let Some(client) = self.clients.get_mut(&entity) {
+            client.notify(msg);
+        }
     }
 
     pub fn notify_connected(&mut self, msg: ServerMsg) {
-        for client in &mut self.clients {
+        for client in self.clients.values_mut() {
             if client.state == ClientState::Connected {
-                client.postbox.send(msg.clone());
+                client.notify(msg.clone());
             }
         }
     }
 
-    pub fn notify_connected_except(&mut self, entity: EcsEntity, msg: ServerMsg) {
-        for client in &mut self.clients {
-            if client.entity != entity && client.state == ClientState::Connected {
-                client.postbox.send(msg.clone());
+    pub fn notify_connected_except(&mut self, except_entity: EcsEntity, msg: ServerMsg) {
+        for (entity, client) in self.clients.iter_mut() {
+            if client.state == ClientState::Connected && *entity != except_entity {
+                client.notify(msg.clone());
             }
         }
     }
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 35946c683e..0d3d4f872c 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -13,6 +13,7 @@ pub use crate::{
 use std::{
     time::Duration,
     net::SocketAddr,
+    sync::mpsc,
 };
 use specs::{
     Entity as EcsEntity,
@@ -22,11 +23,13 @@ use specs::{
     saveload::MarkedBuilder,
 };
 use vek::*;
+use threadpool::ThreadPool;
 use common::{
     comp,
     state::State,
     net::PostOffice,
     msg::{ServerMsg, ClientMsg},
+    terrain::TerrainChunk,
 };
 use world::World;
 use crate::client::{
@@ -56,18 +59,30 @@ pub struct Server {
 
     postoffice: PostOffice<ServerMsg, ClientMsg>,
     clients: Clients,
+
+    thread_pool: ThreadPool,
+    chunk_tx: mpsc::Sender<(Vec3<i32>, TerrainChunk)>,
+    chunk_rx: mpsc::Receiver<(Vec3<i32>, TerrainChunk)>,
 }
 
 impl Server {
     /// Create a new `Server`.
     #[allow(dead_code)]
     pub fn new() -> Result<Self, Error> {
+        let (chunk_tx, chunk_rx) = mpsc::channel();
+
         Ok(Self {
             state: State::new(),
             world: World::new(),
 
             postoffice: PostOffice::bind(SocketAddr::from(([0; 4], 59003)))?,
             clients: Clients::empty(),
+
+            thread_pool: threadpool::Builder::new()
+                .thread_name("veloren-worker".into())
+                .build(),
+            chunk_tx,
+            chunk_rx,
         })
     }
 
@@ -119,6 +134,27 @@ impl Server {
         // Tick the client's LocalState (step 3)
         self.state.tick(dt);
 
+        // Fetch any generated `TerrainChunk`s and insert them into the terrain
+        // Also, send the chunk data to anybody that is close by
+        for (key, chunk) in self.chunk_rx.try_iter() {
+            // Send the chunk to all nearby players
+            for (entity, player, pos) in (
+                &self.state.ecs().internal().entities(),
+                &self.state.ecs().internal().read_storage::<comp::Player>(),
+                &self.state.ecs().internal().read_storage::<comp::phys::Pos>(),
+            ).join() {
+                // TODO: Distance check
+                // if self.state.terrain().key_pos(key)
+
+                self.clients.notify(entity, ServerMsg::TerrainChunkUpdate {
+                    key,
+                    chunk: chunk.clone(),
+                });
+            }
+
+            self.state.insert_chunk(key, chunk);
+        }
+
         // Synchronise clients with the new state of the world
         self.sync_clients();
 
@@ -143,9 +179,8 @@ impl Server {
                 .create_entity_synced()
                 .build();
 
-            self.clients.add(Client {
+            self.clients.add(entity, Client {
                 state: ClientState::Connecting,
-                entity,
                 postbox,
                 last_ping: self.state.get_time(),
             });
@@ -166,7 +201,7 @@ impl Server {
         let mut new_chat_msgs = Vec::new();
         let mut disconnected_clients = Vec::new();
 
-        self.clients.remove_if(|client| {
+        self.clients.remove_if(|entity, client| {
             let mut disconnect = false;
             let new_msgs = client.postbox.new_messages();
 
@@ -181,12 +216,12 @@ impl Server {
                             ClientMsg::Connect { player, character } => {
 
                                 // Write client components
-                                state.write_component(client.entity, player);
-                                state.write_component(client.entity, comp::phys::Pos(Vec3::zero()));
-                                state.write_component(client.entity, comp::phys::Vel(Vec3::zero()));
-                                state.write_component(client.entity, comp::phys::Dir(Vec3::unit_y()));
+                                state.write_component(entity, player);
+                                state.write_component(entity, comp::phys::Pos(Vec3::zero()));
+                                state.write_component(entity, comp::phys::Vel(Vec3::zero()));
+                                state.write_component(entity, comp::phys::Dir(Vec3::unit_y()));
                                 if let Some(character) = character {
-                                    state.write_component(client.entity, character);
+                                    state.write_component(entity, character);
                                 }
 
                                 client.state = ClientState::Connected;
@@ -196,7 +231,7 @@ impl Server {
                                     ecs_state: state.ecs().gen_state_package(),
                                     player_entity: state
                                         .ecs()
-                                        .uid_from_entity(client.entity)
+                                        .uid_from_entity(entity)
                                         .unwrap()
                                         .into(),
                                 });
@@ -207,11 +242,11 @@ impl Server {
                             ClientMsg::Connect { .. } => disconnect = true, // Not allowed when already connected
                             ClientMsg::Ping => client.postbox.send(ServerMsg::Pong),
                             ClientMsg::Pong => {},
-                            ClientMsg::Chat(msg) => new_chat_msgs.push((client.entity, msg)),
+                            ClientMsg::Chat(msg) => new_chat_msgs.push((entity, msg)),
                             ClientMsg::PlayerPhysics { pos, vel, dir } => {
-                                state.write_component(client.entity, pos);
-                                state.write_component(client.entity, vel);
-                                state.write_component(client.entity, dir);
+                                state.write_component(entity, pos);
+                                state.write_component(entity, vel);
+                                state.write_component(entity, dir);
                             },
                             ClientMsg::Disconnect => disconnect = true,
                         },
@@ -228,7 +263,7 @@ impl Server {
             }
 
             if disconnect {
-                disconnected_clients.push(client.entity);
+                disconnected_clients.push(entity);
                 true
             } else {
                 false
diff --git a/voxygen/src/menu/main/mod.rs b/voxygen/src/menu/main/mod.rs
index 4b95bb6d46..88c08cb0b8 100644
--- a/voxygen/src/menu/main/mod.rs
+++ b/voxygen/src/menu/main/mod.rs
@@ -58,7 +58,7 @@ impl PlayState for MainMenuState {
 
             global_state.window.renderer_mut().clear(BG_COLOR);
 
-            // Maintain the UI
+            // Maintain the UI (TODO: Maybe clean this up a little to avoid rightward drift?)
             for event in self.main_menu_ui.maintain(global_state.window.renderer_mut()) {
                 match event {
                     MainMenuEvent::LoginAttempt{ username, server_address } => {
@@ -70,7 +70,7 @@ impl PlayState for MainMenuState {
                             Ok(mut socket_adders) => {
                                 while let Some(socket_addr) = socket_adders.next() {
                                     // TODO: handle error
-                                    match Client::new(socket_addr, comp::Player::new(username.clone()), Some(comp::Character::test())) {
+                                    match Client::new(socket_addr, comp::Player::new(username.clone()), Some(comp::Character::test()), 300) {
                                         Ok(client) => {
                                             return PlayStateResult::Push(
                                                 Box::new(CharSelectionState::new(

From d4af18e3d4b8e4d9898c2d3c882a410b0cf667c9 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Thu, 11 Apr 2019 00:41:37 +0100
Subject: [PATCH 04/16] Added server-side chunk generation

Former-commit-id: 72e02f8ec711ec4fac3111b591c4b08086dee4e3
---
 common/src/msg/client.rs      |  4 ++++
 common/src/volumes/vol_map.rs |  8 ++++++--
 server/src/lib.rs             | 25 ++++++++++++++++++++++++-
 world/src/lib.rs              |  2 +-
 4 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs
index e2339aada3..5a599633d7 100644
--- a/common/src/msg/client.rs
+++ b/common/src/msg/client.rs
@@ -1,3 +1,4 @@
+use vek::*;
 use crate::comp;
 
 #[derive(Clone, Serialize, Deserialize)]
@@ -14,5 +15,8 @@ pub enum ClientMsg {
         vel: comp::phys::Vel,
         dir: comp::phys::Dir,
     },
+    TerrainChunkRequest {
+        key: Vec3<i32>,
+    },
     Disconnect,
 }
diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs
index 2060b63989..ab2947a416 100644
--- a/common/src/volumes/vol_map.rs
+++ b/common/src/volumes/vol_map.rs
@@ -126,8 +126,12 @@ impl<V: Vox, S: VolSize, M> VolMap<V, S, M> {
         self.chunks.insert(key, chunk)
     }
 
-    pub fn remove(&mut self, key: &Vec3<i32>) -> Option<Chunk<V, S, M>> {
-        self.chunks.remove(key)
+    pub fn get_key(&self, key: Vec3<i32>) -> Option<&Chunk<V, S, M>> {
+        self.chunks.get(&key)
+    }
+
+    pub fn remove(&mut self, key: Vec3<i32>) -> Option<Chunk<V, S, M>> {
+        self.chunks.remove(&key)
     }
 
     pub fn key_pos(&self, key: Vec3<i32>) -> Vec3<i32> {
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 0d3d4f872c..9313505a71 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -14,6 +14,7 @@ use std::{
     time::Duration,
     net::SocketAddr,
     sync::mpsc,
+    collections::HashSet,
 };
 use specs::{
     Entity as EcsEntity,
@@ -63,6 +64,7 @@ pub struct Server {
     thread_pool: ThreadPool,
     chunk_tx: mpsc::Sender<(Vec3<i32>, TerrainChunk)>,
     chunk_rx: mpsc::Receiver<(Vec3<i32>, TerrainChunk)>,
+    pending_chunks: HashSet<Vec3<i32>>,
 }
 
 impl Server {
@@ -83,6 +85,7 @@ impl Server {
                 .build(),
             chunk_tx,
             chunk_rx,
+            pending_chunks: HashSet::new(),
         })
     }
 
@@ -200,6 +203,7 @@ impl Server {
         let state = &mut self.state;
         let mut new_chat_msgs = Vec::new();
         let mut disconnected_clients = Vec::new();
+        let mut requested_chunks = Vec::new();
 
         self.clients.remove_if(|entity, client| {
             let mut disconnect = false;
@@ -240,6 +244,7 @@ impl Server {
                         },
                         ClientState::Connected => match msg {
                             ClientMsg::Connect { .. } => disconnect = true, // Not allowed when already connected
+                            ClientMsg::Disconnect => disconnect = true,
                             ClientMsg::Ping => client.postbox.send(ServerMsg::Pong),
                             ClientMsg::Pong => {},
                             ClientMsg::Chat(msg) => new_chat_msgs.push((entity, msg)),
@@ -248,7 +253,13 @@ impl Server {
                                 state.write_component(entity, vel);
                                 state.write_component(entity, dir);
                             },
-                            ClientMsg::Disconnect => disconnect = true,
+                            ClientMsg::TerrainChunkRequest { key } => match state.terrain().get_key(key) {
+                                Some(chunk) => client.postbox.send(ServerMsg::TerrainChunkUpdate {
+                                    key,
+                                    chunk: chunk.clone(),
+                                }),
+                                None => requested_chunks.push(key),
+                            },
                         },
                     }
                 }
@@ -297,6 +308,11 @@ impl Server {
             });
         }
 
+        // Generate requested chunks
+        for key in requested_chunks {
+            self.generate_chunk(key);
+        }
+
         Ok(frontend_events)
     }
 
@@ -304,6 +320,13 @@ impl Server {
     fn sync_clients(&mut self) {
         self.clients.notify_connected(ServerMsg::EcsSync(self.state.ecs_mut().next_sync_package()));
     }
+
+    pub fn generate_chunk(&mut self, key: Vec3<i32>) {
+        if self.pending_chunks.insert(key) {
+            let chunk_tx = self.chunk_tx.clone();
+            self.thread_pool.execute(move || chunk_tx.send((key, World::generate_chunk(key))).unwrap());
+        }
+    }
 }
 
 impl Drop for Server {
diff --git a/world/src/lib.rs b/world/src/lib.rs
index b296ff2e6b..5c9d57b42c 100644
--- a/world/src/lib.rs
+++ b/world/src/lib.rs
@@ -24,7 +24,7 @@ impl World {
         Self
     }
 
-    pub fn generate_chunk(&self, chunk_pos: Vec3<i32>) -> TerrainChunk {
+    pub fn generate_chunk(chunk_pos: Vec3<i32>) -> TerrainChunk {
         // TODO: This is all test code, remove/improve this later
 
         let mut chunk = TerrainChunk::filled(Block::empty(), TerrainChunkMeta::void());

From f4ce38e58a10bb3d6a16f0b7292f7d1e666698a6 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Thu, 11 Apr 2019 23:26:43 +0100
Subject: [PATCH 05/16] Rewrote netcode, added basic chunk synching

Former-commit-id: e9f76f7fa9dbe0c81cd4c998bf0f0b3eec9235cb
---
 chat-cli/src/main.rs          |   2 +-
 client/src/error.rs           |   5 +-
 client/src/lib.rs             |  43 +++-
 common/Cargo.toml             |   1 -
 common/src/lib.rs             |   2 +-
 common/src/msg/client.rs      |   2 +
 common/src/msg/server.rs      |   4 +-
 common/src/net/mod.rs         |   5 +-
 common/src/net/post.rs        | 244 +++++++++++++--------
 common/src/net/post2.rs       | 402 ++++++++++++++++++++++++++++++++++
 common/src/volumes/vol_map.rs |   4 +
 server/src/client.rs          |   2 +-
 server/src/lib.rs             |  12 +-
 13 files changed, 608 insertions(+), 120 deletions(-)
 create mode 100644 common/src/net/post2.rs

diff --git a/chat-cli/src/main.rs b/chat-cli/src/main.rs
index deb5cb126c..2bbc51a388 100644
--- a/chat-cli/src/main.rs
+++ b/chat-cli/src/main.rs
@@ -18,7 +18,7 @@ fn main() {
     let mut clock = Clock::new();
 
     // Create client
-    let mut client = Client::new(([127, 0, 0, 1], 59003), comp::Player::new("test".to_string()), None)
+    let mut client = Client::new(([127, 0, 0, 1], 59003), comp::Player::new("test".to_string()), None, 300)
         .expect("Failed to create client instance");
 
     client.send_chat("Hello!".to_string());
diff --git a/client/src/error.rs b/client/src/error.rs
index b4b3ce4742..1f74ae62b9 100644
--- a/client/src/error.rs
+++ b/client/src/error.rs
@@ -11,9 +11,6 @@ pub enum Error {
 
 impl From<PostError> for Error {
     fn from(err: PostError) -> Self {
-        match err {
-            PostError::Disconnect => Error::ServerShutdown,
-            err => Error::Network(err),
-        }
+        Error::Network(err)
     }
 }
diff --git a/client/src/lib.rs b/client/src/lib.rs
index c20cca643c..1d5bdc1a00 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -13,6 +13,7 @@ pub use crate::{
 use std::{
     time::Duration,
     net::SocketAddr,
+    collections::HashSet,
 };
 use vek::*;
 use threadpool::ThreadPool;
@@ -41,6 +42,8 @@ pub struct Client {
     state: State,
     player: Option<EcsEntity>,
     view_distance: u64,
+
+    pending_chunks: HashSet<Vec3<i32>>,
 }
 
 impl Client {
@@ -53,10 +56,10 @@ impl Client {
         view_distance: u64,
     ) -> Result<Self, Error> {
 
-        let mut postbox = PostBox::to_server(addr)?;
+        let mut postbox = PostBox::to(addr)?;
 
         // Send connection request
-        postbox.send(ClientMsg::Connect {
+        postbox.send_message(ClientMsg::Connect {
             player,
             character,
         });
@@ -83,6 +86,8 @@ impl Client {
             state,
             player,
             view_distance,
+
+            pending_chunks: HashSet::new(),
         })
     }
 
@@ -115,7 +120,7 @@ impl Client {
     /// Send a chat message to the server
     #[allow(dead_code)]
     pub fn send_chat(&mut self, msg: String) {
-        self.postbox.send(ClientMsg::Chat(msg))
+        self.postbox.send_message(ClientMsg::Chat(msg))
     }
 
     /// Execute a single client tick, handle input and update the game state by the given duration
@@ -161,12 +166,31 @@ impl Client {
                 self.state.read_storage().get(ecs_entity).cloned(),
             ) {
                 (Some(pos), Some(vel), Some(dir)) => {
-                    self.postbox.send(ClientMsg::PlayerPhysics { pos, vel, dir });
+                    self.postbox.send_message(ClientMsg::PlayerPhysics { pos, vel, dir });
                 },
                 _ => {},
             }
         }
 
+        // Request chunks from the server
+        if let Some(player_entity) = self.player {
+            if let Some(pos) = self.state.read_storage::<comp::phys::Pos>().get(player_entity) {
+                let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
+
+                for i in chunk_pos.x - 0..chunk_pos.x + 1 {
+                    for j in chunk_pos.y - 0..chunk_pos.y + 1 {
+                        for k in 0..3 {
+                            let key = chunk_pos + Vec3::new(i, j, k);
+                            if self.state.terrain().get_key(key).is_none() && !self.pending_chunks.contains(&key) {
+                                self.postbox.send_message(ClientMsg::TerrainChunkRequest { key });
+                                self.pending_chunks.insert(key);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
         // Finish the tick, pass control back to the frontend (step 6)
         self.tick += 1;
         Ok(frontend_events)
@@ -193,12 +217,15 @@ impl Client {
                 match msg {
                     ServerMsg::Handshake { .. } => return Err(Error::ServerWentMad),
                     ServerMsg::Shutdown => return Err(Error::ServerShutdown),
-                    ServerMsg::Ping => self.postbox.send(ClientMsg::Pong),
+                    ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
                     ServerMsg::Pong => {},
                     ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
                     ServerMsg::SetPlayerEntity(uid) => self.player = Some(self.state.ecs().entity_from_uid(uid).unwrap()), // TODO: Don't unwrap here!
                     ServerMsg::EcsSync(sync_package) => self.state.ecs_mut().sync_with_package(sync_package),
-                    ServerMsg::TerrainChunkUpdate { key, chunk } => self.state.insert_chunk(key, chunk),
+                    ServerMsg::TerrainChunkUpdate { key, chunk } => {
+                        self.state.insert_chunk(key, *chunk);
+                        self.pending_chunks.remove(&key);
+                    },
                 }
             }
         } else if let Some(err) = self.postbox.error() {
@@ -207,7 +234,7 @@ impl Client {
             return Err(Error::ServerTimeout);
         } else if self.state.get_time() - self.last_ping > SERVER_TIMEOUT * 0.5 {
             // Try pinging the server if the timeout is nearing
-            self.postbox.send(ClientMsg::Ping);
+            self.postbox.send_message(ClientMsg::Ping);
         }
 
         Ok(frontend_events)
@@ -216,6 +243,6 @@ impl Client {
 
 impl Drop for Client {
     fn drop(&mut self) {
-        self.postbox.send(ClientMsg::Disconnect);
+        self.postbox.send_message(ClientMsg::Disconnect);
     }
 }
diff --git a/common/Cargo.toml b/common/Cargo.toml
index 75c032bf18..8c82e841a3 100644
--- a/common/Cargo.toml
+++ b/common/Cargo.toml
@@ -18,4 +18,3 @@ serde = "1.0"
 serde_derive = "1.0"
 bincode = "1.0"
 log = "0.4"
-pretty_env_logger = "0.3"
diff --git a/common/src/lib.rs b/common/src/lib.rs
index 72bcade3f8..146e272351 100644
--- a/common/src/lib.rs
+++ b/common/src/lib.rs
@@ -1,4 +1,4 @@
-#![feature(euclidean_division, duration_float, trait_alias)]
+#![feature(euclidean_division, duration_float, trait_alias, bind_by_move_pattern_guards)]
 
 #[macro_use]
 extern crate serde_derive;
diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs
index 5a599633d7..ffc941b1b6 100644
--- a/common/src/msg/client.rs
+++ b/common/src/msg/client.rs
@@ -20,3 +20,5 @@ pub enum ClientMsg {
     },
     Disconnect,
 }
+
+impl middleman::Message for ClientMsg {}
diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs
index db0ae2ed81..bdd86945ca 100644
--- a/common/src/msg/server.rs
+++ b/common/src/msg/server.rs
@@ -16,6 +16,8 @@ pub enum ServerMsg {
     EcsSync(sphynx::SyncPackage<EcsPacket>),
     TerrainChunkUpdate {
         key: Vec3<i32>,
-        chunk: TerrainChunk,
+        chunk: Box<TerrainChunk>,
     },
 }
+
+impl middleman::Message for ServerMsg {}
diff --git a/common/src/net/mod.rs b/common/src/net/mod.rs
index c1c7fd4107..11829e32fa 100644
--- a/common/src/net/mod.rs
+++ b/common/src/net/mod.rs
@@ -1,5 +1,8 @@
 pub mod data;
-pub mod post;
+//pub mod post;
+pub mod post2;
+
+pub use post2 as post;
 
 // Reexports
 pub use self::{
diff --git a/common/src/net/post.rs b/common/src/net/post.rs
index 6338424912..38a8533186 100644
--- a/common/src/net/post.rs
+++ b/common/src/net/post.rs
@@ -23,6 +23,7 @@ use mio_extras::channel::{
     Sender,
 };
 use bincode;
+use middleman::Middleman;
 
 #[derive(Clone, Debug, PartialEq)]
 pub enum Error {
@@ -56,14 +57,15 @@ impl<T> From<mio_extras::channel::SendError<T>> for Error {
     }
 }
 
-pub trait PostSend = 'static + serde::Serialize + Send;
-pub trait PostRecv = 'static + serde::de::DeserializeOwned + Send;
+pub trait PostSend = 'static + serde::Serialize + Send + middleman::Message;
+pub trait PostRecv = 'static + serde::de::DeserializeOwned + Send + middleman::Message;
 
-const TCP_TOK:     Token = Token(0);
-const CTRL_TOK:    Token = Token(1);
-const POSTBOX_TOK: Token = Token(2);
-const SEND_TOK:    Token = Token(3);
-const RECV_TOK:    Token = Token(4);
+const TCP_TOK:       Token = Token(0);
+const CTRL_TOK:      Token = Token(1);
+const POSTBOX_TOK:   Token = Token(2);
+const SEND_TOK:      Token = Token(3);
+const RECV_TOK:      Token = Token(4);
+const MIDDLEMAN_TOK: Token = Token(5);
 
 const MAX_MSG_BYTES: usize = 1 << 20;
 
@@ -218,7 +220,7 @@ impl<S: PostSend, R: PostRecv> PostBox<S, R> {
         let (recv_tx, recv_rx) = channel();
 
         let worker_poll = Poll::new()?;
-        worker_poll.register(&tcp_stream, TCP_TOK, Ready::readable(), PollOpt::edge())?;
+        worker_poll.register(&tcp_stream, TCP_TOK, Ready::readable() | Ready::writable(), PollOpt::edge())?;
         worker_poll.register(&ctrl_rx, CTRL_TOK, Ready::readable(), PollOpt::edge())?;
         worker_poll.register(&send_rx, SEND_TOK, Ready::readable(), PollOpt::edge())?;
 
@@ -345,12 +347,38 @@ fn postbox_worker<S: PostSend, R: PostRecv>(
     send_rx: Receiver<S>,
     recv_tx: Sender<Result<R, Error>>,
 ) -> Result<(), Error> {
+    fn try_tcp_send(tcp_stream: &mut TcpStream, chunks: &mut VecDeque<Vec<u8>>) -> Result<(), Error> {
+        loop {
+            let chunk = match chunks.pop_front() {
+                Some(chunk) => chunk,
+                None => break,
+            };
+
+            match tcp_stream.write_all(&chunk) {
+                Ok(()) => {},
+                Err(err) if err.kind() == io::ErrorKind::WouldBlock => {
+                    chunks.push_front(chunk);
+                    break;
+                },
+                Err(err) => {
+                    println!("Error: {:?}", err);
+                    return Err(err.into());
+                },
+            }
+        }
+
+        Ok(())
+    }
+
     enum RecvState {
         ReadHead(Vec<u8>),
         ReadBody(usize, Vec<u8>),
     }
 
-    let mut recv_state = RecvState::ReadHead(Vec::with_capacity(8));
+    let mut recv_state = RecvState::ReadHead(Vec::new());
+    let mut chunks = VecDeque::new();
+
+    //let mut recv_state = RecvState::ReadHead(Vec::with_capacity(8));
     let mut events = Events::with_capacity(64);
 
     'work: loop {
@@ -383,18 +411,23 @@ fn postbox_worker<S: PostSend, R: PostRecv>(
                                 },
                             };
 
-                            let mut packet = msg_bytes
+                            let mut bytes = msg_bytes
                                 .len()
                                 .to_le_bytes()
                                 .as_ref()
                                 .to_vec();
-                            packet.append(&mut msg_bytes);
+                            bytes.append(&mut msg_bytes);
 
-                            match tcp_stream.write_all(&packet) {
-                                Ok(()) => {},
+                            bytes
+                                .chunks(1024)
+                                .map(|chunk| chunk.to_vec())
+                                .for_each(|chunk| chunks.push_back(chunk));
+
+                            match try_tcp_send(&mut tcp_stream, &mut chunks) {
+                                Ok(_) => {},
                                 Err(err) => {
                                     recv_tx.send(Err(err.into()))?;
-                                    break 'work;
+                                    return Err(Error::Network);
                                 },
                             }
                         },
@@ -402,61 +435,75 @@ fn postbox_worker<S: PostSend, R: PostRecv>(
                         Err(err) => Err(err)?,
                     }
                 },
-                TCP_TOK => loop {
-                    match tcp_stream.take_error() {
-                        Ok(None) => {},
-                        Ok(Some(err)) => {
-                            recv_tx.send(Err(err.into()))?;
-                            break 'work;
-                        },
+                TCP_TOK => {
+                    loop {
+                        // Check TCP error
+                        match tcp_stream.take_error() {
+                            Ok(None) => {},
+                            Ok(Some(err)) => {
+                                recv_tx.send(Err(err.into()))?;
+                                break 'work;
+                            },
+                            Err(err) => {
+                                recv_tx.send(Err(err.into()))?;
+                                break 'work;
+                            },
+                        }
+                        match &mut recv_state {
+                            RecvState::ReadHead(head) => if head.len() == 8 {
+                                let len = usize::from_le_bytes(<[u8; 8]>::try_from(head.as_slice()).unwrap());
+                                if len > MAX_MSG_BYTES {
+                                    println!("TOO BIG! {:x}", len);
+                                    recv_tx.send(Err(Error::InvalidMsg))?;
+                                    break 'work;
+                                } else if len == 0 {
+                                    recv_state = RecvState::ReadHead(Vec::with_capacity(8));
+                                    break;
+                                } else {
+                                    recv_state = RecvState::ReadBody(
+                                        len,
+                                        Vec::new(),
+                                    );
+                                }
+                            } else {
+                                let mut b = [0; 1];
+                                match tcp_stream.read(&mut b) {
+                                    Ok(0) => {},
+                                    Ok(_) => head.push(b[0]),
+                                    Err(_) => break,
+                                }
+                            },
+                            RecvState::ReadBody(len, body) => if body.len() == *len {
+                                match bincode::deserialize(&body) {
+                                    Ok(msg) => {
+                                        recv_tx.send(Ok(msg))?;
+                                        recv_state = RecvState::ReadHead(Vec::with_capacity(8));
+                                    },
+                                    Err(err) => {
+                                        recv_tx.send(Err((*err).into()))?;
+                                        break 'work;
+                                    },
+                                }
+                            } else {
+                                let left = *len - body.len();
+                                let mut buf = vec![0; left];
+                                match tcp_stream.read(&mut buf) {
+                                    Ok(_) => body.append(&mut buf),
+                                    Err(err) => {
+                                        recv_tx.send(Err(err.into()))?;
+                                        break 'work;
+                                    },
+                                }
+                            },
+                        }
+                    }
+
+                    // Now, try sending TCP stuff
+                    match try_tcp_send(&mut tcp_stream, &mut chunks) {
+                        Ok(_) => {},
                         Err(err) => {
                             recv_tx.send(Err(err.into()))?;
-                            break 'work;
-                        },
-                    }
-                    match &mut recv_state {
-                        RecvState::ReadHead(head) => if head.len() == 8 {
-                            let len = usize::from_le_bytes(<[u8; 8]>::try_from(head.as_slice()).unwrap());
-                            if len > MAX_MSG_BYTES {
-                                recv_tx.send(Err(Error::InvalidMsg))?;
-                                break 'work;
-                            } else if len == 0 {
-                                recv_state = RecvState::ReadHead(Vec::with_capacity(8));
-                                break;
-                            } else {
-                                recv_state = RecvState::ReadBody(
-                                    len,
-                                    Vec::new(),
-                                );
-                            }
-                        } else {
-                            let mut b = [0; 1];
-                            match tcp_stream.read(&mut b) {
-                                Ok(_) => head.push(b[0]),
-                                Err(_) => break,
-                            }
-                        },
-                        RecvState::ReadBody(len, body) => if body.len() == *len {
-                            match bincode::deserialize(&body) {
-                                Ok(msg) => {
-                                    recv_tx.send(Ok(msg))?;
-                                    recv_state = RecvState::ReadHead(Vec::with_capacity(8));
-                                },
-                                Err(err) => {
-                                    recv_tx.send(Err((*err).into()))?;
-                                    break 'work;
-                                },
-                            }
-                        } else {
-                            let left = *len - body.len();
-                            let mut buf = vec![0; left];
-                            match tcp_stream.read(&mut buf) {
-                                Ok(_) => body.append(&mut buf),
-                                Err(err) => {
-                                    recv_tx.send(Err(err.into()))?;
-                                    break 'work;
-                                },
-                            }
+                            return Err(Error::Network);
                         },
                     }
                 },
@@ -465,24 +512,28 @@ fn postbox_worker<S: PostSend, R: PostRecv>(
         }
     }
 
-    tcp_stream.shutdown(Shutdown::Both)?;
+    //tcp_stream.shutdown(Shutdown::Both)?;
     Ok(())
 }
 
 // TESTS
 
+/*
+#[derive(Serialize, Deserialize)]
+struct TestMsg<T>(T);
+
 #[test]
 fn connect() {
     let srv_addr = ([127, 0, 0, 1], 12345);
 
-    let mut postoffice = PostOffice::<u32, f32>::bind(srv_addr).unwrap();
+    let mut postoffice = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(srv_addr).unwrap();
 
     // We should start off with 0 incoming connections
     thread::sleep(Duration::from_millis(250));
     assert_eq!(postoffice.new_connections().len(), 0);
     assert_eq!(postoffice.error(), None);
 
-    let postbox = PostBox::<f32, u32>::to_server(srv_addr).unwrap();
+    let postbox = PostBox::<TestMsg<f32>, TestMsg<u32>>::to_server(srv_addr).unwrap();
 
     // Now a postbox has been created, we should have 1 new
     thread::sleep(Duration::from_millis(250));
@@ -496,21 +547,21 @@ fn connect_fail() {
     let listen_addr = ([0; 4], 12345);
     let connect_addr = ([127, 0, 0, 1], 12212);
 
-    let mut postoffice = PostOffice::<u32, f32>::bind(listen_addr).unwrap();
+    let mut postoffice = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(listen_addr).unwrap();
 
     // We should start off with 0 incoming connections
     thread::sleep(Duration::from_millis(250));
     assert_eq!(postoffice.new_connections().len(), 0);
     assert_eq!(postoffice.error(), None);
 
-    assert!(PostBox::<f32, u32>::to_server(connect_addr).is_err());
+    assert!(PostBox::<TestMsg<f32>, TestMsg<u32>>::to_server(connect_addr).is_err());
 }
 
 #[test]
 fn connection_count() {
     let srv_addr = ([127, 0, 0, 1], 12346);
 
-    let mut postoffice = PostOffice::<u32, f32>::bind(srv_addr).unwrap();
+    let mut postoffice = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(srv_addr).unwrap();
     let mut postboxes = Vec::new();
 
     // We should start off with 0 incoming connections
@@ -519,7 +570,7 @@ fn connection_count() {
     assert_eq!(postoffice.error(), None);
 
     for _ in 0..5 {
-        postboxes.push(PostBox::<f32, u32>::to_server(srv_addr).unwrap());
+        postboxes.push(PostBox::<TestMsg<f32>, TestMsg<u32>>::to_server(srv_addr).unwrap());
     }
 
     // 5 postboxes created, we should have 5
@@ -533,10 +584,10 @@ fn connection_count() {
 fn disconnect() {
     let srv_addr = ([127, 0, 0, 1], 12347);
 
-    let mut postoffice = PostOffice::<u32, f32>::bind(srv_addr).unwrap();
+    let mut postoffice = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(srv_addr).unwrap();
 
     let mut server_postbox = {
-        let mut client_postbox = PostBox::<f32, u32>::to_server(srv_addr).unwrap();
+        let mut client_postbox = PostBox::<TestMsg<f32>, TestMsg<u32>>::to_server(srv_addr).unwrap();
 
         thread::sleep(Duration::from_millis(250));
         let mut incoming = postoffice.new_connections();
@@ -558,52 +609,53 @@ fn disconnect() {
 fn client_to_server() {
     let srv_addr = ([127, 0, 0, 1], 12348);
 
-    let mut po = PostOffice::<u32, f32>::bind(srv_addr).unwrap();
+    let mut po = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(srv_addr).unwrap();
 
-    let mut client_pb = PostBox::<f32, u32>::to_server(srv_addr).unwrap();
+    let mut client_pb = PostBox::<TestMsg<f32>, TestMsg<u32>>::to_server(srv_addr).unwrap();
 
     thread::sleep(Duration::from_millis(250));
 
     let mut server_pb = po.new_connections().next().unwrap();
 
-    client_pb.send(1337.0);
-    client_pb.send(9821.0);
-    client_pb.send(-3.2);
-    client_pb.send(17.0);
+    client_pb.send(TestMsg(1337.0));
+    client_pb.send(TestMsg(9821.0));
+    client_pb.send(TestMsg(-3.2));
+    client_pb.send(TestMsg(17.0));
 
     thread::sleep(Duration::from_millis(250));
 
     let mut incoming_msgs = server_pb.new_messages();
     assert_eq!(incoming_msgs.len(), 4);
-    assert_eq!(incoming_msgs.next().unwrap(), 1337.0);
-    assert_eq!(incoming_msgs.next().unwrap(), 9821.0);
-    assert_eq!(incoming_msgs.next().unwrap(), -3.2);
-    assert_eq!(incoming_msgs.next().unwrap(), 17.0);
+    assert_eq!(incoming_msgs.next().unwrap(), TestMsg(1337.0));
+    assert_eq!(incoming_msgs.next().unwrap(), TestMsg(9821.0));
+    assert_eq!(incoming_msgs.next().unwrap(), TestMsg(-3.2));
+    assert_eq!(incoming_msgs.next().unwrap(), TestMsg(17.0));
 }
 
 #[test]
 fn server_to_client() {
     let srv_addr = ([127, 0, 0, 1], 12349);
 
-    let mut po = PostOffice::<u32, f32>::bind(srv_addr).unwrap();
+    let mut po = PostOffice::<TestMsg<u32>, TestMsg<f32>>::bind(srv_addr).unwrap();
 
-    let mut client_pb = PostBox::<f32, u32>::to_server(srv_addr).unwrap();
+    let mut client_pb = PostBox::<TestMsg<f32>, TestMsg<u32>>::to_server(srv_addr).unwrap();
 
     thread::sleep(Duration::from_millis(250));
 
     let mut server_pb = po.new_connections().next().unwrap();
 
-    server_pb.send(1337);
-    server_pb.send(9821);
-    server_pb.send(39999999);
-    server_pb.send(17);
+    server_pb.send(TestMsg(1337));
+    server_pb.send(TestMsg(9821));
+    server_pb.send(TestMsg(39999999));
+    server_pb.send(TestMsg(17));
 
     thread::sleep(Duration::from_millis(250));
 
     let mut incoming_msgs = client_pb.new_messages();
     assert_eq!(incoming_msgs.len(), 4);
-    assert_eq!(incoming_msgs.next().unwrap(), 1337);
-    assert_eq!(incoming_msgs.next().unwrap(), 9821);
-    assert_eq!(incoming_msgs.next().unwrap(), 39999999);
-    assert_eq!(incoming_msgs.next().unwrap(), 17);
+    assert_eq!(incoming_msgs.next().unwrap(), TestMsg(1337));
+    assert_eq!(incoming_msgs.next().unwrap(), TestMsg(9821));
+    assert_eq!(incoming_msgs.next().unwrap(), TestMsg(39999999));
+    assert_eq!(incoming_msgs.next().unwrap(), TestMsg(17));
 }
+*/
diff --git a/common/src/net/post2.rs b/common/src/net/post2.rs
new file mode 100644
index 0000000000..16a9bb985a
--- /dev/null
+++ b/common/src/net/post2.rs
@@ -0,0 +1,402 @@
+use std::{
+    io::{self, Read, Write},
+    net::{TcpListener, TcpStream, SocketAddr, Shutdown},
+    time::{Instant, Duration},
+    marker::PhantomData,
+    sync::mpsc,
+    thread,
+    collections::VecDeque,
+    convert::TryFrom,
+};
+use serde::{Serialize, de::DeserializeOwned};
+
+#[derive(Clone, Debug)]
+pub enum Error {
+    Io, //Io(io::Error),
+    Bincode, //Bincode(bincode::Error),
+    ChannelFailure,
+    InvalidMessage,
+}
+
+impl From<io::Error> for Error {
+    fn from(err: io::Error) -> Self {
+        Error::Io //(err)
+    }
+}
+
+impl From<bincode::Error> for Error {
+    fn from(err: bincode::Error) -> Self {
+        Error::Bincode //(err)
+    }
+}
+
+impl From<mpsc::TryRecvError> for Error {
+    fn from(error: mpsc::TryRecvError) -> Self {
+        Error::ChannelFailure
+    }
+}
+
+pub trait PostMsg = Serialize + DeserializeOwned + 'static + Send;
+
+const MAX_MSG_SIZE: usize = 1 << 20;
+
+pub struct PostOffice<S: PostMsg, R: PostMsg> {
+    listener: TcpListener,
+    error: Option<Error>,
+    phantom: PhantomData<(S, R)>,
+}
+
+impl<S: PostMsg, R: PostMsg> PostOffice<S, R> {
+    pub fn bind<A: Into<SocketAddr>>(addr: A) -> Result<Self, Error> {
+        let mut listener = TcpListener::bind(addr.into())?;
+        listener.set_nonblocking(true)?;
+
+        Ok(Self {
+            listener,
+            error: None,
+            phantom: PhantomData,
+        })
+    }
+
+    pub fn error(&self) -> Option<Error> {
+        self.error.clone()
+    }
+
+    pub fn new_postboxes(&mut self) -> impl ExactSizeIterator<Item=PostBox<S, R>> {
+        let mut new = Vec::new();
+
+        if self.error.is_some() {
+            return new.into_iter();
+        }
+
+        loop {
+            match self.listener.accept() {
+                Ok((stream, sock)) => new.push(PostBox::from_stream(stream).unwrap()),
+                Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
+                Err(e) => {
+                    self.error = Some(e.into());
+                    break;
+                },
+            }
+        }
+
+        new.into_iter()
+    }
+}
+
+pub struct PostBox<S: PostMsg, R: PostMsg> {
+    send_tx: mpsc::Sender<Option<S>>,
+    recv_rx: mpsc::Receiver<Result<R, Error>>,
+    worker: Option<thread::JoinHandle<()>>,
+    error: Option<Error>,
+}
+
+impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
+    pub fn to<A: Into<SocketAddr>>(addr: A) -> Result<Self, Error> {
+        Self::from_stream(TcpStream::connect(addr.into())?)
+    }
+
+    fn from_stream(stream: TcpStream) -> Result<Self, Error> {
+        stream.set_nonblocking(true)?;
+
+        let (send_tx, send_rx) = mpsc::channel();
+        let (recv_tx, recv_rx) = mpsc::channel();
+
+        let worker = thread::spawn(move || Self::worker(stream, send_rx, recv_tx));
+
+        Ok(Self {
+            send_tx,
+            recv_rx,
+            worker: Some(worker),
+            error: None,
+        })
+    }
+
+    pub fn error(&self) -> Option<Error> {
+        self.error.clone()
+    }
+
+    pub fn send_message(&mut self, msg: S) {
+        let _ = self.send_tx.send(Some(msg));
+    }
+
+    pub fn next_message(&mut self) -> Option<R> {
+        if self.error.is_some() {
+            return None;
+        }
+
+        match self.recv_rx.recv().ok()? {
+            Ok(msg) => Some(msg),
+            Err(e) => {
+                self.error = Some(e);
+                None
+            },
+        }
+    }
+
+    pub fn new_messages(&mut self) -> impl ExactSizeIterator<Item=R> {
+        let mut new = Vec::new();
+
+        if self.error.is_some() {
+            return new.into_iter();
+        }
+
+        loop {
+            match self.recv_rx.try_recv() {
+                Ok(Ok(msg)) => new.push(msg),
+                Err(mpsc::TryRecvError::Empty) => break,
+                Err(e) => {
+                    self.error = Some(e.into());
+                    break;
+                },
+                Ok(Err(e)) => {
+                    self.error = Some(e);
+                    break;
+                },
+            }
+        }
+
+        new.into_iter()
+    }
+
+    fn worker(mut stream: TcpStream, send_rx: mpsc::Receiver<Option<S>>, recv_tx: mpsc::Sender<Result<R, Error>>) {
+        let mut outgoing_chunks = VecDeque::new();
+        let mut incoming_buf = Vec::new();
+
+        'work: loop {
+            // Get stream errors
+            match stream.take_error() {
+                Ok(Some(e)) | Err(e) => {
+                    recv_tx.send(Err(e.into())).unwrap();
+                    break 'work;
+                },
+                Ok(None) => {},
+            }
+
+            // Try getting messages from the send channel
+            loop {
+                match send_rx.try_recv() {
+                    Ok(Some(send_msg)) => {
+                        // Serialize message
+                        let mut msg_bytes = bincode::serialize(&send_msg).unwrap();
+
+                        // Assemble into packet
+                        let mut packet_bytes = msg_bytes
+                            .len()
+                            .to_le_bytes()
+                            .as_ref()
+                            .to_vec();
+                        packet_bytes.append(&mut msg_bytes);
+
+                        // Split packet into chunks
+                        packet_bytes
+                            .chunks(4096)
+                            .map(|chunk| chunk.to_vec())
+                            .for_each(|chunk| outgoing_chunks.push_back(chunk))
+                    },
+                    // Shut down worker
+                    Ok(None) => break 'work,
+                    Err(mpsc::TryRecvError::Empty) => break,
+                    // Worker error
+                    Err(e) => {
+                        let _ = recv_tx.send(Err(e.into()));
+                        break 'work;
+                    },
+                }
+            }
+
+            // Try sending bytes through the TCP stream
+            loop {
+                //println!("HERE! Outgoing len: {}", outgoing_chunks.len());
+                match outgoing_chunks.pop_front() {
+                    Some(chunk) => match stream.write_all(&chunk) {
+                        Ok(()) => {},
+                        Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
+                            // Return chunk to the queue to try again later
+                            outgoing_chunks.push_front(chunk);
+                            break;
+                        },
+                        // Worker error
+                        Err(e) => {
+                            recv_tx.send(Err(e.into())).unwrap();
+                            break 'work;
+                        },
+                    },
+                    None => break,
+                }
+            }
+
+            // Try receiving bytes from the TCP stream
+            loop {
+                let mut buf = [0; 1024];
+
+                match stream.read(&mut buf) {
+                    Ok(n) => incoming_buf.extend_from_slice(&buf[0..n]),
+                    Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
+                    // Worker error
+                    Err(e) => {
+                        recv_tx.send(Err(e.into())).unwrap();
+                        break 'work;
+                    },
+                }
+            }
+
+            // Try turning bytes into messages
+            loop {
+                match incoming_buf.get(0..8) {
+                    Some(len_bytes) => {
+                        let len = usize::from_le_bytes(<[u8; 8]>::try_from(len_bytes).unwrap()); // Can't fail
+
+                        if len > MAX_MSG_SIZE {
+                            recv_tx.send(Err(Error::InvalidMessage)).unwrap();
+                            break 'work;
+                        } else if incoming_buf.len() >= len + 8 {
+                            let deserialize_result = bincode::deserialize(&incoming_buf[8..len + 8]);
+
+                            if let Err(e) = &deserialize_result {
+                                println!("DESERIALIZE ERROR: {:?}", e);
+                            }
+
+                            recv_tx.send(deserialize_result.map_err(|e| e.into()));
+                            incoming_buf = incoming_buf.split_off(len + 8);
+                        } else {
+                            break;
+                        }
+                    },
+                    None => break,
+                }
+            }
+
+            thread::sleep(Duration::from_millis(10));
+        }
+
+        stream.shutdown(Shutdown::Both);
+    }
+}
+
+impl<S: PostMsg, R: PostMsg> Drop for PostBox<S, R> {
+    fn drop(&mut self) {
+        let _ = self.send_tx.send(None);
+        // TODO: Cleanly join!
+        //self.worker.take().map(|handle| handle.join());
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn create_postoffice<S: PostMsg, R: PostMsg>(id: u16) -> Result<(PostOffice<S, R>, SocketAddr), Error> {
+        let sock = ([0; 4], 12345 + id).into();
+        Ok((PostOffice::bind(sock)?, sock))
+    }
+
+    fn loop_for<F: FnMut()>(duration: Duration, mut f: F) {
+        let start = Instant::now();
+        while start.elapsed() < duration {
+            f();
+        }
+    }
+
+    #[test]
+    fn connect() {
+        let (mut postoffice, sock) = create_postoffice::<(), ()>(0).unwrap();
+
+        let _client0 = PostBox::<(), ()>::to(sock).unwrap();
+        let _client1 = PostBox::<(), ()>::to(sock).unwrap();
+        let _client2 = PostBox::<(), ()>::to(sock).unwrap();
+
+        let mut new_clients = 0;
+        loop_for(Duration::from_millis(250), || {
+            new_clients += postoffice.new_postboxes().count();
+        });
+
+        assert_eq!(new_clients, 3);
+    }
+
+    /*
+    #[test]
+    fn disconnect() {
+        let (mut postoffice, sock) = create_postoffice::<(), ()>(1).unwrap();
+
+        let mut client = PostBox::<i32, ()>::to(sock).unwrap();
+        loop_for(Duration::from_millis(250), || ());
+        let mut server = postoffice.new_postboxes().unwrap().next().unwrap();
+
+        drop(client);
+        loop_for(Duration::from_millis(300), || ());
+
+        assert!(server.new_messages().is_err());
+    }
+    */
+
+    #[test]
+    fn send_recv() {
+        let (mut postoffice, sock) = create_postoffice::<(), i32>(2).unwrap();
+        let test_msgs = vec![1, 1337, 42, -48];
+
+        let mut client = PostBox::<i32, ()>::to(sock).unwrap();
+        loop_for(Duration::from_millis(250), || ());
+        let mut server = postoffice.new_postboxes().next().unwrap();
+
+        for msg in &test_msgs {
+            client.send_message(msg.clone());
+        }
+
+        let mut recv_msgs = Vec::new();
+        loop_for(Duration::from_millis(250), || server
+                .new_messages()
+                .for_each(|msg| recv_msgs.push(msg)));
+
+        assert_eq!(test_msgs, recv_msgs);
+    }
+
+    #[test]
+    fn send_recv_huge() {
+        let (mut postoffice, sock) = create_postoffice::<(), Vec<i32>>(3).unwrap();
+        let test_msgs: Vec<Vec<i32>> = (0..5).map(|i| (0..100000).map(|j| i * 2 + j).collect()).collect();
+
+        let mut client = PostBox::<Vec<i32>, ()>::to(sock).unwrap();
+        loop_for(Duration::from_millis(250), || ());
+        let mut server = postoffice.new_postboxes().next().unwrap();
+
+        for msg in &test_msgs {
+            client.send_message(msg.clone());
+        }
+
+        let mut recv_msgs = Vec::new();
+        loop_for(Duration::from_millis(2000), || server
+                .new_messages()
+                .for_each(|msg| recv_msgs.push(msg)));
+
+        assert_eq!(test_msgs.len(), recv_msgs.len());
+        assert!(test_msgs == recv_msgs);
+    }
+
+    #[test]
+    fn send_recv_both() {
+        let (mut postoffice, sock) = create_postoffice::<u32, u32>(4).unwrap();
+        let test_msgs = vec![1, 1337, 42, -48];
+
+        let mut client = PostBox::<u32, u32>::to(sock).unwrap();
+        loop_for(Duration::from_millis(250), || ());
+        let mut server = postoffice.new_postboxes().next().unwrap();
+
+        let test_msgs = vec![
+            (0xDEADBEAD, 0xBEEEEEEF),
+            (0x1BADB002, 0xBAADF00D),
+            (0xBAADA555, 0xC0DED00D),
+            (0xCAFEBABE, 0xDEADC0DE),
+        ];
+
+        for (to, from) in test_msgs {
+            client.send_message(to);
+            server.send_message(from);
+
+            loop_for(Duration::from_millis(250), || ());
+
+            assert_eq!(client.new_messages().next().unwrap(), from);
+            assert_eq!(server.new_messages().next().unwrap(), to);
+        }
+    }
+}
diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs
index ab2947a416..507c009aea 100644
--- a/common/src/volumes/vol_map.rs
+++ b/common/src/volumes/vol_map.rs
@@ -137,4 +137,8 @@ impl<V: Vox, S: VolSize, M> VolMap<V, S, M> {
     pub fn key_pos(&self, key: Vec3<i32>) -> Vec3<i32> {
         key * S::SIZE.map(|e| e as i32)
     }
+
+    pub fn pos_key(&self, pos: Vec3<i32>) -> Vec3<i32> {
+        Self::chunk_key(pos)
+    }
 }
diff --git a/server/src/client.rs b/server/src/client.rs
index 71d8aae6ab..c0e2eafe90 100644
--- a/server/src/client.rs
+++ b/server/src/client.rs
@@ -21,7 +21,7 @@ pub struct Client {
 
 impl Client {
     pub fn notify(&mut self, msg: ServerMsg) {
-        self.postbox.send(msg);
+        self.postbox.send_message(msg);
     }
 }
 
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 9313505a71..f8ebba4b3c 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -151,7 +151,7 @@ impl Server {
 
                 self.clients.notify(entity, ServerMsg::TerrainChunkUpdate {
                     key,
-                    chunk: chunk.clone(),
+                    chunk: Box::new(chunk.clone()),
                 });
             }
 
@@ -176,7 +176,7 @@ impl Server {
     fn handle_new_connections(&mut self) -> Result<Vec<Event>, Error> {
         let mut frontend_events = Vec::new();
 
-        for mut postbox in self.postoffice.new_connections() {
+        for mut postbox in self.postoffice.new_postboxes() {
             let entity = self.state
                 .ecs_mut()
                 .create_entity_synced()
@@ -245,7 +245,7 @@ impl Server {
                         ClientState::Connected => match msg {
                             ClientMsg::Connect { .. } => disconnect = true, // Not allowed when already connected
                             ClientMsg::Disconnect => disconnect = true,
-                            ClientMsg::Ping => client.postbox.send(ServerMsg::Pong),
+                            ClientMsg::Ping => client.postbox.send_message(ServerMsg::Pong),
                             ClientMsg::Pong => {},
                             ClientMsg::Chat(msg) => new_chat_msgs.push((entity, msg)),
                             ClientMsg::PlayerPhysics { pos, vel, dir } => {
@@ -254,9 +254,9 @@ impl Server {
                                 state.write_component(entity, dir);
                             },
                             ClientMsg::TerrainChunkRequest { key } => match state.terrain().get_key(key) {
-                                Some(chunk) => client.postbox.send(ServerMsg::TerrainChunkUpdate {
+                                Some(chunk) => client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
                                     key,
-                                    chunk: chunk.clone(),
+                                    chunk: Box::new(chunk.clone()),
                                 }),
                                 None => requested_chunks.push(key),
                             },
@@ -270,7 +270,7 @@ impl Server {
                 disconnect = true;
             } else if state.get_time() - client.last_ping > CLIENT_TIMEOUT * 0.5 {
                 // Try pinging the client if the timeout is nearing
-                client.postbox.send(ServerMsg::Ping);
+                client.postbox.send_message(ServerMsg::Ping);
             }
 
             if disconnect {

From 5644238d5675ca1e0d852b5db73805f129ab3a64 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Fri, 12 Apr 2019 10:09:14 +0100
Subject: [PATCH 06/16] Added partial chunk loading, package section to
 workspace Cargo.toml

Former-commit-id: 4164daf4ccbe6695f664a44d0fce0ee10df39b8d
---
 Cargo.toml                    |  6 ++++++
 client/src/lib.rs             |  4 ++++
 common/src/volumes/vol_map.rs | 18 ++++++++++++++++++
 3 files changed, 28 insertions(+)

diff --git a/Cargo.toml b/Cargo.toml
index 533a0add9c..437f7f5e71 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,3 +1,9 @@
+[package]
+name = "veloren"
+description = "Veloren is an open-world, open-source multiplayer voxel RPG."
+documentation = "https://docs.veloren.net"
+repository = "https://www.gitlab.com/veloren/veloren"
+
 [workspace]
 members = [
 	"common",
diff --git a/client/src/lib.rs b/client/src/lib.rs
index 1d5bdc1a00..c98a01b746 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -144,6 +144,10 @@ impl Client {
         // Handle new messages from the server
         frontend_events.append(&mut self.handle_new_messages()?);
 
+        self.state.terrain().iter().for_each(|(k, _)| {
+            println!("Chunk at {:?}", k);
+        });
+
         // Step 1
         if let Some(ecs_entity) = self.player {
             // TODO: remove this
diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs
index 507c009aea..fcf45d32cd 100644
--- a/common/src/volumes/vol_map.rs
+++ b/common/src/volumes/vol_map.rs
@@ -141,4 +141,22 @@ impl<V: Vox, S: VolSize, M> VolMap<V, S, M> {
     pub fn pos_key(&self, pos: Vec3<i32>) -> Vec3<i32> {
         Self::chunk_key(pos)
     }
+
+    pub fn iter<'a>(&'a self) -> ChunkIter<'a, V, S, M> {
+        ChunkIter {
+            iter: self.chunks.iter(),
+        }
+    }
+}
+
+pub struct ChunkIter<'a, V: Vox, S: VolSize, M> {
+    iter: std::collections::hash_map::Iter<'a, Vec3<i32>, Chunk<V, S, M>>,
+}
+
+impl<'a, V: Vox, S: VolSize, M> Iterator for ChunkIter<'a, V, S, M> {
+    type Item = (Vec3<i32>, &'a Chunk<V, S, M>);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next().map(|(k, c)| (*k, c))
+    }
 }

From c878557056ca0416cd47a63d69fac88d8fd7851e Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Fri, 12 Apr 2019 10:10:01 +0100
Subject: [PATCH 07/16] Disabled informing clients of chunks temporarily

Former-commit-id: ab964ebfdae55e1fcf1002d7e7622d58e538c83b
---
 server/src/lib.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/server/src/lib.rs b/server/src/lib.rs
index f8ebba4b3c..8f9c7d5b80 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -149,10 +149,12 @@ impl Server {
                 // TODO: Distance check
                 // if self.state.terrain().key_pos(key)
 
+                /*
                 self.clients.notify(entity, ServerMsg::TerrainChunkUpdate {
                     key,
                     chunk: Box::new(chunk.clone()),
                 });
+                */
             }
 
             self.state.insert_chunk(key, chunk);
@@ -254,10 +256,10 @@ impl Server {
                                 state.write_component(entity, dir);
                             },
                             ClientMsg::TerrainChunkRequest { key } => match state.terrain().get_key(key) {
-                                Some(chunk) => client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
+                                Some(chunk) => {}, /*client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
                                     key,
                                     chunk: Box::new(chunk.clone()),
-                                }),
+                                }),*/
                                 None => requested_chunks.push(key),
                             },
                         },

From d45e518413c617c908c2a972f3caa8de9007821d Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Fri, 12 Apr 2019 10:17:59 +0100
Subject: [PATCH 08/16] Updated package versions

Former-commit-id: bb0d1efd718ddef598fbb894498a43ad014a11c0
---
 Cargo.toml            | 1 +
 chat-cli/Cargo.toml   | 2 +-
 client/Cargo.toml     | 2 +-
 common/Cargo.toml     | 2 +-
 server-cli/Cargo.toml | 2 +-
 server/Cargo.toml     | 2 +-
 voxygen/Cargo.toml    | 2 +-
 world/Cargo.toml      | 2 +-
 8 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 437f7f5e71..f11e750a92 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,6 +3,7 @@ name = "veloren"
 description = "Veloren is an open-world, open-source multiplayer voxel RPG."
 documentation = "https://docs.veloren.net"
 repository = "https://www.gitlab.com/veloren/veloren"
+version = "0.2.0"
 
 [workspace]
 members = [
diff --git a/chat-cli/Cargo.toml b/chat-cli/Cargo.toml
index 61161cd537..90e7c0e5d4 100644
--- a/chat-cli/Cargo.toml
+++ b/chat-cli/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "veloren-chat-cli"
-version = "0.1.0"
+version = "0.2.0"
 authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"]
 edition = "2018"
 
diff --git a/client/Cargo.toml b/client/Cargo.toml
index bc4284934f..847431764b 100644
--- a/client/Cargo.toml
+++ b/client/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "veloren-client"
-version = "0.1.0"
+version = "0.2.0"
 authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"]
 edition = "2018"
 
diff --git a/common/Cargo.toml b/common/Cargo.toml
index 8c82e841a3..1b99516d23 100644
--- a/common/Cargo.toml
+++ b/common/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "veloren-common"
-version = "0.1.0"
+version = "0.2.0"
 authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>", "Maciej Ćwięka <mckol363@gmail.com>"]
 edition = "2018"
 
diff --git a/server-cli/Cargo.toml b/server-cli/Cargo.toml
index d682c8b971..62ad0c6368 100644
--- a/server-cli/Cargo.toml
+++ b/server-cli/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "veloren-server-cli"
-version = "0.1.0"
+version = "0.2.0"
 authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"]
 edition = "2018"
 
diff --git a/server/Cargo.toml b/server/Cargo.toml
index a5b590a902..4189be7693 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "veloren-server"
-version = "0.1.0"
+version = "0.2.0"
 authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"]
 edition = "2018"
 
diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml
index d418ec1e55..c8d67c4104 100644
--- a/voxygen/Cargo.toml
+++ b/voxygen/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "voxygen"
-version = "0.1.0"
+version = "0.2.0"
 authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"]
 edition = "2018"
 
diff --git a/world/Cargo.toml b/world/Cargo.toml
index e24048bcdd..6918256955 100644
--- a/world/Cargo.toml
+++ b/world/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "veloren-world"
-version = "0.1.0"
+version = "0.2.0"
 authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"]
 edition = "2018"
 

From 49732f5361bd58cbda415b772a6296cdd96f4545 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Fri, 12 Apr 2019 10:22:37 +0100
Subject: [PATCH 09/16] Named Voxygen correctly

Former-commit-id: a4f4e5703103e3f93da87bd515e80eb430eef52e
---
 Cargo.toml         | 7 -------
 voxygen/Cargo.toml | 2 +-
 2 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index f11e750a92..533a0add9c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,10 +1,3 @@
-[package]
-name = "veloren"
-description = "Veloren is an open-world, open-source multiplayer voxel RPG."
-documentation = "https://docs.veloren.net"
-repository = "https://www.gitlab.com/veloren/veloren"
-version = "0.2.0"
-
 [workspace]
 members = [
 	"common",
diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml
index c8d67c4104..9af01232bb 100644
--- a/voxygen/Cargo.toml
+++ b/voxygen/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "voxygen"
+name = "veloren-voxygen"
 version = "0.2.0"
 authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"]
 edition = "2018"

From de8a6b3c1e9a078ea8ddc0d7d7ed0ded87a70be7 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Fri, 12 Apr 2019 14:16:44 +0100
Subject: [PATCH 10/16] Prevented postal workers spinning for too long

Former-commit-id: e535f5745c817b7fd5f109711aaa65e6c78d6ecc
---
 common/src/net/post2.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/common/src/net/post2.rs b/common/src/net/post2.rs
index 16a9bb985a..c82e3b14c6 100644
--- a/common/src/net/post2.rs
+++ b/common/src/net/post2.rs
@@ -174,7 +174,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
             }
 
             // Try getting messages from the send channel
-            loop {
+            for _ in 0..10 {
                 match send_rx.try_recv() {
                     Ok(Some(send_msg)) => {
                         // Serialize message
@@ -206,7 +206,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
             }
 
             // Try sending bytes through the TCP stream
-            loop {
+            for _ in 0..10 {
                 //println!("HERE! Outgoing len: {}", outgoing_chunks.len());
                 match outgoing_chunks.pop_front() {
                     Some(chunk) => match stream.write_all(&chunk) {
@@ -227,7 +227,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
             }
 
             // Try receiving bytes from the TCP stream
-            loop {
+            for _ in 0..10 {
                 let mut buf = [0; 1024];
 
                 match stream.read(&mut buf) {
@@ -242,7 +242,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
             }
 
             // Try turning bytes into messages
-            loop {
+            for _ in 0..10 {
                 match incoming_buf.get(0..8) {
                     Some(len_bytes) => {
                         let len = usize::from_le_bytes(<[u8; 8]>::try_from(len_bytes).unwrap()); // Can't fail

From 86ab128b158943e642c94f78eda366c493303aae Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Fri, 12 Apr 2019 14:36:52 +0100
Subject: [PATCH 11/16] Extended timeout on huge transfer test to avoid failure
 on debug

Former-commit-id: 7fa49db2ce310ff83b0c7ba2c4525771f16e7842
---
 common/src/net/post2.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common/src/net/post2.rs b/common/src/net/post2.rs
index c82e3b14c6..62f95078eb 100644
--- a/common/src/net/post2.rs
+++ b/common/src/net/post2.rs
@@ -365,7 +365,7 @@ mod tests {
         }
 
         let mut recv_msgs = Vec::new();
-        loop_for(Duration::from_millis(2000), || server
+        loop_for(Duration::from_millis(3000), || server
                 .new_messages()
                 .for_each(|msg| recv_msgs.push(msg)));
 

From a9c2b24ed9aa39704ae7d592df59e8d2e01edfa5 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Fri, 12 Apr 2019 17:03:42 +0100
Subject: [PATCH 12/16] Fixed 1-frame animation bug

Former-commit-id: fc591de5026e35cab1ef72ce250b19cbe2fcec0e
---
 voxygen/src/scene/figure.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs
index e0c5ae6ba4..5b61c7ec32 100644
--- a/voxygen/src/scene/figure.rs
+++ b/voxygen/src/scene/figure.rs
@@ -91,9 +91,9 @@ impl Figures {
                 .entry(entity)
                 .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
 
-            state.update(renderer, pos.0, dir.0);
-
             RunAnimation::update_skeleton(&mut state.skeleton, time);
+
+            state.update(renderer, pos.0, dir.0);
         }
 
         self.states.retain(|entity, _| ecs.entities().is_alive(*entity));

From 0f5afd1f9240b447e2f9cfeaa4697af0a5f1a56a Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Fri, 12 Apr 2019 17:17:14 +0100
Subject: [PATCH 13/16] Fixed zombie network worker threads

Former-commit-id: a8e74a9a8e42a0d5e1a79d87a1daf398e6294c73
---
 common/src/net/post2.rs | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/common/src/net/post2.rs b/common/src/net/post2.rs
index 62f95078eb..25db57288b 100644
--- a/common/src/net/post2.rs
+++ b/common/src/net/post2.rs
@@ -3,7 +3,7 @@ use std::{
     net::{TcpListener, TcpStream, SocketAddr, Shutdown},
     time::{Instant, Duration},
     marker::PhantomData,
-    sync::mpsc,
+    sync::{mpsc, Arc, atomic::{AtomicBool, Ordering}},
     thread,
     collections::VecDeque,
     convert::TryFrom,
@@ -85,9 +85,10 @@ impl<S: PostMsg, R: PostMsg> PostOffice<S, R> {
 }
 
 pub struct PostBox<S: PostMsg, R: PostMsg> {
-    send_tx: mpsc::Sender<Option<S>>,
+    send_tx: mpsc::Sender<S>,
     recv_rx: mpsc::Receiver<Result<R, Error>>,
     worker: Option<thread::JoinHandle<()>>,
+    running: Arc<AtomicBool>,
     error: Option<Error>,
 }
 
@@ -99,15 +100,19 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
     fn from_stream(stream: TcpStream) -> Result<Self, Error> {
         stream.set_nonblocking(true)?;
 
+        let running = Arc::new(AtomicBool::new(true));
+        let worker_running = running.clone();
+
         let (send_tx, send_rx) = mpsc::channel();
         let (recv_tx, recv_rx) = mpsc::channel();
 
-        let worker = thread::spawn(move || Self::worker(stream, send_rx, recv_tx));
+        let worker = thread::spawn(move || Self::worker(stream, send_rx, recv_tx, worker_running));
 
         Ok(Self {
             send_tx,
             recv_rx,
             worker: Some(worker),
+            running,
             error: None,
         })
     }
@@ -117,7 +122,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
     }
 
     pub fn send_message(&mut self, msg: S) {
-        let _ = self.send_tx.send(Some(msg));
+        let _ = self.send_tx.send(msg);
     }
 
     pub fn next_message(&mut self) -> Option<R> {
@@ -159,11 +164,11 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
         new.into_iter()
     }
 
-    fn worker(mut stream: TcpStream, send_rx: mpsc::Receiver<Option<S>>, recv_tx: mpsc::Sender<Result<R, Error>>) {
+    fn worker(mut stream: TcpStream, send_rx: mpsc::Receiver<S>, recv_tx: mpsc::Sender<Result<R, Error>>, running: Arc<AtomicBool>) {
         let mut outgoing_chunks = VecDeque::new();
         let mut incoming_buf = Vec::new();
 
-        'work: loop {
+        'work: while running.load(Ordering::Relaxed) {
             // Get stream errors
             match stream.take_error() {
                 Ok(Some(e)) | Err(e) => {
@@ -176,7 +181,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
             // Try getting messages from the send channel
             for _ in 0..10 {
                 match send_rx.try_recv() {
-                    Ok(Some(send_msg)) => {
+                    Ok(send_msg) => {
                         // Serialize message
                         let mut msg_bytes = bincode::serialize(&send_msg).unwrap();
 
@@ -194,8 +199,6 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
                             .map(|chunk| chunk.to_vec())
                             .for_each(|chunk| outgoing_chunks.push_back(chunk))
                     },
-                    // Shut down worker
-                    Ok(None) => break 'work,
                     Err(mpsc::TryRecvError::Empty) => break,
                     // Worker error
                     Err(e) => {
@@ -276,9 +279,8 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
 
 impl<S: PostMsg, R: PostMsg> Drop for PostBox<S, R> {
     fn drop(&mut self) {
-        let _ = self.send_tx.send(None);
-        // TODO: Cleanly join!
-        //self.worker.take().map(|handle| handle.join());
+        self.running.store(false, Ordering::Relaxed);
+        self.worker.take().map(|handle| handle.join());
     }
 }
 

From cb45a079cd74483226cc441e6efae77afc358e54 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Fri, 12 Apr 2019 23:19:19 +0100
Subject: [PATCH 14/16] Ensured that Client is Send

Former-commit-id: abadfc7d1d86110ed442cdb5a2e639c163c96e04
---
 voxygen/src/anim/character/run.rs | 17 +++++++++--------
 voxygen/src/anim/mod.rs           |  4 +++-
 2 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/voxygen/src/anim/character/run.rs b/voxygen/src/anim/character/run.rs
index 015feb8d89..ac78dca92e 100644
--- a/voxygen/src/anim/character/run.rs
+++ b/voxygen/src/anim/character/run.rs
@@ -24,27 +24,28 @@ impl Animation for RunAnimation {
         let wave_slow = (time as f32 * 6.0 + PI).sin();
         let wave_dip = (wave_slow.abs() - 0.5).abs();
 
-        skeleton.head.offset = Vec3::unit_z() * 13.0;
+        skeleton.head.offset = Vec3::unit_z() * 13.0 / 11.0;
         skeleton.head.ori = Quaternion::rotation_z(wave * 0.3);
 
-        skeleton.chest.offset = Vec3::unit_z() * 9.0;
+        skeleton.chest.offset = Vec3::unit_z() * 9.0 / 11.0;
         skeleton.chest.ori = Quaternion::rotation_z(wave * 0.3);
 
-        skeleton.belt.offset = Vec3::unit_z() * 7.0;
+        skeleton.belt.offset = Vec3::unit_z() * 7.0 / 11.0;
         skeleton.belt.ori = Quaternion::rotation_z(wave * 0.2);
 
-        skeleton.shorts.offset = Vec3::unit_z() * 4.0;
+        skeleton.shorts.offset = Vec3::unit_z() * 4.0 / 11.0;
         skeleton.shorts.ori = Quaternion::rotation_z(wave * 0.1);
 
-        skeleton.l_hand.offset = Vec3::new(-6.0 - wave_dip * 6.0, wave * 5.0, 11.0 - wave_dip * 6.0);
-        skeleton.r_hand.offset = Vec3::new(6.0 + wave_dip * 6.0, -wave * 5.0, 11.0 - wave_dip * 6.0);
+        skeleton.l_hand.offset = Vec3::new(-6.0 - wave_dip * 6.0, wave * 5.0, 11.0 - wave_dip * 6.0) / 11.0;
+        skeleton.r_hand.offset = Vec3::new(6.0 + wave_dip * 6.0, -wave * 5.0, 11.0 - wave_dip * 6.0) / 11.0;
 
-        skeleton.l_foot.offset = Vec3::new(-3.5, 1.0 - wave * 8.0, 3.5 - wave_dip * 4.0);
+        skeleton.l_foot.offset = Vec3::new(-3.5, 1.0 - wave * 8.0, 3.5 - wave_dip * 4.0) / 11.0;
         skeleton.l_foot.ori = Quaternion::rotation_x(-wave + 1.0);
-        skeleton.r_foot.offset = Vec3::new(3.5, 1.0 + wave * 8.0, 3.5 - wave_dip * 4.0);
+        skeleton.r_foot.offset = Vec3::new(3.5, 1.0 + wave * 8.0, 3.5 - wave_dip * 4.0) / 11.0;
         skeleton.r_foot.ori = Quaternion::rotation_x(wave + 1.0);
 
         skeleton.back.offset = Vec3::new(-9.0, 5.0, 18.0);
         skeleton.back.ori = Quaternion::rotation_y(2.5);
+        skeleton.back.scale = Vec3::one();
     }
 }
diff --git a/voxygen/src/anim/mod.rs b/voxygen/src/anim/mod.rs
index be609f0d59..e226c48e7f 100644
--- a/voxygen/src/anim/mod.rs
+++ b/voxygen/src/anim/mod.rs
@@ -10,6 +10,7 @@ use crate::render::FigureBoneData;
 pub struct Bone {
     pub offset: Vec3<f32>,
     pub ori: Quaternion<f32>,
+    pub scale: Vec3<f32>,
 }
 
 impl Bone {
@@ -17,11 +18,12 @@ impl Bone {
         Self {
             offset: Vec3::zero(),
             ori: Quaternion::identity(),
+            scale: Vec3::broadcast(1.0 / 11.0),
         }
     }
 
     pub fn compute_base_matrix(&self) -> Mat4<f32> {
-        Mat4::<f32>::translation_3d(self.offset) * Mat4::from(self.ori)
+        Mat4::<f32>::translation_3d(self.offset) * Mat4::scaling_3d(self.scale) * Mat4::from(self.ori)
     }
 }
 

From a0d32f870c9392fe7f8742da18c1fc5b5c8345e7 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Fri, 12 Apr 2019 23:20:08 +0100
Subject: [PATCH 15/16] Fixed player speed

Former-commit-id: becc175a91cd60a8957baa8eaaab35f740f677ed
---
 client/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/client/src/lib.rs b/client/src/lib.rs
index c98a01b746..a2e3648bea 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -153,7 +153,7 @@ impl Client {
             // TODO: remove this
             const PLAYER_VELOCITY: f32 = 100.0;
             // TODO: Set acceleration instead
-            self.state.write_component(ecs_entity, comp::phys::Vel(Vec3::from(input.move_dir * PLAYER_VELOCITY)));
+            self.state.write_component(ecs_entity, comp::phys::Vel(Vec3::from(input.move_dir * PLAYER_VELOCITY) * 0.1));
             if input.move_dir.magnitude() > 0.01 {
                 self.state.write_component(ecs_entity, comp::phys::Dir(input.move_dir.normalized().into()));
             }

From 33e0cb54f3832205c752092b75b975ae065b7726 Mon Sep 17 00:00:00 2001
From: Joshua Barretto <joshua.s.barretto@gmail.com>
Date: Sat, 13 Apr 2019 23:17:44 +0100
Subject: [PATCH 16/16] Rebased

Former-commit-id: 017002bca2078f48998ecb412480492556082491
---
 common/src/msg/client.rs | 2 --
 common/src/msg/server.rs | 2 --
 2 files changed, 4 deletions(-)

diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs
index ffc941b1b6..5a599633d7 100644
--- a/common/src/msg/client.rs
+++ b/common/src/msg/client.rs
@@ -20,5 +20,3 @@ pub enum ClientMsg {
     },
     Disconnect,
 }
-
-impl middleman::Message for ClientMsg {}
diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs
index bdd86945ca..2f852072bf 100644
--- a/common/src/msg/server.rs
+++ b/common/src/msg/server.rs
@@ -19,5 +19,3 @@ pub enum ServerMsg {
         chunk: Box<TerrainChunk>,
     },
 }
-
-impl middleman::Message for ServerMsg {}