From 1775667ef772eab604c355cbf4d96b520a150fce Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 9 Jan 2024 23:49:59 +0200 Subject: [PATCH] Add facilities to designate entities as player-controlled --- source/game/events.h | 6 ++++ source/game/messages.h | 6 ++++ source/game/possessed.cpp | 17 +++++++++++ source/game/possessed.h | 26 +++++++++++++++++ source/game/protocol.cpp | 1 + source/game/replicator.cpp | 59 +++++++++++++++++++++++++++++++++++++- source/game/replicator.h | 14 +++++++-- 7 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 source/game/possessed.cpp create mode 100644 source/game/possessed.h diff --git a/source/game/events.h b/source/game/events.h index 7636a10..436537e 100644 --- a/source/game/events.h +++ b/source/game/events.h @@ -77,6 +77,12 @@ struct RemotePlayerEntered unsigned id; }; +struct PossessionChanged +{ + Handle entity; + unsigned player_id; +}; + struct RemotePlayerExited { unsigned id; diff --git a/source/game/messages.h b/source/game/messages.h index c576ae6..4b96215 100644 --- a/source/game/messages.h +++ b/source/game/messages.h @@ -48,6 +48,12 @@ struct SpawnEntity LinAl::Vector scale; }; +struct GrantPossession +{ + std::uint32_t entity_id; + std::uint16_t player_id; +}; + struct StageActivated { std::uint16_t name; diff --git a/source/game/possessed.cpp b/source/game/possessed.cpp new file mode 100644 index 0000000..cc52e1c --- /dev/null +++ b/source/game/possessed.cpp @@ -0,0 +1,17 @@ +#include "possessed.h" + +namespace Msp::Game { + +void Possessed::set_player_id(unsigned p) +{ + if(p!=player_id) + changed = true; + player_id = p; +} + +void Possessed::clear_changed() +{ + changed = false; +} + +} // namespace Msp::Game diff --git a/source/game/possessed.h b/source/game/possessed.h new file mode 100644 index 0000000..54350da --- /dev/null +++ b/source/game/possessed.h @@ -0,0 +1,26 @@ +#ifndef MSP_GAME_POSSESSED_H_ +#define MSP_GAME_POSSESSED_H_ + +#include "component.h" +#include "mspgame_api.h" + +namespace Msp::Game { + +class MSPGAME_API Possessed: public Component +{ +private: + unsigned player_id = 0; + bool changed = false; + +public: + Possessed(Handle e): Component(e) { } + + void set_player_id(unsigned); + unsigned get_player_id() const { return player_id; } + bool has_changed() const { return changed; } + void clear_changed(); +}; + +} // namespace Msp::Game + +#endif diff --git a/source/game/protocol.cpp b/source/game/protocol.cpp index 9b81f51..32242a9 100644 --- a/source/game/protocol.cpp +++ b/source/game/protocol.cpp @@ -26,6 +26,7 @@ StageProtocol::StageProtocol() add(&HeightmapPoint::elevation, &HeightmapPoint::material); add(&SpawnEntity::id, &SpawnEntity::type, &SpawnEntity::setup, &SpawnEntity::position, &SpawnEntity::rotation, &SpawnEntity::scale); + add(&GrantPossession::entity_id, &GrantPossession::player_id); add(&LandscapeData::entity_id, &LandscapeData::heightmap); } diff --git a/source/game/replicator.cpp b/source/game/replicator.cpp index 94bdc27..9fd6eb5 100644 --- a/source/game/replicator.cpp +++ b/source/game/replicator.cpp @@ -1,5 +1,6 @@ #include "replicator.h" #include +#include "possessed.h" #include "spawner.h" #include "transform.h" #include "zygote.h" @@ -10,6 +11,7 @@ namespace Msp::Game { Replicator::Replicator(Stage &s, Networking &n): System(s), + event_source(stage.get_event_bus()), observer(stage.get_event_bus()), networking(n), protocol(networking.set_receiver(&dispatcher)) @@ -17,6 +19,7 @@ Replicator::Replicator(Stage &s, Networking &n): observer.observe([this](const auto &e){ component_created(e); }); add_receiver(*this); + add_receiver(*this); } void Replicator::add_spawner(Spawner &spawner, const string &type) @@ -47,6 +50,23 @@ Handle Replicator::find_entity(uint32_t id) const return (i!=entities.end() ? i->entity : nullptr); } +void Replicator::tick(Time::TimeDelta) +{ + stage.iterate_objects([this](Possessed &p){ + if(p.has_changed()) + { + auto i = lower_bound_member(entities, p.get_entity()->get_transform(), &ReplicatedEntity::transform); + if(i!=entities.end() && i->possessed.get()==&p) + { + event_source.emit(i->entity, p.get_player_id()); + if(i->visible_to_players && is_server()) + send_possession(*i, -1); + } + p.clear_changed(); + } + }); +} + void Replicator::deferred_tick() { for(ReplicatedEntity &e: entities) @@ -63,14 +83,22 @@ void Replicator::component_created(const Events::ComponentCreated &event) { Handle entity = zygote->get_entity(); Handle transform = entity->get_transform(); + Handle possessed = entity->get_component(); auto i = lower_bound_member(entities, transform, &ReplicatedEntity::transform); - entities.emplace(i, entity, transform, zygote); + entities.emplace(i, entity, transform, zygote, possessed); if(networking.is_server()) zygote->set_entity_id(next_entity_id++); else if(received_entity_id!=Zygote::NO_ID) zygote->set_entity_id(received_entity_id); } + else if(Handle possessed = dynamic_handle_cast(event.component)) + { + Handle transform = possessed->get_entity()->get_transform(); + auto i = lower_bound_member(entities, transform, &ReplicatedEntity::transform); + if(i!=entities.end() && i->transform==transform) + i->possessed = possessed; + } } void Replicator::send_spawn(const ReplicatedEntity &re, int target) @@ -97,6 +125,27 @@ void Replicator::send_spawn(const ReplicatedEntity &re, int target) } info.spawner->notify_spawn_sent(re.entity, target); + + if(re.possessed && re.possessed->get_player_id()) + send_possession(re, target); +} + +void Replicator::send_possession(const ReplicatedEntity &re, int target) +{ + if(target<0 && players.empty()) + return; + + Messages::GrantPossession grant; + grant.entity_id = re.zygote->get_entity_id(); + grant.player_id = re.possessed->get_player_id(); + + if(target>=0) + networking.send(target, grant); + else + { + for(unsigned p: players) + networking.send(p, grant); + } } void Replicator::receive(const Messages::SpawnEntity &message) @@ -111,4 +160,12 @@ void Replicator::receive(const Messages::SpawnEntity &message) (*i)->spawn(type_name, setup_name, TransformValues(message.position, message.rotation, message.scale)); } +void Replicator::receive(const Messages::GrantPossession &message) +{ + Handle entity = find_entity(message.entity_id); + if(entity) + if(Handle possessed = entity->get_component()) + possessed->set_player_id(message.player_id); +} + } // namespace Msp::Game diff --git a/source/game/replicator.h b/source/game/replicator.h index 6dc42e8..23c5b66 100644 --- a/source/game/replicator.h +++ b/source/game/replicator.h @@ -12,20 +12,27 @@ namespace Msp::Game { +class Possessed; class Spawner; class Transform; -class MSPGAME_API Replicator: public System, private Net::PacketReceiver +class MSPGAME_API Replicator: public System, private Net::PacketReceiver, + private Net::PacketReceiver { +public: + using EventSource = Game::EventSource; + private: struct ReplicatedEntity { Handle entity; Handle transform; Handle zygote; + Handle possessed; bool visible_to_players = false; }; + EventSource event_source; EventObserver observer; Networking &networking; Net::DynamicDispatcher dispatcher; @@ -41,6 +48,7 @@ public: void add_spawner(Spawner &, const std::string &); void add_target_player(unsigned); + bool is_server() const { return networking.is_server(); } template void add_receiver(Net::PacketReceiver

&); @@ -56,14 +64,16 @@ public: Handle find_entity(std::uint32_t) const; - void tick(Time::TimeDelta) override { } + void tick(Time::TimeDelta) override; void deferred_tick() override; private: void component_created(const Events::ComponentCreated &); void send_spawn(const ReplicatedEntity &, int); + void send_possession(const ReplicatedEntity &, int); void receive(const Messages::SpawnEntity &) override; + void receive(const Messages::GrantPossession &) override; }; template -- 2.45.2