From: Mikko Rasa Date: Sat, 17 Jun 2023 22:09:30 +0000 (+0300) Subject: Rework Landscape to support replication X-Git-Url: https://git.tdb.fi/?a=commitdiff_plain;h=97da80a0673808158cf7f8c512782a922ed8cd89;p=libs%2Fgame.git Rework Landscape to support replication --- diff --git a/source/game/heightmapterrain.cpp b/source/game/heightmapterrain.cpp index 8e4d1a2..dafa433 100644 --- a/source/game/heightmapterrain.cpp +++ b/source/game/heightmapterrain.cpp @@ -50,4 +50,29 @@ float HeightmapTerrain::get_elevation(const LinAl::Vector &p) const return weighted_elev*setup.elevation_scale; } +void HeightmapTerrain::send_data(vector &out_data) const +{ + out_data.resize(grid_size.x*grid_size.y); + for(unsigned y=0; y &in_data) +{ + for(unsigned y=0; y #include #include "component.h" +#include "messages.h" #include "mspgame_api.h" namespace Msp::Game { @@ -35,6 +36,9 @@ public: unsigned get_material_index(const LinAl::Vector &i) const { return materials[i.x+i.y*grid_size.x]; } const std::string &get_technique_name() const { return setup.technique_name; } unsigned get_generation() const { return generation; } + + void send_data(std::vector &) const; + void receive_data(const std::vector &); }; } // namespace Msp::Game diff --git a/source/game/landscape.cpp b/source/game/landscape.cpp index c9c2814..2f39c6d 100644 --- a/source/game/landscape.cpp +++ b/source/game/landscape.cpp @@ -6,20 +6,30 @@ using namespace std; namespace Msp::Game { -Landscape::Landscape(Stage &s, const HeightmapTerrainSetup &t, float b): +Landscape::Landscape(Stage &s, Replicator *r, const HeightmapTerrainSetup &t, float b): System(s), + replicator(r), + data_call(replicator, [this](const auto &... a){ receive_data(a...); }), subroot(stage.get_root(), Entity::NO_TRANSFORM), - terrain_setup(t), + spawner(stage, replicator, subroot, *this), + block_setup(t), block_size(b) { - float grid_size = block_size/terrain_setup.grid_spacing; + spawner.add_spawnable_type([this](const std::string &) -> const BlockSetup & { return block_setup; }); + + float grid_size = block_size/block_setup.heightmap.grid_spacing; grid_size = max(round(grid_size), 1.0f); - block_size = grid_size*terrain_setup.grid_spacing; + block_size = grid_size*block_setup.heightmap.grid_spacing; + block_setup.block_size = { block_size, block_size }; } -bool Landscape::terrain_index_compare(const Terrain &t, const LinAl::Vector &i) +Landscape::Landscape(Stage &s, const HeightmapTerrainSetup &t, float b): + Landscape(s, nullptr, t, b) +{ } + +bool Landscape::block_index_compare(const Owned &t, const LinAl::Vector &i) { - return t.index.yindex.yindex.y==i.y && t->index.x &bounds) const LinAl::Vector &max_pt = bounds.get_maximum_point(); LinAl::Vector min_index(round(min_pt.x/block_size), round(min_pt.y/block_size)); LinAl::Vector max_index(round(max_pt.x/block_size), round(max_pt.y/block_size)); - LinAl::Vector block_size_vec(block_size, block_size); for(int y=min_index.y; y<=max_index.y; ++y) - { - auto i = lower_bound(terrains, LinAl::Vector(min_index.x, y), terrain_index_compare); - for(int x=min_index.x; x<=max_index.x; ++x) { - if(i==terrains.end() || i->index.x>x) - { - LinAl::Vector index(x ,y); - LinAl::Vector center = LinAl::Vector(index)*block_size; - Owned entity(subroot, compose(center, 0.0f)); - Owned terrain(entity, terrain_setup, block_size_vec); - if(generator) - { - LinAl::Vector base = center-block_size_vec/2.0f; - generator->generate_block(*this, { base, base+block_size_vec }, terrain); - } - i = terrains.emplace(i, index, move(entity), move(terrain)); - } - ++i; + auto i = lower_bound(blocks, LinAl::Vector(x, y), block_index_compare); + if(i==blocks.end() || (*i)->index.y!=y || (*i)->index.x!=x) + spawner.spawn(string(), LinAl::Vector(x*block_size, y*block_size, 0.0f)); } - } } LinAl::Vector Landscape::get_ground_position(const LinAl::Vector &p) const { LinAl::Vector index(round(p.x/block_size), round(p.y/block_size)); - auto i = lower_bound(terrains, index, terrain_index_compare); - if(i==terrains.end() || i->index!=index) + auto i = lower_bound(blocks, index, block_index_compare); + if(i==blocks.end() || (*i)->index!=index) return compose(p.slice<2>(0), 0.0f); - LinAl::Vector center = i->entity->get_transform()->get_position(); - LinAl::Vector corner = center.slice<2>(0) - i->terrain->get_size()/2.0f; + LinAl::Vector center = (*i)->get_transform()->get_position(); + LinAl::Vector corner = center.slice<2>(0) - (*i)->terrain->get_size()/2.0f; LinAl::Vector p_xy = p.slice<2>(0); - float z = i->terrain->get_elevation(p_xy-corner); + float z = (*i)->terrain->get_elevation(p_xy-corner); return center+compose(p_xy, z); } +void Landscape::spawned(Owned entity) +{ + if(Owned block = dynamic_owned_cast(move(entity))) + { + LinAl::Vector center = block->get_transform()->get_position().slice<2>(0); + block->index = { static_cast(round(center.x/block_size)), static_cast(round(center.y/block_size)) }; + if(generator) + { + LinAl::Vector base = center-block_setup.block_size/2.0f; + generator->generate_block({ base, base+block_setup.block_size }, block->terrain, spawner); + } + auto i = lower_bound(blocks, block->index, block_index_compare); + blocks.emplace(i, move(block)); + } + else + { + Handle tf = entity->get_transform(); + tf->set_position(get_ground_position(tf->get_position())); + props.emplace_back(move(entity)); + } +} + +void Landscape::spawn_sent(Handle entity, unsigned target) +{ + if(Handle block = dynamic_handle_cast(entity)) + { + Messages::LandscapeData message; + block->terrain->send_data(message.heightmap); + data_call(target, block, message); + } +} + +void Landscape::receive_data(Handle block, const Messages::LandscapeData &message) +{ + block->terrain->receive_data(message.heightmap); +} + + +Landscape::TerrainBlock::TerrainBlock(Handle p, const BlockSetup &s, const TransformValues &t): + Entity(p, t), + terrain(this, s.heightmap, s.block_size), + zygote(this) +{ } + } // namespace Msp::Game diff --git a/source/game/landscape.h b/source/game/landscape.h index 9319718..aa042e5 100644 --- a/source/game/landscape.h +++ b/source/game/landscape.h @@ -3,34 +3,47 @@ #include #include +#include "entity.h" #include "heightmapterrain.h" #include "mspgame_api.h" #include "owned.h" +#include "remotecall.h" +#include "spawner.h" #include "system.h" #include "transform.h" +#include "zygote.h" namespace Msp::Game { -class Entity; -class Landscape; - class MSPGAME_API LandscapeGenerator { protected: LandscapeGenerator() = default; public: - virtual void generate_block(Landscape &, const Geometry::BoundingBox &, Handle) = 0; + virtual void generate_block(const Geometry::BoundingBox &, Handle, Spawner &) = 0; }; -class MSPGAME_API Landscape: public System +class MSPGAME_API Landscape: public System, private SpawningHandler { private: - struct Terrain + struct BlockSetup + { + const HeightmapTerrainSetup &heightmap; + LinAl::Vector block_size; + + BlockSetup(const HeightmapTerrainSetup &h): heightmap(h) { } + }; + + struct TerrainBlock: Entity { + using Setup = BlockSetup; + LinAl::Vector index; - Owned entity; Owned terrain; + Owned zygote; + + TerrainBlock(Handle, const BlockSetup &, const TransformValues &); }; struct Prop @@ -38,18 +51,22 @@ private: Owned entity; }; + Replicator *replicator = nullptr; + ReplicatedEntityCall data_call; Owned subroot; - const HeightmapTerrainSetup &terrain_setup; + Spawner spawner; + BlockSetup block_setup; float block_size = 100.0f; LandscapeGenerator *generator = nullptr; - std::vector terrains; + std::vector> blocks; std::vector props; public: + Landscape(Stage &, Replicator *, const HeightmapTerrainSetup &, float); Landscape(Stage &, const HeightmapTerrainSetup &, float); private: - static bool terrain_index_compare(const Terrain &, const LinAl::Vector &); + static bool block_index_compare(const Owned &, const LinAl::Vector &); public: void set_generator(LandscapeGenerator *); @@ -58,20 +75,16 @@ public: template requires std::is_base_of_v - void add_prop(const T::Setup &, TransformValues); + void add_prop_type() { spawner.add_spawnable_type(); } void tick(Time::TimeDelta) override { } -}; +private: + void spawned(Owned) override; + void spawn_sent(Handle, unsigned) override; -template - requires std::is_base_of_v -void Landscape::add_prop(const T::Setup &setup, TransformValues tf) -{ - tf.position = get_ground_position(tf.position); - Owned prop(subroot, setup, tf); - props.emplace_back(std::move(prop)); -} + void receive_data(Handle, const Messages::LandscapeData &); +}; } // namespace Msp::Game diff --git a/source/game/messages.h b/source/game/messages.h index 860fc45..7e91919 100644 --- a/source/game/messages.h +++ b/source/game/messages.h @@ -1,6 +1,7 @@ #ifndef MSP_GAME_MESSAGES_H_ #define MSP_GAME_MESSAGES_H_ +#include #include #include @@ -51,6 +52,18 @@ struct StageActivated std::uint16_t name; }; +struct HeightmapPoint +{ + std::int16_t elevation; + std::uint8_t material; +}; + +struct LandscapeData +{ + std::uint32_t entity_id; + std::vector heightmap; +}; + } // namespace Messages } // namespace Msp::Game diff --git a/source/game/protocol.cpp b/source/game/protocol.cpp index 9c1d1f6..9b81f51 100644 --- a/source/game/protocol.cpp +++ b/source/game/protocol.cpp @@ -23,8 +23,10 @@ StageProtocol::StageProtocol() using Quaternion = Geometry::Quaternion; add(&Vector3f::x, &Vector3f::y, &Vector3f::z); add(&Quaternion::a, &Quaternion::b, &Quaternion::c, &Quaternion::d); + add(&HeightmapPoint::elevation, &HeightmapPoint::material); add(&SpawnEntity::id, &SpawnEntity::type, &SpawnEntity::setup, &SpawnEntity::position, &SpawnEntity::rotation, &SpawnEntity::scale); + add(&LandscapeData::entity_id, &LandscapeData::heightmap); } } // namespace Msp::Game