Same make_obj call allocates the correct type

This commit is contained in:
Yousef Khadadeh 2025-12-08 20:51:11 +03:00
parent 5d24b34200
commit d9a90dda16
10 changed files with 53 additions and 17 deletions

View file

@ -3,7 +3,7 @@
namespace NetworkingObjects {
template <typename T> void register_generic_serialized_class(NetObjManagerTypeList& t) {
t.register_class<T, T>({
t.register_class<T, T, T, T>({
.writeConstructorFuncClient = [](const NetObjPtr<T>& o, cereal::PortableBinaryOutputArchive& a) {
a(*o);
},

View file

@ -10,6 +10,11 @@ namespace NetworkingObjects {
template <typename Archive> void serialize(Archive& a) {
a(data[1], data[0]);
}
std::string to_string() {
std::stringstream ss;
ss << "[" << data[1] << ", " << data[0] << "]";
return ss.str();
}
NetObjID& operator=(const NetObjID&) = default;
bool operator==(const NetObjID&) const = default;
static NetObjID random_gen();

View file

@ -23,7 +23,6 @@ namespace NetworkingObjects {
void set_client(std::shared_ptr<NetClient> initClient, MessageCommandType initUpdateCommandID);
void set_server(std::shared_ptr<NetServer> initServer, MessageCommandType initUpdateCommandID);
bool is_server() const;
template <typename T> NetObjPtr<T> read_create_message(cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& clientReceivedFrom) {
NetObjID id;
NetTypeIDType typeID;
@ -42,7 +41,15 @@ namespace NetworkingObjects {
return NetObjPtr<T>();
return NetObjPtr<T>(this, id, std::static_pointer_cast<T>(it->second.p));
}
template <typename T, typename... Args> NetObjPtr<T> make_obj(Args&&... items) {
template <typename T> NetObjPtr<T> make_obj() {
auto sharedPtr = std::static_pointer_cast<T>(isServer ? typeList->typeIndexDataServer[std::type_index(typeid(T*))].allocatorFunc() : typeList->typeIndexDataClient[std::type_index(typeid(T*))].allocatorFunc());
NetObjID newID = NetObjID::random_gen();
if(!objectData.emplace(newID, SingleObjectData{.netTypeID = isServer ? typeList->typeIndexDataServer[std::type_index(typeid(T*))].netTypeID : typeList->typeIndexDataClient[std::type_index(typeid(T*))].netTypeID, .p = std::static_pointer_cast<void>(sharedPtr)}).second)
throw std::runtime_error("[NetObjManager::make_obj] ID Collision");
return NetObjPtr<T>(this, newID, sharedPtr);
}
// Don't use this function unless you're sure that class T isn't a base class
template <typename T, typename... Args> NetObjPtr<T> make_obj_direct(Args&&... items) {
auto sharedPtr = std::make_shared<T>(items...);
NetObjID newID = NetObjID::random_gen();
if(!objectData.emplace(newID, SingleObjectData{.netTypeID = isServer ? typeList->typeIndexDataServer[std::type_index(typeid(T*))].netTypeID : typeList->typeIndexDataClient[std::type_index(typeid(T*))].netTypeID, .p = std::static_pointer_cast<void>(sharedPtr)}).second)

View file

@ -17,7 +17,7 @@ class NetObjManagerTypeList {
std::function<NetObjPtr<void>(NetObjManager&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readConstructorFuncServer;
std::function<void(const NetObjPtr<ServerT>&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readUpdateFuncServer;
};
template <typename ClientT, typename ServerT> void register_class(const ServerClientClassFunctions<ClientT, ServerT>& funcs) {
template <typename ClientT, typename ServerT, typename ClientAllocatedType, typename ServerAllocatedType> void register_class(const ServerClientClassFunctions<ClientT, ServerT>& funcs) {
netTypeIDData[nextNetTypeID] = NetTypeIDContainer {
.readConstructorFuncClient = funcs.readConstructorFuncClient,
.readUpdateFuncClient = [f = funcs.readUpdateFuncClient](const NetObjPtr<void>& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr<NetServer::ClientData>& c) {
@ -35,12 +35,14 @@ class NetObjManagerTypeList {
.writeConstructorFunc = [f = funcs.writeConstructorFuncClient](const NetObjPtr<void>& obj, cereal::PortableBinaryOutputArchive& message) {
f(obj.cast<ClientT>(), message);
},
.allocatorFunc = []() { return std::make_shared<ClientAllocatedType>(); }
};
typeIndexDataServer[std::type_index(typeid(ServerT*))] = TypeIndexContainer{
.netTypeID = nextNetTypeID,
.writeConstructorFunc = [f = funcs.writeConstructorFuncServer](const NetObjPtr<void>& obj, cereal::PortableBinaryOutputArchive& message) {
f(obj.cast<ServerT>(), message);
},
.allocatorFunc = []() { return std::make_shared<ServerAllocatedType>(); }
};
nextNetTypeID++;
}
@ -51,6 +53,7 @@ class NetObjManagerTypeList {
struct TypeIndexContainer {
NetTypeIDType netTypeID;
std::function<void(const NetObjPtr<void>&, cereal::PortableBinaryOutputArchive&)> writeConstructorFunc;
std::function<std::shared_ptr<void>()> allocatorFunc;
};
// std::type_index in this case is the typeinfo for the POINTER of the type in question. This ensures that we get a mapping for the exact type that was registered, not for a child of the type in case of inheritance

View file

@ -45,9 +45,11 @@ namespace NetworkingObjects {
template <typename T> class NetObjOrderedList {
public:
template <typename... Args> static NetObjPtr<T> emplace_back(const NetObjPtr<NetObjOrderedList<T>>& l, Args&&... args) {
NetObjPtr<T> newObj = l.get_obj_man()->template make_obj<T>(args...);
return push_back_and_send_create(l, newObj);
// Don't use this function unless you're sure that class T isn't a base class
template <typename ...Args> NetObjPtr<T> emplace_back_direct(const NetObjPtr<NetObjOrderedList<T>>& l, Args&&... items) {
NetObjPtr<T> newObj = l.get_obj_man()->template make_obj_direct<T>(items...);
l->push_back(l, newObj);
return newObj;
}
static NetObjPtr<T> push_back_and_send_create(const NetObjPtr<NetObjOrderedList<T>>& l, const NetObjPtr<T>& newObj) {
l->push_back(l, newObj);
@ -65,6 +67,7 @@ namespace NetworkingObjects {
}
virtual uint32_t size() const = 0;
virtual const std::vector<NetObjOrderedListObjectInfoPtr<T>>& get_data() const = 0;
virtual ~NetObjOrderedList() {}
protected:
virtual void push_back(const NetObjPtr<NetObjOrderedList<T>>& l, const NetObjPtr<T>& newObj) = 0;
virtual void insert(const NetObjPtr<NetObjOrderedList<T>>& l, uint32_t posToInsertAt, const NetObjPtr<T>& newObj) = 0;
@ -86,6 +89,7 @@ namespace NetworkingObjects {
template <typename T> class NetObjOrderedListServer : public NetObjOrderedList<T> {
public:
NetObjOrderedListServer() {}
virtual uint32_t size() const override {
return data.size();
}
@ -166,6 +170,7 @@ namespace NetworkingObjects {
template <typename T> class NetObjOrderedListClient : public NetObjOrderedList<T> {
public:
NetObjOrderedListClient() {}
virtual uint32_t size() const override {
return clientData.size();
}
@ -241,13 +246,13 @@ namespace NetworkingObjects {
};
template <typename T> NetObjPtr<void> NetObjOrderedList<T>::read_constructor_func(NetObjManager& objMan, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c) {
NetObjPtr<NetObjOrderedList<T>> allocatedPtr = objMan.is_server() ? objMan.make_obj<NetObjOrderedListServer<T>>().template cast<NetObjOrderedList<T>>() : objMan.make_obj<NetObjOrderedListClient<T>>().template cast<NetObjOrderedList<T>>();
NetObjPtr<NetObjOrderedList<T>> allocatedPtr = objMan.make_obj<NetObjOrderedList<T>>();
allocatedPtr->read_constructor_post_allocation(allocatedPtr, a, c);
return allocatedPtr.template cast<void>();
}
template <typename S> void register_ordered_list_class(NetObjManagerTypeList& t) {
t.register_class<NetObjOrderedList<S>, NetObjOrderedList<S>>({
t.register_class<NetObjOrderedList<S>, NetObjOrderedList<S>, NetObjOrderedListClient<S>, NetObjOrderedListServer<S>>({
.writeConstructorFuncClient = NetObjOrderedList<S>::write_constructor_func,
.readConstructorFuncClient = NetObjOrderedList<S>::read_constructor_func,
.readUpdateFuncClient = NetObjOrderedList<S>::read_update_func,