-Subproject commit 82ab37629683a73061240c2d7da64f0a612fde42
+Subproject commit 2e992fd6861d4c45c5938bd519600aeb8b8be386
#include "Chaser.hpp"
#include "RandomWalk.hpp"
-#include "../app/TextureIndex.hpp"
#include "../model/Model.hpp"
-#include "../model/Skeletons.hpp"
+#include "../model/ModelRegistry.hpp"
#include "../rand/GaloisLFSR.hpp"
#include "../world/BlockLookup.hpp"
#include "../world/BlockType.hpp"
namespace blank {
-Spawner::Spawner(World &world, Skeletons &skeletons, GaloisLFSR &rand)
+Spawner::Spawner(World &world, ModelRegistry &models, GaloisLFSR &rand)
: world(world)
-, skeletons(skeletons)
+, models(models)
, controllers()
, random(rand)
, timer(64)
, spawn_distance(16 * 16)
, max_entities(16)
, chunk_range(4)
-, skeletons_offset(0)
-, skeletons_length(skeletons.size())
-, tex_map() {
+, model_offset(0)
+, model_length(models.size()) {
timer.Start();
}
}
-void Spawner::LimitSkeletons(size_t begin, size_t end) {
- if (begin >= skeletons.size() || end > skeletons.size() || begin >= end) {
- cout << "warning, skeleton limit out of bounds or invalid range given" << endl;
+void Spawner::LimitModels(size_t begin, size_t end) {
+ if (begin >= models.size() || end > models.size() || begin >= end) {
+ cout << "warning, models limit out of bounds or invalid range given" << endl;
} else {
- skeletons_offset = begin;
- skeletons_length = end - begin;
+ model_offset = begin;
+ model_length = end - begin;
}
}
-void Spawner::LoadTextures(TextureIndex &tex_index) {
- tex_map.clear();
- tex_map.push_back(tex_index.GetID("rock-1"));
- tex_map.push_back(tex_index.GetID("rock-face"));
-}
-
void Spawner::Update(int dt) {
CheckDespawn();
timer.Update(dt);
}
void Spawner::TrySpawn() {
- if (controllers.size() >= max_entities || skeletons_length == 0) return;
+ if (controllers.size() >= max_entities || model_length == 0) return;
// select random player to punish
auto &players = world.Players();
e.Position(chunk, pos);
e.Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
e.WorldCollidable(true);
- RandomSkeleton().Instantiate(e.GetModel());
- e.GetModel().SetTextures(tex_map);
+ RandomModel().Instantiate(e.GetModel());
e.AngularVelocity(rot);
Controller *ctrl;
if (random()) {
controllers.emplace_back(ctrl);
}
-Model &Spawner::RandomSkeleton() noexcept {
- std::size_t offset = (random.Next<std::size_t>() % skeletons_length) + skeletons_offset;
- return skeletons[offset];
+Model &Spawner::RandomModel() noexcept {
+ std::size_t offset = (random.Next<std::size_t>() % model_length) + model_offset;
+ return models[offset];
}
}
class Entity;
class GaloisLFSR;
class Model;
-class Skeletons;
-class TextureIndex;
+class ModelRegistry;
class World;
class Spawner {
public:
- Spawner(World &, Skeletons &, GaloisLFSR &);
+ Spawner(World &, ModelRegistry &, GaloisLFSR &);
~Spawner();
- void LimitSkeletons(std::size_t begin, std::size_t end);
- void LoadTextures(TextureIndex &);
+ void LimitModels(std::size_t begin, std::size_t end);
void Update(int dt);
void TrySpawn();
void Spawn(Entity &reference, const glm::ivec3 &, const glm::vec3 &);
- Model &RandomSkeleton() noexcept;
+ Model &RandomModel() noexcept;
private:
World &world;
- Skeletons &skeletons;
+ ModelRegistry ⊧
std::vector<Controller *> controllers;
GaloisLFSR &random;
unsigned int max_entities;
int chunk_range;
- std::size_t skeletons_offset;
- std::size_t skeletons_length;
-
- std::vector<float> tex_map;
+ std::size_t model_offset;
+ std::size_t model_length;
};
class ArrayTexture;
class BlockTypeRegistry;
class CubeMap;
+class ModelRegistry;
class ShapeRegistry;
class Sound;
class Texture;
const ShapeRegistry &) const;
CubeMap LoadCubeMap(const std::string &name) const;
Font LoadFont(const std::string &name, int size) const;
+ void LoadModels(
+ const std::string &set_name,
+ ModelRegistry &,
+ TextureIndex &,
+ const ShapeRegistry &) const;
void LoadShapes(const std::string &set_name, ShapeRegistry &) const;
Sound LoadSound(const std::string &name) const;
Texture LoadTexture(const std::string &name) const;
#include "../graphics/Texture.hpp"
#include "../io/TokenStreamReader.hpp"
#include "../model/bounds.hpp"
+#include "../model/Model.hpp"
+#include "../model/ModelRegistry.hpp"
#include "../model/Shape.hpp"
#include "../model/ShapeRegistry.hpp"
#include "../world/BlockType.hpp"
return Font(full.c_str(), size);
}
+void AssetLoader::LoadModels(
+ const string &set_name,
+ ModelRegistry &models,
+ TextureIndex &tex_index,
+ const ShapeRegistry &shapes
+) const {
+ string full = data + set_name + ".models";
+ std::ifstream file(full);
+ if (!file) {
+ throw std::runtime_error("failed to open model file " + full);
+ }
+ TokenStreamReader in(file);
+ string model_name;
+ string prop_name;
+ while (in.HasMore()) {
+ in.ReadIdentifier(model_name);
+ in.Skip(Token::EQUALS);
+ in.Skip(Token::ANGLE_BRACKET_OPEN);
+ Model &model = models.Add(model_name);
+ while (in.HasMore() && in.Peek().type != Token::ANGLE_BRACKET_CLOSE) {
+ in.ReadIdentifier(prop_name);
+ in.Skip(Token::EQUALS);
+ if (prop_name == "root") {
+ model.RootPart().Read(in, tex_index, shapes);
+ } else {
+ while (in.HasMore() && in.Peek().type != Token::SEMICOLON) {
+ in.Next();
+ }
+ }
+ in.Skip(Token::SEMICOLON);
+ }
+ model.Enumerate();
+ in.Skip(Token::ANGLE_BRACKET_CLOSE);
+ in.Skip(Token::SEMICOLON);
+ }
+}
+
void AssetLoader::LoadShapes(const string &set_name, ShapeRegistry &shapes) const {
string full = data + set_name + ".shapes";
std::ifstream file(full);
#include "../app/IntervalTimer.hpp"
#include "../graphics/SkyBox.hpp"
#include "../io/WorldSave.hpp"
+#include "../model/ModelRegistry.hpp"
#include "../model/ShapeRegistry.hpp"
-#include "../model/Skeletons.hpp"
#include "../net/Packet.hpp"
#include "../ui/HUD.hpp"
#include "../ui/InteractiveManipulator.hpp"
World &GetWorld() noexcept { return world; }
Player &GetPlayer() noexcept { return player; }
ChunkReceiver &GetChunkReceiver() noexcept { return chunk_receiver; }
- Skeletons &GetSkeletons() noexcept { return skeletons; }
+ ModelRegistry &GetModels() noexcept { return models; }
void OnEnter() override;
MasterState &master;
ShapeRegistry shapes;
BlockTypeRegistry block_types;
+ ModelRegistry models;
WorldSave save;
World world;
Player &player;
Interface interface;
ChunkReceiver chunk_receiver;
ChunkRenderer chunk_renderer;
- Skeletons skeletons;
IntervalTimer loop_timer;
SkyBox sky;
- std::vector<float> tex_map;
-
struct UpdateStatus {
std::uint16_t last_packet;
int last_update;
: master(master)
, shapes()
, block_types()
+, models()
, save(master.GetEnv().config.GetWorldPath(master.GetWorldConf().name, master.GetConfig().net.host))
, world(block_types, master.GetWorldConf())
, player(*world.AddPlayer(master.GetConfig().player.name))
, interface(master.GetConfig(), master.GetEnv().keymap, input, *this)
, chunk_receiver(world.Chunks(), save)
, chunk_renderer(player.GetChunks())
-, skeletons()
, loop_timer(16)
, sky(master.GetEnv().loader.LoadCubeMap("skybox"))
-, tex_map()
, update_status() {
if (!save.Exists()) {
save.Write(master.GetWorldConf());
TextureIndex tex_index;
master.GetEnv().loader.LoadShapes("default", shapes);
master.GetEnv().loader.LoadBlockTypes("default", block_types, tex_index, shapes);
- skeletons.Load(shapes);
- tex_map.push_back(tex_index.GetID("rock-1"));
- tex_map.push_back(tex_index.GetID("rock-face"));
+ master.GetEnv().loader.LoadModels("default", models, tex_index, shapes);
interface.SetInventorySlots(block_types.size() - 1);
chunk_renderer.LoadTextures(master.GetEnv().loader, tex_index);
chunk_renderer.FogDensity(master.GetWorldConf().fog_density);
pack.ReadEntity(entity);
uint32_t skel_id;
pack.ReadSkeletonID(skel_id);
- Model *skel = skeletons.ByID(skel_id);
- if (skel) {
- skel->Instantiate(entity.GetModel());
- entity.GetModel().SetTextures(tex_map);
+ if (skel_id > 0 && skel_id <= models.size()) {
+ Model &skel = models.Get(skel_id);
+ skel.Instantiate(entity.GetModel());
}
cout << "spawned entity #" << entity_id << " (" << entity.Name()
<< ") at " << entity.AbsolutePosition() << endl;
#include "Part.hpp"
-#include <memory>
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
namespace blank {
class DirectionalLighting;
-class EntityMesh;
class Model;
class Part;
Instance();
~Instance();
- Instance(const Instance &);
- Instance &operator =(const Instance &);
-
operator bool() const noexcept { return model; }
const Model &GetModel() const noexcept { return *model; }
void Render(const glm::mat4 &, DirectionalLighting &);
- void SetTextures(const std::vector<float> &t);
- void SetHSLModifier(const glm::vec3 &m);
- void SetRGBModifier(const glm::vec3 &m);
-
private:
const Model *model;
std::vector<Part::State> state;
- std::vector<std::unique_ptr<EntityMesh>> mesh;
-
- std::vector<float> tex_map;
- glm::vec3 hsl_mod;
- glm::vec3 rgb_mod;
};
--- /dev/null
+#ifndef BLANK_MODEL_MODELREGISTRY_HPP_
+#define BLANK_MODEL_MODELREGISTRY_HPP_
+
+#include "Model.hpp"
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+
+namespace blank {
+
+class ModelRegistry {
+
+public:
+ using size_type = std::size_t;
+ using reference = Model &;
+ using const_reference = const Model &;
+
+public:
+ ModelRegistry();
+
+ reference Add(const std::string &);
+
+ size_type size() const noexcept { return models.size(); }
+
+ // by offset
+ reference operator[](size_type i) noexcept { return *models[i]; }
+ const_reference operator[](size_type i) const noexcept { return *models[i]; }
+ // by ID
+ reference Get(std::uint16_t i) { return *models[i - 1]; }
+ const_reference Get(std::uint16_t i) const { return *models[i - 1]; }
+ // by name
+ reference Get(const std::string &);
+ const_reference Get(const std::string &) const;
+
+private:
+ std::vector<std::unique_ptr<Model>> models;
+ std::map<std::string, Model *> name_index;
+
+};
+
+}
+
+#endif
#include <cstdint>
#include <list>
+#include <memory>
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
namespace blank {
class DirectionalLighting;
+class EntityMesh;
class Instance;
class Model;
class Shape;
+class ShapeRegistry;
+class TextureIndex;
+class TokenStreamReader;
struct Part {
- std::uint16_t id;
- AABB bounds;
+public:
struct State {
glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f);
glm::quat orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
- } initial;
- const Shape *shape;
+ };
Part();
~Part();
+ void Read(TokenStreamReader &, TextureIndex &, const ShapeRegistry &);
+
Part &AddChild();
const std::list<Part> &Children() const noexcept { return children; }
glm::mat4 LocalTransform(const Instance &) const noexcept;
glm::mat4 GlobalTransform(const Instance &) const noexcept;
- void LoadMeshes(Instance &) const;
void Render(
const glm::mat4 &,
const Instance &,
private:
const Part *parent;
+ const Shape *shape;
std::list<Part> children;
+ std::vector<float> tex_map;
+ mutable std::unique_ptr<EntityMesh> mesh;
+ State initial;
+ glm::vec3 hsl_mod;
+ glm::vec3 rgb_mod;
+ std::uint16_t id;
};
+++ /dev/null
-#ifndef BLANK_MODEL_SKELETONS_HPP_
-#define BLANK_MODEL_SKELETONS_HPP_
-
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-
-namespace blank {
-
-class Model;
-class ShapeRegistry;
-
-class Skeletons {
-
-public:
- using size_type = std::size_t;
- using reference = Model &;
- using const_reference = const Model &;
-
-public:
- Skeletons();
- ~Skeletons();
-
- void Load(const ShapeRegistry &);
-
- size_type size() const noexcept { return skeletons.size(); }
-
- reference operator[](size_type i) noexcept { return *skeletons[i]; }
- const_reference operator[](size_type i) const noexcept { return *skeletons[i]; }
-
- Model *ByID(std::uint16_t) noexcept;
- const Model *ByID(std::uint16_t) const noexcept;
-
-private:
- std::vector<std::unique_ptr<Model>> skeletons;
-
-};
-
-}
-
-#endif
#include "Model.hpp"
+#include "ModelRegistry.hpp"
#include "Instance.hpp"
-#include "Skeletons.hpp"
+#include "Part.hpp"
#include "Shape.hpp"
#include "ShapeRegistry.hpp"
#include "../app/TextureIndex.hpp"
+#include "../io/TokenStreamReader.hpp"
#include "../graphics/DirectionalLighting.hpp"
#include "../graphics/EntityMesh.hpp"
Instance::Instance()
: model(nullptr)
-, state()
-, mesh()
-, tex_map()
-, hsl_mod(0.0f, 1.0f, 1.0f)
-, rgb_mod(1.0f) {
+, state() {
}
}
-Instance::Instance(const Instance &other)
-: model(other.model)
-, state(other.state)
-, mesh()
-, tex_map(other.tex_map)
-, hsl_mod(other.hsl_mod)
-, rgb_mod(other.rgb_mod) {
-
-}
-
-Instance &Instance::operator =(const Instance &other) {
- model = other.model;
- state = other.state;
- mesh.clear();
- tex_map = other.tex_map;
- hsl_mod = other.hsl_mod;
- rgb_mod = other.rgb_mod;
- return *this;
-}
-
void Instance::Render(const glm::mat4 &M, DirectionalLighting &prog) {
- if (mesh.empty()) {
- std::cout << "building meshes for instance" << std::endl;
- mesh.resize(state.size());
- model->RootPart().LoadMeshes(*this);
- }
model->RootPart().Render(M, *this, prog);
}
-void Instance::SetTextures(const std::vector<float> &t) {
- tex_map = t;
- mesh.clear();
-}
-
-void Instance::SetHSLModifier(const glm::vec3 &m) {
- hsl_mod = m;
- mesh.clear();
-}
-
-void Instance::SetRGBModifier(const glm::vec3 &m) {
- rgb_mod = m;
- mesh.clear();
-}
-
Model::Model()
: id(0)
void Model::Instantiate(Instance &inst) const {
inst.model = this;
inst.state.clear();
- inst.mesh.clear();
inst.state.resize(part.size());
}
+ModelRegistry::ModelRegistry()
+: models()
+, name_index() {
+
+}
+
+Model &ModelRegistry::Add(const std::string &name) {
+ models.emplace_back(new Model());
+ models.back()->ID(models.size());
+ name_index[name] = &*models.back();
+ return *models.back();
+}
+
+Model &ModelRegistry::Get(const std::string &name) {
+ auto entry = name_index.find(name);
+ if (entry != name_index.end()) {
+ return *entry->second;
+ } else {
+ throw std::runtime_error("unknown model " + name);
+ }
+}
+
+const Model &ModelRegistry::Get(const std::string &name) const {
+ auto entry = name_index.find(name);
+ if (entry != name_index.end()) {
+ return *entry->second;
+ } else {
+ throw std::runtime_error("unknown model " + name);
+ }
+}
+
+
Part::Part()
-: id(0)
-, bounds{ glm::vec3(0.0f), glm::vec3(0.0f) }
-, initial()
+: parent(nullptr)
, shape(nullptr)
-, parent(nullptr)
-, children() {
+, children()
+, tex_map()
+, mesh()
+, initial()
+, hsl_mod(0.0f, 1.0f, 1.0f)
+, rgb_mod(1.0f, 1.0f, 1.0f)
+, id(0) {
}
}
+void Part::Read(TokenStreamReader &in, TextureIndex &tex_index, const ShapeRegistry &shapes) {
+ std::string name;
+ std::string shape_name;
+ std::string tex_name;
+ in.Skip(Token::ANGLE_BRACKET_OPEN);
+ while (in.HasMore() && in.Peek().type != Token::ANGLE_BRACKET_CLOSE) {
+ in.ReadIdentifier(name);
+ in.Skip(Token::EQUALS);
+ if (name == "shape") {
+ in.ReadIdentifier(shape_name);
+ shape = &shapes.Get(shape_name);
+ } else if (name == "position") {
+ in.ReadVec(initial.position);
+ } else if (name == "orientation") {
+ in.ReadQuat(initial.orientation);
+ } else if (name == "hsl_mod") {
+ in.ReadVec(hsl_mod);
+ } else if (name == "rgb_mod") {
+ in.ReadVec(rgb_mod);
+ } else if (name == "textures") {
+ in.Skip(Token::BRACKET_OPEN);
+ while (in.HasMore() && in.Peek().type != Token::BRACKET_CLOSE) {
+ in.ReadString(tex_name);
+ tex_map.push_back(tex_index.GetID(tex_name));
+ if (in.Peek().type == Token::COMMA) {
+ in.Skip(Token::COMMA);
+ }
+ }
+ in.Skip(Token::BRACKET_CLOSE);
+ } else if (name == "children") {
+ in.Skip(Token::BRACKET_OPEN);
+ while (in.HasMore() && in.Peek().type != Token::BRACKET_CLOSE) {
+ Part &child = AddChild();
+ child.Read(in, tex_index, shapes);
+ if (in.Peek().type == Token::COMMA) {
+ in.Skip(Token::COMMA);
+ }
+ }
+ in.Skip(Token::BRACKET_CLOSE);
+ } else {
+ while (in.HasMore() && in.Peek().type != Token::SEMICOLON) {
+ in.Next();
+ }
+ }
+ in.Skip(Token::SEMICOLON);
+ }
+ in.Skip(Token::ANGLE_BRACKET_CLOSE);
+}
+
Part &Part::AddChild() {
children.emplace_back();
children.back().parent = this;
}
-void Part::LoadMeshes(Instance &inst) const {
- if (shape && shape->IndexCount() > 0) {
- buf.Clear();
- buf.hsl_mods.resize(shape->VertexCount(), inst.hsl_mod);
- buf.rgb_mods.resize(shape->VertexCount(), inst.rgb_mod);
- shape->Fill(buf, inst.tex_map);
- inst.mesh[id].reset(new EntityMesh());
- inst.mesh[id]->Update(buf);
- } else {
- inst.mesh[id].reset();
- }
- for (const Part &part : children) {
- part.LoadMeshes(inst);
- }
-}
-
void Part::Render(
const glm::mat4 &M,
const Instance &inst,
DirectionalLighting &prog
) const {
glm::mat4 transform = M * LocalTransform(inst);
- if (inst.mesh[id]) {
+ if (shape && shape->IndexCount() > 0) {
+ if (!mesh) {
+ buf.Clear();
+ buf.hsl_mods.resize(shape->VertexCount(), hsl_mod);
+ buf.rgb_mods.resize(shape->VertexCount(), rgb_mod);
+ shape->Fill(buf, tex_map);
+ mesh.reset(new EntityMesh());
+ mesh->Update(buf);
+ }
prog.SetM(transform);
- inst.mesh[id]->Draw();
+ mesh->Draw();
}
for (const Part &part : children) {
part.Render(transform, inst, prog);
}
}
-
-Skeletons::Skeletons()
-: skeletons() {
-
-}
-
-Skeletons::~Skeletons() {
-
-}
-
-void Skeletons::Load(const ShapeRegistry &shapes) {
- skeletons.clear();
- skeletons.reserve(4);
- AABB bounds{{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }};
- const Shape *shape = &shapes.Get("player_head_block");
- {
- skeletons.emplace_back(new Model);
- skeletons[0]->ID(1);
- skeletons[0]->RootPart().bounds = bounds;
- skeletons[0]->RootPart().shape = shape;
- skeletons[0]->Enumerate();
- }
- {
- skeletons.emplace_back(new Model);
- skeletons[1]->ID(2);
- skeletons[1]->RootPart().bounds = bounds;
- skeletons[1]->RootPart().shape = shape;
- skeletons[1]->Enumerate();
- }
- {
- skeletons.emplace_back(new Model);
- skeletons[2]->ID(3);
- skeletons[2]->RootPart().bounds = bounds;
- skeletons[2]->RootPart().shape = shape;
- skeletons[2]->Enumerate();
- }
- {
- skeletons.emplace_back(new Model);
- skeletons[3]->ID(4);
- skeletons[3]->RootPart().bounds = bounds;
- skeletons[3]->RootPart().shape = shape;
- skeletons[3]->Enumerate();
- }
-}
-
-Model *Skeletons::ByID(std::uint16_t id) noexcept {
- if (id == 0 || id > skeletons.size()) {
- return nullptr;
- } else {
- return skeletons[id - 1].get();
- }
-}
-
-const Model *Skeletons::ByID(std::uint16_t id) const noexcept {
- if (id == 0 || id > skeletons.size()) {
- return nullptr;
- } else {
- return skeletons[id - 1].get();
- }
-}
-
}
} else {
// try to skip, might fail though
- while (in.Peek().type != Token::SEMICOLON) {
+ while (in.HasMore() && in.Peek().type != Token::SEMICOLON) {
in.Next();
}
}
: env(env)
, shapes()
, block_types()
+, models()
, world(block_types, wc)
, generator(gc)
, chunk_loader(world.Chunks(), generator, ws)
-, skeletons()
-, spawner(world, skeletons, env.rng)
+, spawner(world, models, env.rng)
, server(config.net, world, wc, ws)
, loop_timer(16) {
TextureIndex tex_index;
env.loader.LoadShapes("default", shapes);
env.loader.LoadBlockTypes("default", block_types, tex_index, shapes);
+ env.loader.LoadModels("default", models, tex_index, shapes);
+ if (models.size() < 2) {
+ throw std::runtime_error("need at least two models to run");
+ }
generator.LoadTypes(block_types);
- skeletons.Load(shapes);
- spawner.LimitSkeletons(1, skeletons.size());
- spawner.LoadTextures(tex_index);
- server.SetPlayerModel(skeletons[0]);
+ spawner.LimitModels(1, models.size());
+ server.SetPlayerModel(models[0]);
loop_timer.Start();
#include "../ai/Spawner.hpp"
#include "../app/IntervalTimer.hpp"
#include "../app/State.hpp"
+#include "../model/ModelRegistry.hpp"
#include "../model/ShapeRegistry.hpp"
-#include "../model/Skeletons.hpp"
#include "../world/BlockTypeRegistry.hpp"
#include "../world/ChunkLoader.hpp"
#include "../world/Generator.hpp"
HeadlessEnvironment &env;
ShapeRegistry shapes;
BlockTypeRegistry block_types;
+ ModelRegistry models;
World world;
Generator generator;
ChunkLoader chunk_loader;
- Skeletons skeletons;
Spawner spawner;
Server server;
IntervalTimer loop_timer;
, env(env)
, shapes()
, block_types()
+, models()
, save(save)
, world(block_types, wc)
, spawn_index(world.Chunks().MakeIndex(wc.spawn, 3))
, generator(gc)
, chunk_loader(world.Chunks(), generator, save)
, chunk_renderer(player.GetChunks())
-, skeletons()
-, spawner(world, skeletons, env.rng)
+, spawner(world, models, env.rng)
, sky(env.loader.LoadCubeMap("skybox"))
, preload(env, chunk_loader, chunk_renderer)
, unload(env, world.Chunks(), save) {
TextureIndex tex_index;
env.loader.LoadShapes("default", shapes);
env.loader.LoadBlockTypes("default", block_types, tex_index, shapes);
- skeletons.Load(shapes);
- spawner.LimitSkeletons(0, skeletons.size());
- spawner.LoadTextures(tex_index);
+ env.loader.LoadModels("default", models, tex_index, shapes);
+ if (models.size() < 2) {
+ throw std::runtime_error("need at least two models to run");
+ }
+ spawner.LimitModels(0, models.size());
interface.SetInventorySlots(block_types.size() - 1);
generator.LoadTypes(block_types);
chunk_renderer.LoadTextures(env.loader, tex_index);
#include "UnloadState.hpp"
#include "../ai/Spawner.hpp"
#include "../graphics/SkyBox.hpp"
+#include "../model/ModelRegistry.hpp"
#include "../model/ShapeRegistry.hpp"
-#include "../model/Skeletons.hpp"
#include "../ui/DirectInput.hpp"
#include "../ui/HUD.hpp"
#include "../ui/InteractiveManipulator.hpp"
Environment &env;
ShapeRegistry shapes;
BlockTypeRegistry block_types;
+ ModelRegistry models;
const WorldSave &save;
World world;
ChunkIndex &spawn_index;
Generator generator;
ChunkLoader chunk_loader;
ChunkRenderer chunk_renderer;
- Skeletons skeletons;
Spawner spawner;
SkyBox sky;