#include <concepts>
#include <functional>
#include <stdexcept>
+#include <typeinfo>
#include <msp/net/receiver.h>
#include "entity.h"
+#include "mspgame_api.h"
#include "replicator.h"
#include "zygote.h"
template<typename P>
concept HasEntityIdField = requires(P p) { { (p.entity_id) } -> std::same_as<std::uint32_t &>; };
-template<typename P, typename F = void(const P &)>
-class RemoteCallBase: protected Net::PacketReceiver<P>
+template<typename P, typename E>
+concept ValidRemoteCall = std::is_same_v<E, void> || (std::is_base_of_v<Entity, E> && HasEntityIdField<P>);
+
+
+template<typename P, typename E>
+ requires ValidRemoteCall<P, E>
+class RemoteCall: protected Net::PacketReceiver<P>
{
protected:
- using Function = std::function<F>;
+ using Function = std::conditional_t<std::is_same_v<E, void>,
+ std::function<void(const P &)>, std::function<void(Handle<E>, const P &)>>;
- Replicator *replicator;
+ Replicator *replicator = nullptr;
Function func;
- RemoteCallBase(Replicator *, Function);
-};
-
-
-template<typename P, typename E = Entity>
- requires std::is_base_of_v<Entity, E> && HasEntityIdField<P>
-class RemoteEntityCallBase: protected RemoteCallBase<P, void(Handle<E>, const P &)>
-{
-protected:
- using RemoteCallBase<P, void(Handle<E>, const P &)>::RemoteCallBase;
+ RemoteCall(Replicator *, Function);
- void prepare(Handle<E>, P &);
- void call(const P &);
+ void prepare(Handle<E>, P &) const;
+ void receive(P &&) override;
};
-template<typename P>
-class ReplicatedCall: public RemoteCallBase<P>
+template<typename P, typename E = void>
+class ReplicatedCall: public RemoteCall<P, E>
{
public:
- ReplicatedCall(Replicator *r, RemoteCallBase<P>::Function f): RemoteCallBase<P>(r, std::move(f)) { }
-
- void operator()(P &);
- void operator()(unsigned, P &);
+ ReplicatedCall(Replicator *r, RemoteCall<P, E>::Function f): RemoteCall<P, E>(r, std::move(f)) { }
-private:
- void receive(P &&p) override { this->func(p); }
+ void operator()(Handle<E>, P &);
+ void operator()(unsigned, Handle<E>, P &);
};
-
template<typename P>
-class RequestCall: public RemoteCallBase<P>
+class ReplicatedCall<P, void>: public RemoteCall<P, void>
{
public:
- RequestCall(Replicator *, RemoteCallBase<P>::Function);
-
- void operator()(P &);
+ ReplicatedCall(Replicator *r, RemoteCall<P, void>::Function f): RemoteCall<P, void>(r, std::move(f)) { }
-private:
- void receive(P &&p) override { this->func(p); }
+ void operator()(const P &);
+ void operator()(unsigned, const P &);
};
-template<typename P, typename E = Entity>
-class ReplicatedEntityCall: public RemoteEntityCallBase<P, E>
+template<typename P, typename E = void>
+class RequestCall: public RemoteCall<P, E>
{
public:
- ReplicatedEntityCall(Replicator *r, RemoteEntityCallBase<P, E>::Function f): RemoteEntityCallBase<P, E>(r, std::move(f)) { }
+ RequestCall(Replicator *r, RemoteCall<P, E>::Function f): RemoteCall<P, E>(r, std::move(f)) { }
void operator()(Handle<E>, P &);
- void operator()(unsigned, Handle<E>, P &);
-
- void receive(P &&p) override { this->call(p); }
};
-
-template<typename P, typename E = Entity>
-class EntityRequestCall: public RemoteEntityCallBase<P, E>
+template<typename P>
+class RequestCall<P, void>: public RemoteCall<P, void>
{
public:
- EntityRequestCall(Replicator *r, RemoteEntityCallBase<P, E>::Function f): RemoteEntityCallBase<P, E>(r, std::move(f)) { }
-
- void operator()(Handle<E>, P &);
+ RequestCall(Replicator *r, RemoteCall<P, void>::Function f): RemoteCall<P, void>(r, std::move(f)) { }
- void receive(P &&p) override { this->call(p); }
+ void operator()(P &);
};
-template<typename P, typename F>
-RemoteCallBase<P, F>::RemoteCallBase(Replicator *r, Function f):
+template<typename P, typename E>
+ requires ValidRemoteCall<P, E>
+RemoteCall<P, E>::RemoteCall(Replicator *r, Function f):
replicator(r),
func(std::move(f))
{
if(replicator)
- replicator->add_receiver<P>(*this);
+ replicator->add_receiver(*this);
}
-
template<typename P, typename E>
- requires std::is_base_of_v<Entity, E> && HasEntityIdField<P>
-void RemoteEntityCallBase<P, E>::prepare(Handle<E> entity, P &packet)
+ requires ValidRemoteCall<P, E>
+void RemoteCall<P, E>::prepare(Handle<E> entity, P &packet) const
{
Handle<Zygote> zygote = entity->template get_component<Zygote>();
if(!zygote)
- throw std::invalid_argument("ReplicatedEntityCall::operator()");
+ throw std::invalid_argument("RemoteCall::prepare");
std::uint32_t entity_id = zygote->get_entity_id();
if(entity_id==Zygote::NO_ID)
- throw std::invalid_argument("ReplicatedEntityCall::operator()");
+ throw std::invalid_argument("RemoteCall::prepare");
packet.entity_id = entity_id;
}
template<typename P, typename E>
- requires std::is_base_of_v<Entity, E> && HasEntityIdField<P>
-void RemoteEntityCallBase<P, E>::call(const P &packet)
+ requires ValidRemoteCall<P, E>
+void RemoteCall<P, E>::receive(P &&packet)
{
- Handle<Entity> entity = this->replicator->find_entity(packet.entity_id, this->replicator->is_server());
- if(!entity)
- return; // TODO report the error somehow
+ if constexpr(std::is_same_v<E, void>)
+ this->func(packet);
+ else
+ {
+ Handle<Entity> entity = this->replicator->find_entity(packet.entity_id, this->replicator->is_server());
+ if(!entity)
+ return; // TODO report the error somehow
- Handle<E> cast_entity = dynamic_handle_cast<E>(entity);
- if(!cast_entity)
- return;
+ Handle<E> cast_entity = dynamic_handle_cast<E>(entity);
+ if(!cast_entity)
+ return;
- this->func(cast_entity, packet);
+ this->func(cast_entity, packet);
+ }
}
-template<typename P>
-void ReplicatedCall<P>::operator()(P &packet)
+template<typename P, typename E>
+void ReplicatedCall<P, E>::operator()(Handle<E> entity, P &packet)
{
if(this->replicator)
{
if(!this->replicator->is_server())
throw invalid_state("ReplicatedCall<P>::operator()");
- this->replicator->send(packet);
+ this->prepare(entity, packet);
+ this->replicator->send(entity, packet);
}
- func(packet);
+ this->func(entity, packet);
}
-template<typename P>
-void ReplicatedCall<P>::operator()(unsigned target, P &packet)
+template<typename P, typename E>
+void ReplicatedCall<P, E>::operator()(unsigned target, Handle<E> entity, P &packet)
{
if(this->replicator)
+ {
+ this->prepare(entity, packet);
this->replicator->send(target, packet);
+ }
}
template<typename P>
-void RequestCall<P>::operator()(P &packet)
-{
- if(this->replicator && !this->replicator->is_server())
- this->replicator->send(packet);
- else
- this->func(packet);
-}
-
-
-template<typename P, typename E>
-void ReplicatedEntityCall<P, E>::operator()(Handle<E> entity, P &packet)
+void ReplicatedCall<P, void>::operator()(const P &packet)
{
if(this->replicator)
{
- this->prepare(entity, packet);
- this->replicator->send(entity, packet);
+ if(!this->replicator->is_server())
+ throw invalid_state("ReplicatedCall<P>::operator()");
+ this->replicator->send(packet);
}
- this->func(entity, packet);
+ this->func(packet);
}
-template<typename P, typename E>
-void ReplicatedEntityCall<P, E>::operator()(unsigned target, Handle<E> entity, P &packet)
+template<typename P>
+void ReplicatedCall<P, void>::operator()(unsigned target, const P &packet)
{
if(this->replicator)
- {
- this->prepare(entity, packet);
this->replicator->send(target, packet);
- }
}
template<typename P, typename E>
-void EntityRequestCall<P, E>::operator()(Handle<E> entity, P &packet)
+void RequestCall<P, E>::operator()(Handle<E> entity, P &packet)
{
if(this->replicator && !this->replicator->is_server())
{
this->func(entity, packet);
}
+
+template<typename P>
+void RequestCall<P, void>::operator()(P &packet)
+{
+ if(this->replicator && !this->replicator->is_server())
+ this->replicator->send(packet);
+ else
+ this->func(packet);
+}
+
} // namespace Msp::Game
#endif