From: Daniel Karbach Date: Wed, 25 Nov 2015 15:59:19 +0000 (+0100) Subject: block type prototypability and new types X-Git-Url: http://git.localhorst.tv/?a=commitdiff_plain;ds=inline;h=b94a7dc7daad9ae9be90a39d723e332dae375325;p=blank.git block type prototypability and new types this will mess up your world saves and by "your" I mean "my" --- diff --git a/assets b/assets index 8fed550..38f6d1d 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 8fed55072b5b2d5baa06e2ab045df3161f86fdb2 +Subproject commit 38f6d1d15a6d1469a080d77e9fcdafe5c545abf0 diff --git a/doc/todo b/doc/todo index 9df0ec4..2de96bd 100644 --- a/doc/todo +++ b/doc/todo @@ -103,6 +103,8 @@ world generator that is not boring exploration biomes seem too small, maybe that will become easier to tune when there's a little more diversity between them + chunk generation takes too long, it's incredibly annoying + should look into speeding it up and executing on a different thread spawning diff --git a/src/app/app.cpp b/src/app/app.cpp index 4cc742f..6c89bdb 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -321,11 +321,16 @@ void AssetLoader::LoadBlockTypes( throw std::runtime_error("failed to open block type file " + full); } TokenStreamReader in(file); - string name; + string proto; while (in.HasMore()) { - in.ReadIdentifier(name); - in.Skip(Token::EQUALS); BlockType type; + in.ReadIdentifier(type.name); + in.Skip(Token::EQUALS); + if (in.Peek().type == Token::IDENTIFIER) { + // prototype + in.ReadIdentifier(proto); + type.Copy(reg.Get(proto)); + } type.Read(in, snd_index, tex_index, shapes); in.Skip(Token::SEMICOLON); reg.Add(std::move(type)); diff --git a/src/world/BlockType.hpp b/src/world/BlockType.hpp index a63507a..ef328d4 100644 --- a/src/world/BlockType.hpp +++ b/src/world/BlockType.hpp @@ -31,6 +31,9 @@ struct BlockType { /// gravity configuration or null if not emitting gravity std::unique_ptr gravity; + /// a string identifying in contexts where numbers just won't do + /// must be unique within any given set + std::string name; /// a string to display to the user std::string label; @@ -74,6 +77,10 @@ struct BlockType { BlockType() noexcept; + /// clone values of given type + /// this copies everything except for ID, name, label, and gravity + void Copy(const BlockType &) noexcept; + void Read( TokenStreamReader &in, ResourceIndex &snd_index, diff --git a/src/world/BlockTypeRegistry.hpp b/src/world/BlockTypeRegistry.hpp index 6612d15..23b183a 100644 --- a/src/world/BlockTypeRegistry.hpp +++ b/src/world/BlockTypeRegistry.hpp @@ -3,6 +3,8 @@ #include "BlockType.hpp" +#include +#include #include @@ -20,6 +22,8 @@ public: public: BlockTypeRegistry(); + /// register a new block type + /// this may throw if the name is already taken (names must be unique) Block::Type Add(BlockType &&); size_t size() const noexcept { return types.size(); } @@ -29,14 +33,20 @@ public: iterator end() noexcept { return types.end(); } const_iterator end() const noexcept { return types.end(); } - BlockType &operator [](Block::Type id) { return types[id]; } - const BlockType &operator [](Block::Type id) const { return types[id]; } + /// lookup by ID + BlockType &operator [](Block::Type id) noexcept { return types[id]; } + const BlockType &operator [](Block::Type id) const noexcept { return types[id]; } - BlockType &Get(Block::Type id) { return types[id]; } - const BlockType &Get(Block::Type id) const { return types[id]; } + BlockType &Get(Block::Type id) noexcept { return types[id]; } + const BlockType &Get(Block::Type id) const noexcept { return types[id]; } + + /// lookup by name + BlockType &Get(const std::string &name); + const BlockType &Get(const std::string &name) const; private: std::vector types; + std::map names; }; diff --git a/src/world/Generator.cpp b/src/world/Generator.cpp index 466139b..edb7e9c 100644 --- a/src/world/Generator.cpp +++ b/src/world/Generator.cpp @@ -91,6 +91,8 @@ Block Generator::Generate(const glm::vec3 &pos) const noexcept { return Block(0); } float random = GetValue(random_noise, pos, config.randomness); + // as weird as it sounds, but this is faster tham glm::fract and generates a + // better distribution than (transformed variants of) erf, erfc, atan, and smoothstep if (random < 0.0f) random += 1.0f; float value = random * total; // TODO: change to binary search diff --git a/src/world/block.cpp b/src/world/block.cpp index 61e2ab4..9372918 100644 --- a/src/world/block.cpp +++ b/src/world/block.cpp @@ -8,6 +8,7 @@ #include "../shared/ResourceIndex.hpp" #include +#include #include #include #include @@ -77,6 +78,7 @@ BlockType::BlockType() noexcept , rgb_mod(1.0f, 1.0f, 1.0f) , outline_color(-1, -1, -1) , gravity() +, name("anonymous") , label("some block") , place_sound(-1) , remove_sound(-1) @@ -103,6 +105,35 @@ BlockType::BlockType() noexcept } +void BlockType::Copy(const BlockType &other) noexcept { + shape = other.shape; + textures = other.textures; + hsl_mod = other.hsl_mod; + rgb_mod = other.rgb_mod; + outline_color = other.outline_color; + place_sound = other.place_sound; + remove_sound = other.remove_sound; + luminosity = other.luminosity; + visible = other.visible; + block_light = other.block_light; + collision = other.collision; + collide_block = collide_block; + generate = other.generate; + min_solidity = other.min_solidity; + mid_solidity = other.mid_solidity; + max_solidity = other.max_solidity; + min_humidity = other.min_humidity; + mid_humidity = other.mid_humidity; + max_humidity = other.max_humidity; + min_temperature = other.min_temperature; + mid_temperature = other.mid_temperature; + max_temperature = other.max_temperature; + min_richness = other.min_richness; + mid_richness = other.mid_richness; + max_richness = other.max_richness; + commonness = other.commonness; +} + void BlockType::Read( TokenStreamReader &in, ResourceIndex &snd_index, @@ -225,6 +256,8 @@ void BlockType::OutlinePrimitiveMesh(PrimitiveMesh::Buffer &buf) const noexcept BlockTypeRegistry::BlockTypeRegistry() { BlockType air; + air.name = "air"; + air.label = "Air"; air.visible = false; air.block_light = false; air.collision = false; @@ -234,11 +267,32 @@ BlockTypeRegistry::BlockTypeRegistry() { Block::Type BlockTypeRegistry::Add(BlockType &&t) { int id = types.size(); + if (!names.emplace(t.name, id).second) { + throw std::runtime_error("duplicate block type name " + t.name); + } types.push_back(std::move(t)); types.back().id = id; return id; } +BlockType &BlockTypeRegistry::Get(const std::string &name) { + auto entry = names.find(name); + if (entry != names.end()) { + return Get(entry->second); + } else { + throw std::runtime_error("unknown block type " + name); + } +} + +const BlockType &BlockTypeRegistry::Get(const std::string &name) const { + auto entry = names.find(name); + if (entry != names.end()) { + return Get(entry->second); + } else { + throw std::runtime_error("unknown block type " + name); + } +} + namespace { diff --git a/tst/world/ChunkTest.cpp b/tst/world/ChunkTest.cpp index e2c02fd..26f2014 100644 --- a/tst/world/ChunkTest.cpp +++ b/tst/world/ChunkTest.cpp @@ -17,11 +17,13 @@ void ChunkTest::setUp() { types = BlockTypeRegistry(); BlockType obstacle; + obstacle.name = "obstacle"; obstacle.visible = true; obstacle.block_light = true; types.Add(std::move(obstacle)); BlockType source; + source.name = "source"; source.visible = true; source.luminosity = 5; source.block_light = true;