--- /dev/null
+#ifndef MSP_GAME_REMOTECALL_H_
+#define MSP_GAME_REMOTECALL_H_
+
+#include <functional>
+#include <stdexcept>
+#include <msp/net/receiver.h>
+#include "entity.h"
+#include "replicator.h"
+#include "zygote.h"
+
+namespace Msp::Game {
+
+template<typename P>
+class ReplicatedCall: private Net::PacketReceiver<P>
+{
+public:
+ using Function = std::function<void(const P &)>;
+
+private:
+ Replicator *replicator = nullptr;
+ Function func;
+
+public:
+ ReplicatedCall(Replicator *, Function);
+
+ void operator()(P &);
+ void operator()(unsigned, P &);
+
+private:
+ void receive(const P &) override;
+};
+
+
+template<typename P, typename E = Entity>
+ requires std::is_base_of_v<Entity, E>
+class ReplicatedEntityCall: private Net::PacketReceiver<P>
+{
+public:
+ using Function = std::function<void(Handle<E>, const P &)>;
+
+private:
+ Replicator *replicator = nullptr;
+ Function func;
+
+public:
+ ReplicatedEntityCall(Replicator *, Function);
+
+ void operator()(Handle<Entity>, P &);
+ void operator()(unsigned, Handle<Entity>, P &);
+
+private:
+ void prepare(Handle<Entity>, P &);
+
+public:
+ void receive(const P &) override;
+};
+
+
+template<typename P>
+ReplicatedCall<P>::ReplicatedCall(Replicator *r, std::function<void(const P &)> f):
+ replicator(r),
+ func(std::move(f))
+{
+ if(replicator)
+ replicator->add_receiver<P>(*this);
+}
+
+template<typename P>
+void ReplicatedCall<P>::operator()(P &packet)
+{
+ if(replicator)
+ replicator->send(packet);
+ func(packet);
+}
+
+template<typename P>
+void ReplicatedCall<P>::receive(const P &packet)
+{
+ func(packet);
+}
+
+
+template<typename P, typename E>
+ReplicatedEntityCall<P, E>::ReplicatedEntityCall(Replicator *r, Function f):
+ replicator(r),
+ func(std::move(f))
+{
+ if(replicator)
+ replicator->add_receiver<P>(*this);
+}
+
+template<typename P, typename E>
+void ReplicatedEntityCall<P, E>::operator()(Handle<Entity> entity, P &packet)
+{
+ if(replicator)
+ {
+ prepare(entity, packet);
+ replicator->send(entity, packet);
+ }
+ func(entity, packet);
+}
+
+template<typename P, typename E>
+void ReplicatedEntityCall<P, E>::operator()(unsigned target, Handle<Entity> entity, P &packet)
+{
+ if(replicator)
+ {
+ prepare(entity, packet);
+ replicator->send(target, packet);
+ }
+}
+
+template<typename P, typename E>
+void ReplicatedEntityCall<P, E>::prepare(Handle<Entity> entity, P &packet)
+{
+ Handle<Zygote> zygote = entity->get_component<Zygote>();
+ if(!zygote)
+ throw std::invalid_argument("ReplicatedEntityCall::operator()");
+
+ std::uint32_t entity_id = zygote->get_entity_id();
+ if(entity_id==Zygote::NO_ID)
+ throw std::invalid_argument("ReplicatedEntityCall::operator()");
+
+ packet.entity_id = entity_id;
+}
+
+template<typename P, typename E>
+void ReplicatedEntityCall<P, E>::receive(const P &packet)
+{
+ Handle<Entity> entity = replicator->find_entity(packet.entity_id);
+ if(!entity)
+ return; // TODO report the error somehow
+
+ Handle<E> cast_entity = dynamic_handle_cast<E>(entity);
+ if(!cast_entity)
+ return;
+
+ func(cast_entity, packet);
+}
+
+} // namespace Msp::Game
+
+#endif
#include "replicator.h"
-#include "entity.h"
-#include "networking.h"
#include <msp/core/raii.h>
#include "spawner.h"
#include "transform.h"
Replicator::Replicator(Stage &s, Networking &n):
System(s),
observer(stage.get_event_bus()),
- networking(n)
+ networking(n),
+ protocol(networking.set_receiver<StageProtocol>(&dispatcher))
{
observer.observe<Events::ComponentCreated>([this](const auto &e){ component_created(e); });
- const Net::Protocol &protocol = networking.set_receiver<StageProtocol>(&dispatcher);
- dispatcher.add_receiver<Messages::SpawnEntity>(protocol.get_packet_id<Messages::SpawnEntity>(), *this);
+ add_receiver<Messages::SpawnEntity>(*this);
}
void Replicator::add_spawner(Spawner &spawner, const string &type)
send_spawn(e, id);
}
+Handle<Entity> Replicator::find_entity(uint32_t id) const
+{
+ auto i = find_if(entities, [id](const ReplicatedEntity &e){ return e.zygote->get_entity_id()==id; });
+ return (i!=entities.end() ? i->entity : nullptr);
+}
+
void Replicator::deferred_tick()
{
for(ReplicatedEntity &e: entities)
#include <vector>
#include <msp/net/receiver.h>
+#include "entity.h"
#include "messages.h"
+#include "networking.h"
#include "protocol.h"
#include "system.h"
#include "zygote.h"
namespace Msp::Game {
-class Networking;
class Spawner;
class Transform;
EventObserver observer;
Networking &networking;
Net::DynamicDispatcher dispatcher;
+ const Net::Protocol &protocol;
std::vector<Spawner *> spawners;
std::vector<ReplicatedEntity> entities;
std::vector<unsigned> players;
void add_spawner(Spawner &, const std::string &);
void add_target_player(unsigned);
+ template<typename P>
+ void add_receiver(Net::PacketReceiver<P> &);
+
+ template<typename P>
+ void send(const P &);
+
+ template<typename P>
+ void send(Handle<Entity>, const P &);
+
+ template<typename P>
+ void send(unsigned, const P &);
+
+ Handle<Entity> find_entity(std::uint32_t) const;
+
void tick(Time::TimeDelta) override { }
void deferred_tick() override;
void receive(const Messages::SpawnEntity &) override;
};
+template<typename P>
+void Replicator::add_receiver(Net::PacketReceiver<P> &recv)
+{
+ dispatcher.add_receiver<P>(protocol.get_packet_id<P>(), recv);
+}
+
+template<typename P>
+void Replicator::send(const P &packet)
+{
+ for(unsigned p: players)
+ networking.send(p, packet);
+}
+
+template<typename P>
+void Replicator::send(Handle<Entity> entity, const P &packet)
+{
+ Handle<Transform> transform = entity->get_transform();
+ auto i = lower_bound_member(entities, transform, &ReplicatedEntity::transform);
+ if(i==entities.end() || i->transform!=transform)
+ return;
+
+ if(i->visible_to_players)
+ send(packet);
+}
+
+template<typename P>
+void Replicator::send(unsigned target, const P &packet)
+{
+ networking.send(target, packet);
+}
+
} // namespace Msp::Game
#endif