From: Daniel Karbach Date: Thu, 15 Oct 2015 12:02:36 +0000 (+0200) Subject: load models from assets X-Git-Url: http://git.localhorst.tv/?a=commitdiff_plain;h=7e782291e0ce39eb2d4e8c1df28f682c313e6f8d;p=blank.git load models from assets --- diff --git a/assets b/assets index 82ab376..2e992fd 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 82ab37629683a73061240c2d7da64f0a612fde42 +Subproject commit 2e992fd6861d4c45c5938bd519600aeb8b8be386 diff --git a/src/ai/Spawner.cpp b/src/ai/Spawner.cpp index 064857c..a4b4030 100644 --- a/src/ai/Spawner.cpp +++ b/src/ai/Spawner.cpp @@ -2,9 +2,8 @@ #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" @@ -19,9 +18,9 @@ using namespace std; 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) @@ -29,9 +28,8 @@ Spawner::Spawner(World &world, Skeletons &skeletons, GaloisLFSR &rand) , 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(); } @@ -42,21 +40,15 @@ Spawner::~Spawner() { } -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); @@ -99,7 +91,7 @@ void Spawner::CheckDespawn() noexcept { } 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(); @@ -142,8 +134,7 @@ void Spawner::Spawn(Entity &reference, const glm::ivec3 &chunk, const glm::vec3 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()) { @@ -156,9 +147,9 @@ void Spawner::Spawn(Entity &reference, const glm::ivec3 &chunk, const glm::vec3 controllers.emplace_back(ctrl); } -Model &Spawner::RandomSkeleton() noexcept { - std::size_t offset = (random.Next() % skeletons_length) + skeletons_offset; - return skeletons[offset]; +Model &Spawner::RandomModel() noexcept { + std::size_t offset = (random.Next() % model_length) + model_offset; + return models[offset]; } } diff --git a/src/ai/Spawner.hpp b/src/ai/Spawner.hpp index 6591ef9..be2ff31 100644 --- a/src/ai/Spawner.hpp +++ b/src/ai/Spawner.hpp @@ -13,18 +13,16 @@ class Controller; 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); @@ -33,11 +31,11 @@ private: 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 controllers; GaloisLFSR &random; @@ -48,10 +46,8 @@ private: unsigned int max_entities; int chunk_range; - std::size_t skeletons_offset; - std::size_t skeletons_length; - - std::vector tex_map; + std::size_t model_offset; + std::size_t model_length; }; diff --git a/src/app/Assets.hpp b/src/app/Assets.hpp index 941fa1b..64bc72c 100644 --- a/src/app/Assets.hpp +++ b/src/app/Assets.hpp @@ -11,6 +11,7 @@ namespace blank { class ArrayTexture; class BlockTypeRegistry; class CubeMap; +class ModelRegistry; class ShapeRegistry; class Sound; class Texture; @@ -28,6 +29,11 @@ public: 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; diff --git a/src/app/app.cpp b/src/app/app.cpp index 367f3c2..7f5f02f 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -14,6 +14,8 @@ #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" @@ -494,6 +496,43 @@ Font AssetLoader::LoadFont(const string &name, int size) const { 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); diff --git a/src/client/InteractiveState.hpp b/src/client/InteractiveState.hpp index 731ed0a..2bc459a 100644 --- a/src/client/InteractiveState.hpp +++ b/src/client/InteractiveState.hpp @@ -9,8 +9,8 @@ #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" @@ -40,7 +40,7 @@ public: 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; @@ -71,6 +71,7 @@ private: MasterState &master; ShapeRegistry shapes; BlockTypeRegistry block_types; + ModelRegistry models; WorldSave save; World world; Player &player; @@ -80,13 +81,10 @@ private: Interface interface; ChunkReceiver chunk_receiver; ChunkRenderer chunk_renderer; - Skeletons skeletons; IntervalTimer loop_timer; SkyBox sky; - std::vector tex_map; - struct UpdateStatus { std::uint16_t last_packet; int last_update; diff --git a/src/client/client.cpp b/src/client/client.cpp index 2618d98..cc3106f 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -50,6 +50,7 @@ InteractiveState::InteractiveState(MasterState &master, uint32_t player_id) : 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)) @@ -59,10 +60,8 @@ InteractiveState::InteractiveState(MasterState &master, uint32_t player_id) , 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()); @@ -70,9 +69,7 @@ InteractiveState::InteractiveState(MasterState &master, uint32_t player_id) 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); @@ -167,10 +164,9 @@ void InteractiveState::Handle(const Packet::SpawnEntity &pack) { 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; diff --git a/src/model/Instance.hpp b/src/model/Instance.hpp index 60c0212..8b94bcd 100644 --- a/src/model/Instance.hpp +++ b/src/model/Instance.hpp @@ -3,7 +3,6 @@ #include "Part.hpp" -#include #include #include #include @@ -12,7 +11,6 @@ namespace blank { class DirectionalLighting; -class EntityMesh; class Model; class Part; @@ -25,26 +23,14 @@ public: 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 &t); - void SetHSLModifier(const glm::vec3 &m); - void SetRGBModifier(const glm::vec3 &m); - private: const Model *model; std::vector state; - std::vector> mesh; - - std::vector tex_map; - glm::vec3 hsl_mod; - glm::vec3 rgb_mod; }; diff --git a/src/model/ModelRegistry.hpp b/src/model/ModelRegistry.hpp new file mode 100644 index 0000000..b3ab1ee --- /dev/null +++ b/src/model/ModelRegistry.hpp @@ -0,0 +1,47 @@ +#ifndef BLANK_MODEL_MODELREGISTRY_HPP_ +#define BLANK_MODEL_MODELREGISTRY_HPP_ + +#include "Model.hpp" + +#include +#include +#include +#include +#include + + +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> models; + std::map name_index; + +}; + +} + +#endif diff --git a/src/model/Part.hpp b/src/model/Part.hpp index f3d78e2..f71efc5 100644 --- a/src/model/Part.hpp +++ b/src/model/Part.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -13,23 +14,27 @@ 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 &Children() const noexcept { return children; } @@ -39,7 +44,6 @@ struct Part { 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 &, @@ -47,7 +51,14 @@ struct Part { private: const Part *parent; + const Shape *shape; std::list children; + std::vector tex_map; + mutable std::unique_ptr mesh; + State initial; + glm::vec3 hsl_mod; + glm::vec3 rgb_mod; + std::uint16_t id; }; diff --git a/src/model/Skeletons.hpp b/src/model/Skeletons.hpp deleted file mode 100644 index 3c7c886..0000000 --- a/src/model/Skeletons.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef BLANK_MODEL_SKELETONS_HPP_ -#define BLANK_MODEL_SKELETONS_HPP_ - -#include -#include -#include - - -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> skeletons; - -}; - -} - -#endif diff --git a/src/model/model.cpp b/src/model/model.cpp index 730a34a..63187b8 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -1,10 +1,12 @@ #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" @@ -17,11 +19,7 @@ namespace blank { Instance::Instance() : model(nullptr) -, state() -, mesh() -, tex_map() -, hsl_mod(0.0f, 1.0f, 1.0f) -, rgb_mod(1.0f) { +, state() { } @@ -29,50 +27,10 @@ Instance::~Instance() { } -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 &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) @@ -90,18 +48,52 @@ void Model::Enumerate() { 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) { } @@ -109,6 +101,55 @@ Part::~Part() { } +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; @@ -150,96 +191,27 @@ EntityMesh::Buffer buf; } -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(); - } -} - } diff --git a/src/model/shape.cpp b/src/model/shape.cpp index 66eb25e..4943e63 100644 --- a/src/model/shape.cpp +++ b/src/model/shape.cpp @@ -108,7 +108,7 @@ void Shape::Read(TokenStreamReader &in) { } else { // try to skip, might fail though - while (in.Peek().type != Token::SEMICOLON) { + while (in.HasMore() && in.Peek().type != Token::SEMICOLON) { in.Next(); } } diff --git a/src/server/ServerState.cpp b/src/server/ServerState.cpp index 98861bf..3e2869f 100644 --- a/src/server/ServerState.cpp +++ b/src/server/ServerState.cpp @@ -21,21 +21,23 @@ ServerState::ServerState( : 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(); diff --git a/src/server/ServerState.hpp b/src/server/ServerState.hpp index bfefccf..b62cf09 100644 --- a/src/server/ServerState.hpp +++ b/src/server/ServerState.hpp @@ -5,8 +5,8 @@ #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" @@ -42,10 +42,10 @@ private: 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; diff --git a/src/standalone/MasterState.cpp b/src/standalone/MasterState.cpp index 8199414..9d95966 100644 --- a/src/standalone/MasterState.cpp +++ b/src/standalone/MasterState.cpp @@ -23,6 +23,7 @@ MasterState::MasterState( , env(env) , shapes() , block_types() +, models() , save(save) , world(block_types, wc) , spawn_index(world.Chunks().MakeIndex(wc.spawn, 3)) @@ -35,17 +36,18 @@ MasterState::MasterState( , 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); diff --git a/src/standalone/MasterState.hpp b/src/standalone/MasterState.hpp index 680bb5e..f72c38c 100644 --- a/src/standalone/MasterState.hpp +++ b/src/standalone/MasterState.hpp @@ -8,8 +8,8 @@ #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" @@ -65,6 +65,7 @@ private: Environment &env; ShapeRegistry shapes; BlockTypeRegistry block_types; + ModelRegistry models; const WorldSave &save; World world; ChunkIndex &spawn_index; @@ -77,7 +78,6 @@ private: Generator generator; ChunkLoader chunk_loader; ChunkRenderer chunk_renderer; - Skeletons skeletons; Spawner spawner; SkyBox sky;