Code: 5
 Payload:
-        0 entity ID, 32bit unsigned int
-        4 chunk coords of the entity, 3x 32bit signed int
-       16 pos/vel/rot/ang of the entity, 13x 32bit float
-       68 bounding box of the entity, 6x 32bit float
-       92 flags, 32bit bitfield with boolean values
-          1: world collision
-       96 entity name, max 32 byte UTF-8 string
-Length: 128
+         0 entity ID, 32bit unsigned int
+         4 entity's skeleton ID, 32bit unsigned int
+         8 chunk coords of the entity, 3x 32bit signed int
+        20 pos/vel/rot/ang of the entity, 13x 32bit float
+        72 bounding box of the entity, 6x 32bit float
+        96 flags, 32bit bitfield with boolean values
+           1: world collision
+       100 entity name, max 32 byte UTF-8 string
+Length: 132
 
 
 Despawn Entity
 
 
 #include "../app/State.hpp"
 #include "../io/WorldSave.hpp"
+#include "../model/Skeletons.hpp"
 #include "../ui/Interface.hpp"
 #include "../world/BlockTypeRegistry.hpp"
 #include "../world/ChunkRenderer.hpp"
 
        World &GetWorld() noexcept { return world; }
        Interface &GetInterface() noexcept { return interface; }
+       Skeletons &GetSkeletons() noexcept { return skeletons; }
 
        void OnEnter() override;
 
        World world;
        Interface interface;
        ChunkRenderer chunk_renderer;
+       Skeletons skeletons;
 
 };
 
 
 #include "../app/Environment.hpp"
 #include "../app/init.hpp"
 #include "../app/TextureIndex.hpp"
+#include "../model/CompositeModel.hpp"
 
 #include <iostream>
 #include <glm/gtx/io.hpp>
        world,
        world.AddPlayer(master.GetInterfaceConf().player_name, player_id)
 )
-, chunk_renderer(*interface.GetPlayer().chunks) {
+, chunk_renderer(*interface.GetPlayer().chunks)
+, skeletons() {
        TextureIndex tex_index;
        master.GetEnv().loader.LoadBlockTypes("default", block_types, tex_index);
        chunk_renderer.LoadTextures(master.GetEnv().loader, tex_index);
        chunk_renderer.FogDensity(master.GetWorldConf().fog_density);
+       skeletons.Load();
        // TODO: better solution for initializing HUD
        interface.SelectNext();
 }
                return;
        }
        pack.ReadEntity(*entity);
+       uint32_t skel_id;
+       pack.ReadSkeletonID(skel_id);
+       CompositeModel *skel = state->GetSkeletons().ByID(skel_id);
+       if (skel) {
+               skel->Instantiate(entity->GetModel());
+       }
        cout << "spawned entity " << entity->Name() << " at " << entity->AbsolutePosition() << endl;
 }
 
 
        CompositeInstance();
 
        operator bool() const noexcept { return part_model; }
+       const CompositeModel &GetModel() const noexcept { return *part_model; }
 
        const glm::vec3 &Position() const noexcept { return position; }
        void Position(const glm::vec3 &p) noexcept { position = p; }
 
 
 #include "geometry.hpp"
 
+#include <cstdint>
 #include <list>
 #include <glm/glm.hpp>
 #include <glm/gtc/quaternion.hpp>
        CompositeModel(const CompositeModel &) = delete;
        CompositeModel &operator =(const CompositeModel &) = delete;
 
+       std::uint32_t ID() const noexcept { return id; }
+       void ID(std::uint32_t i) noexcept { id = i; }
+
        const AABB &Bounds() const noexcept { return bounds; }
        void Bounds(const AABB &b) noexcept { bounds = b; }
 
        CompositeModel *parent;
        const EntityModel *node_model;
 
+       std::uint32_t id;
+
        AABB bounds;
 
        glm::vec3 position;
 
 #ifndef BLANK_MODEL_SKELETONS_HPP_
 #define BLANK_MODEL_SKELETONS_HPP_
 
+#include <cstdint>
 #include <memory>
 #include <vector>
 
        CompositeModel &operator[](std::size_t i) noexcept { return *skeletons[i]; }
        const CompositeModel &operator[](std::size_t i) const noexcept { return *skeletons[i]; }
 
+       CompositeModel *ByID(std::uint16_t) noexcept;
+       const CompositeModel *ByID(std::uint16_t) const noexcept;
+
 private:
        std::vector<std::unique_ptr<CompositeModel>> skeletons;
        std::vector<EntityModel> models;
 
 namespace blank {
 
 CompositeModel::CompositeModel()
-: node_model(nullptr)
+: parent(nullptr)
+, node_model(nullptr)
+, id(0)
+, bounds{{ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }}
 , position(0.0f)
 , orientation(1.0f, 0.0f, 0.0f, 0.0f)
 , parts() {
        {
                AABB bounds{{ -0.25f, -0.5f, -0.25f }, { 0.25f, 0.5f, 0.25f }};
                skeletons.emplace_back(new CompositeModel);
+               skeletons[0]->ID(1);
                skeletons[0]->Bounds(bounds);
        }
        {
                AABB bounds{{ -0.5f, -0.25f, -0.5f }, { 0.5f, 0.25f, 0.5f }};
                skeletons.emplace_back(new CompositeModel);
+               skeletons[1]->ID(2);
                skeletons[1]->Bounds(bounds);
        }
        {
                AABB bounds{{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }};
                skeletons.emplace_back(new CompositeModel);
+               skeletons[2]->ID(3);
                skeletons[2]->Bounds(bounds);
        }
 }
        }
 }
 
+CompositeModel *Skeletons::ByID(std::uint16_t id) noexcept {
+       if (id == 0 || id > skeletons.size()) {
+               return nullptr;
+       } else {
+               return skeletons[id - 1].get();
+       }
+}
+
+const CompositeModel *Skeletons::ByID(std::uint16_t id) const noexcept {
+       if (id == 0 || id > skeletons.size()) {
+               return nullptr;
+       } else {
+               return skeletons[id - 1].get();
+       }
+}
+
 }
 
 
        struct SpawnEntity : public Payload {
                static constexpr std::uint8_t TYPE = 5;
-               static constexpr std::size_t MAX_LEN = 128;
+               static constexpr std::size_t MAX_LEN = 132;
 
                void WriteEntity(const Entity &) noexcept;
                void ReadEntityID(std::uint32_t &) const noexcept;
+               void ReadSkeletonID(std::uint32_t &) const noexcept;
                void ReadEntity(Entity &) const noexcept;
        };
 
 
 #include "Server.hpp"
 
 #include "../app/init.hpp"
+#include "../model/CompositeModel.hpp"
 #include "../world/World.hpp"
 
 #include <cstring>
 
 void Packet::SpawnEntity::WriteEntity(const Entity &e) noexcept {
        Write(e.ID(), 0);
-       Write(e.ChunkCoords(), 4);
-       Write(e.Position(), 16);
-       Write(e.Velocity(), 28);
-       Write(e.Orientation(), 40);
-       Write(e.AngularVelocity(), 56);
-       Write(e.Bounds(), 68);
+       if (e.GetModel()) {
+               Write(e.GetModel().GetModel().ID(), 4);
+       } else {
+               Write(uint32_t(0), 4);
+       }
+       Write(e.ChunkCoords(), 8);
+       Write(e.Position(), 20);
+       Write(e.Velocity(), 32);
+       Write(e.Orientation(), 44);
+       Write(e.AngularVelocity(), 60);
+       Write(e.Bounds(), 72);
        uint32_t flags = 0;
        if (e.WorldCollidable()) {
                flags |= 1;
        }
-       Write(flags, 92);
-       WriteString(e.Name(), 96, 32);
+       Write(flags, 96);
+       WriteString(e.Name(), 100, 32);
 }
 
 void Packet::SpawnEntity::ReadEntityID(uint32_t &id) const noexcept {
        Read(id, 0);
 }
 
+void Packet::SpawnEntity::ReadSkeletonID(uint32_t &id) const noexcept {
+       Read(id, 4);
+}
+
 void Packet::SpawnEntity::ReadEntity(Entity &e) const noexcept {
        glm::ivec3 chunk_coords(0);
        glm::vec3 pos;
        uint32_t flags = 0;
        string name;
 
-       Read(chunk_coords, 4);
-       Read(pos, 16);
-       Read(vel, 28);
-       Read(rot, 40);
-       Read(ang, 56);
-       Read(bounds, 68);
-       Read(flags, 92);
-       ReadString(name, 96, 32);
+       Read(chunk_coords, 8);
+       Read(pos, 20);
+       Read(vel, 32);
+       Read(rot, 44);
+       Read(ang, 60);
+       Read(bounds, 72);
+       Read(flags, 96);
+       ReadString(name, 100, 32);
 
        e.Position(chunk_coords, pos);
        e.Velocity(vel);