insert and erase single functions done for both server and client network lists

This commit is contained in:
Yousef Khadadeh 2025-12-07 23:09:17 +03:00
parent 2f7ebfe083
commit 35b46d9d2b
5 changed files with 63 additions and 48 deletions

View file

@ -8,6 +8,9 @@ namespace NetworkingObjects {
typeList(initTypeList),
nextTypeID(0)
{}
bool NetObjManager::is_server() const {
return isServer;
}
void NetObjManager::read_update_message(cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& clientReceivedFrom) {
NetObjID id;
a(id);

View file

@ -21,21 +21,17 @@ namespace NetworkingObjects {
void read_update_message(cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& clientReceivedFrom);
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;
a(id, typeID);
auto& netTypeIDData = typeList->netTypeIDData[typeID];
std::shared_ptr<void> sharedPtr = isServer ? netTypeIDData.allocatorFuncServer() : netTypeIDData.allocatorFuncClient();
auto [it, placed] = objectData.emplace(id, SingleObjectData{.netTypeID = typeID, .p = sharedPtr});
if(!placed)
throw std::runtime_error("[NetObjManager::read_create_message] ID Collision on object creation");
if(isServer)
netTypeIDData.readConstructorFuncServer(NetObjPtr<void>(this, id, sharedPtr), a, clientReceivedFrom);
return netTypeIDData.readConstructorFuncServer(*this, a, clientReceivedFrom).cast<T>();
else
netTypeIDData.readConstructorFuncClient(NetObjPtr<void>(this, id, sharedPtr), a, clientReceivedFrom);
return NetObjPtr<T>(this, id, std::static_pointer_cast<T>(sharedPtr));
return netTypeIDData.readConstructorFuncClient(*this, a, clientReceivedFrom).cast<T>();
}
template <typename T> NetObjPtr<T> read_get_obj_from_message(cereal::PortableBinaryInputArchive& a) {
NetObjID id;
@ -48,14 +44,14 @@ namespace NetworkingObjects {
template <typename T, typename... Args> NetObjPtr<T> make_obj(Args&&... items) {
auto sharedPtr = std::make_shared<T>(items...);
NetObjID newID = idGen->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)
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);
}
template <typename T> NetObjPtr<T> obj_from_ptr(T* p) {
std::shared_ptr<T> sharedPtr(p);
NetObjID newID = idGen->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)
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::obj_from_ptr] ID Collision");
return NetObjPtr<T>(this, newID, sharedPtr);
}

View file

@ -10,47 +10,36 @@ class NetObjManagerTypeList {
public:
template <typename ClientT, typename ServerT> struct ServerClientClassFunctions {
std::function<void(const NetObjPtr<ClientT>&, cereal::PortableBinaryOutputArchive&)> writeConstructorFuncClient;
std::function<void(const NetObjPtr<ClientT>&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readConstructorFuncClient;
std::function<NetObjPtr<void>(NetObjManager&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readConstructorFuncClient;
std::function<void(const NetObjPtr<ClientT>&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readUpdateFuncClient;
std::function<void(const NetObjPtr<ServerT>&, cereal::PortableBinaryOutputArchive&)> writeConstructorFuncServer;
std::function<void(const NetObjPtr<ServerT>&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readConstructorFuncServer;
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 ClientPointerType, typename ServerPointerType, typename ClientActualType, typename ServerActualType> void register_class(const ServerClientClassFunctions<ClientPointerType, ServerPointerType>& funcs) {
template <typename ClientT, typename ServerT> void register_class(const ServerClientClassFunctions<ClientT, ServerT>& funcs) {
netTypeIDData[nextNetTypeID] = NetTypeIDContainer {
.readConstructorFuncClient = [f = funcs.readConstructorFuncClient](const NetObjPtr<void>& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr<NetServer::ClientData>& c) {
if(f)
f(obj.cast<ClientPointerType>(), message, c);
},
.readConstructorFuncClient = funcs.readConstructorFuncClient,
.readUpdateFuncClient = [f = funcs.readUpdateFuncClient](const NetObjPtr<void>& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr<NetServer::ClientData>& c) {
if(f)
f(obj.cast<ClientPointerType>(), message, c);
},
.allocatorFuncClient = []() { return std::static_pointer_cast<void>(std::make_shared<ClientActualType>()); },
.readConstructorFuncServer = [f = funcs.readConstructorFuncServer](const NetObjPtr<void>& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr<NetServer::ClientData>& c) {
if(f)
f(obj.cast<ServerPointerType>(), message, c);
f(obj.cast<ClientT>(), message, c);
},
.readConstructorFuncServer = funcs.readConstructorFuncServer,
.readUpdateFuncServer = [f = funcs.readUpdateFuncServer](const NetObjPtr<void>& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr<NetServer::ClientData>& c) {
if(f)
f(obj.cast<ServerPointerType>(), message, c);
f(obj.cast<ServerT>(), message, c);
},
.allocatorFuncServer = []() { return std::static_pointer_cast<void>(std::make_shared<ServerActualType>()); }
};
typeIndexDataClient[std::type_index(typeid(ClientActualType))] = TypeIndexContainer{
typeIndexDataClient[std::type_index(typeid(ClientT*))] = TypeIndexContainer{
.netTypeID = nextNetTypeID,
.writeConstructorFunc = [f = funcs.writeConstructorFuncClient](const NetObjPtr<void>& obj, cereal::PortableBinaryOutputArchive& message) {
if(f)
f(obj.cast<ClientPointerType>(), message);
f(obj.cast<ClientT>(), message);
},
};
typeIndexDataServer[std::type_index(typeid(ServerActualType))] = TypeIndexContainer{
typeIndexDataServer[std::type_index(typeid(ServerT*))] = TypeIndexContainer{
.netTypeID = nextNetTypeID,
.writeConstructorFunc = [f = funcs.writeConstructorFuncServer](const NetObjPtr<void>& obj, cereal::PortableBinaryOutputArchive& message) {
if(f)
f(obj.cast<ServerPointerType>(), message);
f(obj.cast<ServerT>(), message);
},
};
nextNetTypeID++;
@ -64,17 +53,16 @@ class NetObjManagerTypeList {
std::function<void(const NetObjPtr<void>&, cereal::PortableBinaryOutputArchive&)> writeConstructorFunc;
};
// 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
std::unordered_map<std::type_index, TypeIndexContainer> typeIndexDataClient;
std::unordered_map<std::type_index, TypeIndexContainer> typeIndexDataServer;
struct NetTypeIDContainer {
std::function<void(const NetObjPtr<void>&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readConstructorFuncClient;
std::function<NetObjPtr<void>(NetObjManager&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readConstructorFuncClient;
std::function<void(const NetObjPtr<void>&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readUpdateFuncClient;
std::function<std::shared_ptr<void>()> allocatorFuncClient;
std::function<void(const NetObjPtr<void>&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readConstructorFuncServer;
std::function<NetObjPtr<void>(NetObjManager&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readConstructorFuncServer;
std::function<void(const NetObjPtr<void>&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readUpdateFuncServer;
std::function<std::shared_ptr<void>()> allocatorFuncServer;
};
std::unordered_map<NetTypeIDType, NetTypeIDContainer> netTypeIDData;

View file

@ -71,15 +71,13 @@ namespace NetworkingObjects {
virtual void erase_by_ptr(const NetObjPtr<NetObjOrderedList<T>>& l, const NetObjOrderedListObjectInfoPtr<T>& p) = 0;
virtual void write_constructor(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryOutputArchive& a) = 0;
virtual void read_update(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) = 0;
virtual void read_constructor(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) = 0;
virtual void read_constructor_post_allocation(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) = 0;
private:
template <typename S> friend void register_ordered_list_class(NetObjManagerTypeList& t);
static void write_constructor_func(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryOutputArchive& a) {
l->write_constructor(l, a);
}
static void read_constructor_func(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c) {
l->read_constructor(l, a, c);
}
static NetObjPtr<void> read_constructor_func(NetObjManager& objMan, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c);
static void read_update_func(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c) {
l->read_update(l, a, c);
}
@ -111,7 +109,6 @@ namespace NetworkingObjects {
});
}
virtual void erase_by_index(const NetObjPtr<NetObjOrderedList<T>>& l, uint32_t indexToErase) override {
NetObjOrderedListObjectInfoPtr<T>& objToErase = data[indexToErase];
l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [indexToErase](const NetObjPtr<NetObjOrderedList<T>>&, cereal::PortableBinaryOutputArchive& a) {
a(ObjPtrOrderedListCommand_StoC::ERASE_SINGLE, indexToErase);
});
@ -122,18 +119,18 @@ namespace NetworkingObjects {
l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [indexToErase = p->pos](const NetObjPtr<NetObjOrderedList<T>>&, cereal::PortableBinaryOutputArchive& a) {
a(ObjPtrOrderedListCommand_StoC::ERASE_SINGLE, indexToErase);
});
data.erase(data.begin() + p->pos);
set_positions_for_object_info_vector<T>(data, p->pos);
uint32_t iToErase = p->pos; // We only have a reference to the pointer, so erasing it might destroy the pointer object. Save the index before erasing
data.erase(data.begin() + iToErase);
set_positions_for_object_info_vector<T>(data, iToErase);
}
virtual void write_constructor(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryOutputArchive& a) override {
}
virtual void read_constructor(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c) override {
virtual void read_constructor_post_allocation(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c) override {
}
virtual void read_update(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c) override {
ObjPtrOrderedListCommand_CtoS command;
a(command);
switch(command) {
//cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& clientReceivedFrom
case ObjPtrOrderedListCommand_CtoS::INSERT_SINGLE:
uint32_t newPos;
a(newPos);
@ -142,7 +139,13 @@ namespace NetworkingObjects {
case ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE:
NetObjID idToErase;
a(idToErase);
insert(l, newPos, l.get_obj_man()->template read_create_message<T>(a, c));
std::erase_if(data, [&](NetObjOrderedListObjectInfoPtr<T>& o) {
if(o->obj.get_net_id() == idToErase) {
erase_by_ptr(l, o);
return true;
}
return false;
});
break;
}
}
@ -169,20 +172,39 @@ namespace NetworkingObjects {
virtual void insert(const NetObjPtr<NetObjOrderedList<T>>& l, uint32_t posToInsertAt, const NetObjPtr<T>& newObj) {
}
virtual void erase_by_index(const NetObjPtr<NetObjOrderedList<T>>& l, uint32_t indexToErase) override {
indexToErase = std::min<uint32_t>(indexToErase, clientData.size());
auto& newObjInfoPtr = clientData[indexToErase];
l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [&newObjInfoPtr](const NetObjPtr<NetObjOrderedList<T>>&, cereal::PortableBinaryOutputArchive& a) {
a(ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE, newObjInfoPtr->obj.get_net_id());
});
clientData.erase(clientData.begin() + indexToErase);
set_positions_for_object_info_vector<T>(clientData, indexToErase);
}
virtual void erase_by_ptr(const NetObjPtr<NetObjOrderedList<T>>& l, const NetObjOrderedListObjectInfoPtr<T>& p) override {
l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [&p](const NetObjPtr<NetObjOrderedList<T>>&, cereal::PortableBinaryOutputArchive& a) {
a(ObjPtrOrderedListCommand_CtoS::ERASE_SINGLE, p->obj.get_net_id());
});
uint32_t iToErase = p->pos;
clientData.erase(clientData.begin() + iToErase);
set_positions_for_object_info_vector<T>(clientData, iToErase);
}
virtual void write_constructor(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryOutputArchive& a) override {
}
virtual void read_constructor(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) override {
virtual void read_constructor_post_allocation(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) override {
}
virtual void read_update(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) override {
ObjPtrOrderedListCommand_StoC c;
a(c);
switch(c) {
case ObjPtrOrderedListCommand_StoC::INSERT_SINGLE:
uint32_t newPos;
a(newPos);
serverData.insert(serverData.begin() + newPos, std::make_shared<NetObjOrderedListObjectInfo<T>>(l.get_obj_man()->template read_create_message<T>(a, nullptr), newPos, false));
break;
case ObjPtrOrderedListCommand_StoC::ERASE_SINGLE:
uint32_t posToErase;
a(posToErase);
serverData.erase(serverData.begin() + posToErase);
break;
}
}
@ -191,8 +213,14 @@ namespace NetworkingObjects {
std::vector<NetObjOrderedListObjectInfoPtr<T>> clientData;
};
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>>();
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>, NetObjOrderedListClient<S>, NetObjOrderedListServer<S>>({
t.register_class<NetObjOrderedList<S>, NetObjOrderedList<S>>({
.writeConstructorFuncClient = NetObjOrderedList<S>::write_constructor_func,
.readConstructorFuncClient = NetObjOrderedList<S>::read_constructor_func,
.readUpdateFuncClient = NetObjOrderedList<S>::read_update_func,

View file

@ -90,7 +90,7 @@ namespace NetworkingObjects {
}
template <typename T> void NetObjPtr<T>::write_create_message(cereal::PortableBinaryOutputArchive& a) const {
auto& typeIndexData = objMan->isServer ? objMan->typeList->typeIndexDataServer[std::type_index(typeid(T))] : objMan->typeList->typeIndexDataClient[std::type_index(typeid(T))];
auto& typeIndexData = objMan->isServer ? objMan->typeList->typeIndexDataServer[std::type_index(typeid(T*))] : objMan->typeList->typeIndexDataClient[std::type_index(typeid(T*))];
a(id, typeIndexData.netTypeID);
typeIndexData.writeConstructorFunc(this->cast<void>(), a);
}