LDXXFLAGS += $(PKGLIBS)
 
 DEBUG_FLAGS = -g3 -O0
-PROFILE_FLAGS = -DNDEBUG -O1 -g3
+PROFILE_FLAGS = -DNDEBUG -O1 -g3 -DBLANK_PROFILING
 RELEASE_FLAGS = -DNDEBUG -O2 -g1
 TEST_FLAGS = -g -O2 -I./src $(TESTFLAGS)
 
 
 #include "RandomWalk.hpp"
 #include "../model/CompositeModel.hpp"
 #include "../model/Skeletons.hpp"
+#include "../rand/GaloisLFSR.hpp"
 #include "../world/BlockLookup.hpp"
 #include "../world/BlockType.hpp"
 #include "../world/ChunkIndex.hpp"
 
 namespace blank {
 
-Spawner::Spawner(World &world, Skeletons &skeletons, uint64_t seed)
+Spawner::Spawner(World &world, Skeletons &skeletons, GaloisLFSR &rand)
 : world(world)
 , skeletons(skeletons)
 , controllers()
-, random(seed)
+, random(rand)
 , timer(64)
 , despawn_range(128 * 128)
 , spawn_distance(16 * 16)
 , max_entities(16)
 , chunk_range(4)
 , skeletons_offset(0)
-, skeletons_length(skeletons.Size()) {
+, skeletons_length(skeletons.size()) {
        timer.Start();
 }
 
 
 
 void Spawner::LimitSkeletons(size_t begin, size_t end) {
-       if (begin >= skeletons.Size() || end > skeletons.Size() || begin >= end) {
+       if (begin >= skeletons.size() || end > skeletons.size() || begin >= end) {
                cout << "warning, skeleton limit out of bounds or invalid range given" << endl;
        } else {
                skeletons_offset = begin;
        }
        const Player &player = *i;
 
-       int index = random.Next<unsigned int>() % player.GetChunks().TotalChunks();
-
-       glm::ivec3 chunk(player.GetChunks().PositionOf(index));
-
-       glm::ivec3 pos(
-               random.Next<unsigned char>() % Chunk::width,
-               random.Next<unsigned char>() % Chunk::height,
-               random.Next<unsigned char>() % Chunk::depth
-       );
+       BlockLookup spawn_block(player.GetChunks().RandomBlock(random));
 
        // distance check
        //glm::vec3 diff(glm::vec3(chunk * Chunk::Extent() - pos) + player.entity->Position());
        //}
 
        // check if the spawn block and the one above it are loaded and inhabitable
-       BlockLookup spawn_block(player.GetChunks()[index], pos);
        if (!spawn_block || spawn_block.GetType().collide_block) {
                return;
        }
                return;
        }
 
-       Spawn(player.GetEntity(), chunk, glm::vec3(pos) + glm::vec3(0.5f));
+       Spawn(player.GetEntity(), spawn_block.GetChunk().Position(), spawn_block.GetBlockCoords());
 }
 
 void Spawner::Spawn(Entity &reference, const glm::ivec3 &chunk, const glm::vec3 &pos) {
 
 #define BLANK_AI_SPAWNER_HPP_
 
 #include "../app/IntervalTimer.hpp"
-#include "../rand/GaloisLFSR.hpp"
 
 #include <vector>
 #include <glm/glm.hpp>
 class CompositeModel;
 class Controller;
 class Entity;
+class GaloisLFSR;
 class Skeletons;
 class World;
 
 class Spawner {
 
 public:
-       Spawner(World &, Skeletons &, std::uint64_t seed);
+       Spawner(World &, Skeletons &, GaloisLFSR &);
        ~Spawner();
 
        void LimitSkeletons(std::size_t begin, std::size_t end);
        Skeletons &skeletons;
        std::vector<Controller *> controllers;
 
-       GaloisLFSR random;
+       GaloisLFSR &random;
 
        IntervalTimer timer;
        float despawn_range;
 
 #include "StateControl.hpp"
 #include "../audio/Audio.hpp"
 #include "../graphics/Viewport.hpp"
+#include "../rand/GaloisLFSR.hpp"
 #include "../ui/Keymap.hpp"
 
 #include <string>
 
        StateControl state;
 
+       GaloisLFSR rng;
+
 
        explicit HeadlessEnvironment(const Config &);
 
 
 
 #include <cctype>
 #include <cstdlib>
+#include <ctime>
 #include <fstream>
 #include <iostream>
 #include <SDL.h>
 : config(config)
 , loader(config.asset_path)
 , counter()
-, state() {
-
+, state()
+, rng(
+#ifdef BLANK_PROFILING
+0
+#else
+std::time(nullptr)
+#endif
+){
+       for (int i = 0; i < 4; ++i) {
+               rng.Next<int>();
+       }
 }
 
 string HeadlessEnvironment::Config::GetWorldPath(const string &world_name) const {
 
 
 class Skeletons {
 
+public:
+       using size_type = std::size_t;
+       using reference = CompositeModel &;
+       using const_reference = const CompositeModel &;
+
 public:
        Skeletons();
        ~Skeletons();
        void LoadHeadless();
        void Load();
 
-       std::size_t Size() const noexcept { return skeletons.size(); }
+       size_type size() const noexcept { return skeletons.size(); }
 
-       CompositeModel &operator[](std::size_t i) noexcept { return *skeletons[i]; }
-       const CompositeModel &operator[](std::size_t i) const noexcept { return *skeletons[i]; }
+       reference operator[](size_type i) noexcept { return *skeletons[i]; }
+       const_reference operator[](size_type i) const noexcept { return *skeletons[i]; }
 
        CompositeModel *ByID(std::uint16_t) noexcept;
        const CompositeModel *ByID(std::uint16_t) const noexcept;
 
                return (*this)(next);
        }
 
+       template<class Container>
+       typename Container::reference From(Container &c) {
+               return c[Next<typename Container::size_type>() % c.size()];
+       }
+       template<class Container>
+       typename Container::const_reference From(const Container &c) {
+               return c[Next<typename Container::size_type>() % c.size()];
+       }
+
 private:
        std::uint64_t state;
        // bits 64, 63, 61, and 60 set to 1 (counting from 1 lo to hi)
 
 , generator(gc, block_types)
 , chunk_loader(world.Chunks(), generator, ws)
 , skeletons()
-, spawner(world, skeletons, gc.seed)
+, spawner(world, skeletons, env.rng)
 , server(config.net, world, ws)
 , loop_timer(16) {
        TextureIndex tex_index;
        env.loader.LoadBlockTypes("default", block_types, tex_index);
        generator.Scan();
        skeletons.LoadHeadless();
-       spawner.LimitSkeletons(1, skeletons.Size());
+       spawner.LimitSkeletons(1, skeletons.size());
        server.SetPlayerModel(skeletons[0]);
 
        loop_timer.Start();
 
 , chunk_loader(world.Chunks(), generator, save)
 , chunk_renderer(player.GetChunks())
 , skeletons()
-, spawner(world, skeletons, gc.seed)
+, spawner(world, skeletons, env.rng)
 , sky(env.loader.LoadCubeMap("skybox"))
 , preload(env, chunk_loader, chunk_renderer)
 , unload(env, world.Chunks(), save) {
        chunk_renderer.LoadTextures(env.loader, tex_index);
        chunk_renderer.FogDensity(wc.fog_density);
        skeletons.Load();
-       spawner.LimitSkeletons(0, skeletons.Size());
+       spawner.LimitSkeletons(0, skeletons.size());
        if (save.Exists(player)) {
                save.Read(player);
        } else {
 
 #ifndef BLANK_WORLD_CHUNKINDEX_HPP_
 #define BLANK_WORLD_CHUNKINDEX_HPP_
 
+#include "BlockLookup.hpp"
 #include "Chunk.hpp"
+#include "../rand/GaloisLFSR.hpp"
 
 #include <vector>
 
        Chunk *operator [](int i) noexcept { return chunks[i]; }
        const Chunk *operator [](int i) const noexcept { return chunks[i]; }
 
+       Chunk *RandomChunk(GaloisLFSR &rand) {
+               return rand.From(chunks);
+       }
+       BlockLookup RandomBlock(GaloisLFSR &rand) {
+               return BlockLookup(RandomChunk(rand), Chunk::ToPos(rand.Next<unsigned int>() % Chunk::size));
+       }
+
        int Extent() const noexcept { return extent; }
 
        Chunk::Pos CoordsBegin() const noexcept { return base - Chunk::Pos(extent); }