diff --git a/include/Cubed/gameplay/chunk_generator.hpp b/include/Cubed/gameplay/chunk_generator.hpp index 27faca9..a61f4f6 100644 --- a/include/Cubed/gameplay/chunk_generator.hpp +++ b/include/Cubed/gameplay/chunk_generator.hpp @@ -50,6 +50,8 @@ public: void generate_cave(); void generate_river(); + void spawn_creature(); + private: static inline std::atomic is_init{false}; static inline unsigned m_generator_seed{0}; diff --git a/include/Cubed/gameplay/creatures/spawn.hpp b/include/Cubed/gameplay/creatures/spawn.hpp new file mode 100644 index 0000000..e591dcf --- /dev/null +++ b/include/Cubed/gameplay/creatures/spawn.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "Cubed/gameplay/biome.hpp" + +#include +#include +#include +namespace Cubed { +struct SpawnConfig { + std::string_view name; // factory key, e.g. "cubed:pig" + std::span biomes; // allowed biomes + float probability = 0.0f; // per chunk spawn probability + unsigned max_spawn_count = 0; // per chunk_max_spawn_sum +}; + +namespace SpawnDefaults { +constexpr std::array PIG_BIOMES{BiomeType::PLAIN, + BiomeType::FOREST}; +constexpr SpawnConfig PIG{"cubed:pig", PIG_BIOMES, 0.02f, 3}; +} // namespace SpawnDefaults +} // namespace Cubed diff --git a/include/Cubed/gameplay/server_entity_manager.hpp b/include/Cubed/gameplay/server_entity_manager.hpp index 38dddad..15010ba 100644 --- a/include/Cubed/gameplay/server_entity_manager.hpp +++ b/include/Cubed/gameplay/server_entity_manager.hpp @@ -15,7 +15,7 @@ public: void init(); void update(); // not thread safe - void add_entity(std::string_view name, const glm::vec3& pos); + void add_entity(std::string_view name, const glm::vec3& world_pos); void destory(EntityID id); void handle_player_login(std::shared_ptr session); diff --git a/include/Cubed/gameplay/server_world.hpp b/include/Cubed/gameplay/server_world.hpp index 6b46be4..b82dfe1 100644 --- a/include/Cubed/gameplay/server_world.hpp +++ b/include/Cubed/gameplay/server_world.hpp @@ -95,6 +95,7 @@ public: std::vector> get_all_session() const; uint32_t get_chunk_ref_count(const glm::vec3& pos) const; + ServerEntityManager& entity_manager(); int get_block(const glm::ivec3& block_pos) const override; bool is_solid(const glm::ivec3& block_pos) const override; diff --git a/src/gameplay/chunk_generator.cpp b/src/gameplay/chunk_generator.cpp index bc80670..b10bdf1 100644 --- a/src/gameplay/chunk_generator.cpp +++ b/src/gameplay/chunk_generator.cpp @@ -9,6 +9,7 @@ #include "Cubed/gameplay/builders/river_builder.hpp" #include "Cubed/gameplay/builders/snowy_plain_builder.hpp" #include "Cubed/gameplay/cave_path.hpp" +#include "Cubed/gameplay/creatures/spawn.hpp" #include "Cubed/gameplay/river.path.hpp" #include "Cubed/gameplay/server_chunk.hpp" #include "Cubed/gameplay/server_world.hpp" @@ -17,6 +18,8 @@ #include "Cubed/tools/cubed_hash.hpp" #include "Cubed/tools/math_tools.hpp" #include "Cubed/tools/perlin_noise.hpp" + +#include namespace Cubed { namespace { @@ -805,6 +808,35 @@ void ChunkGenerator::generate_river() { } } +void ChunkGenerator::spawn_creature() { + auto biome = m_chunk.biome(); + const auto& blocks = m_chunk.blocks(); + const auto& heightmap = m_chunk.heightmap(); + const auto& chunk_pos = m_chunk.chunk_pos(); + if (std::ranges::contains(SpawnDefaults::PIG.biomes, biome)) { + + if (m_random.random_bool(SpawnDefaults::PIG.probability)) { + int want = + m_random.random_int(0, SpawnDefaults::PIG.max_spawn_count); + for (int i = 0; i < want; ++i) { + int x = m_random.random_int(0, CHUNK_SIZE - 1); + int z = m_random.random_int(0, CHUNK_SIZE - 1); + int y = static_cast(heightmap[x][z]); + glm::vec3 pos(x, y + 1, z); + auto type = blocks[Chunk::index(pos)]; + if (type != 0) { + continue; + } + auto [world_x, world_y, world_z] = Chunk::block_to_world( + x, y + 1, z, chunk_pos.x, chunk_pos.z); + m_chunk.world().entity_manager().add_entity( + SpawnDefaults::PIG.name, + glm::vec3{world_x, world_y, world_z}); + } + } + } +} + ServerChunk& ChunkGenerator::chunk() { return m_chunk; } Random& ChunkGenerator::random() { return m_random; } diff --git a/src/gameplay/server_chunk.cpp b/src/gameplay/server_chunk.cpp index ee7f711..1d65371 100644 --- a/src/gameplay/server_chunk.cpp +++ b/src/gameplay/server_chunk.cpp @@ -141,6 +141,7 @@ void ServerChunk::gen_phase_five() { m_generator->generate_cave(); m_generator->generate_vegetation(); + m_generator->spawn_creature(); m_generator = nullptr; } diff --git a/src/gameplay/server_entity_manager.cpp b/src/gameplay/server_entity_manager.cpp index 7837ff4..9b3fcc9 100644 --- a/src/gameplay/server_entity_manager.cpp +++ b/src/gameplay/server_entity_manager.cpp @@ -37,6 +37,8 @@ void ServerEntityManager::update() { for (auto e : view) { const auto& c = view.get(e); if (!m_world.get_chunk_ref_count(c.transform.position.value)) { + const auto& entity = m_registry.get(e); + destory(entity.id); continue; } update_ai(e); @@ -102,9 +104,9 @@ void ServerEntityManager::handle_task() { } void ServerEntityManager::add_entity(std::string_view name, - const glm::vec3& pos) { + const glm::vec3& world_pos) { m_tasks.emplace(Command::CREATE, - EntityCreateElement{std::string(name), pos}); + EntityCreateElement{std::string(name), world_pos}); } void ServerEntityManager::destory(EntityID id) { diff --git a/src/gameplay/server_world.cpp b/src/gameplay/server_world.cpp index f53b847..f359603 100644 --- a/src/gameplay/server_world.cpp +++ b/src/gameplay/server_world.cpp @@ -1114,5 +1114,5 @@ BlockType ServerWorld::get_block_tpye(const glm::ivec3& block_pos) const { } int ServerWorld::get_per_tick_time() const { return m_per_tick_time; } - +ServerEntityManager& ServerWorld::entity_manager() { return m_entity_manager; } } // namespace Cubed \ No newline at end of file