Objects are sent with correct IDs over network

This commit is contained in:
Yousef Khadadeh 2025-12-08 22:21:07 +03:00
parent d9a90dda16
commit c51b7e7eb1
6 changed files with 51 additions and 31 deletions

View file

@ -7,10 +7,8 @@ namespace NetworkingObjects {
.writeConstructorFuncClient = [](const NetObjPtr<T>& o, cereal::PortableBinaryOutputArchive& a) {
a(*o);
},
.readConstructorFuncClient = [](NetObjManager& m, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) {
NetObjPtr<T> o = m.make_obj<T>();
.readConstructorFuncClient = [](const NetObjPtr<T>& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) {
a(*o);
return o.template cast<void>();
},
.readUpdateFuncClient = [](const NetObjPtr<T>& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) {
a(*o);
@ -18,10 +16,8 @@ namespace NetworkingObjects {
.writeConstructorFuncServer = [](const NetObjPtr<T>& o, cereal::PortableBinaryOutputArchive& a) {
a(*o);
},
.readConstructorFuncServer = [](NetObjManager& m, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) {
NetObjPtr<T> o = m.make_obj<T>();
.readConstructorFuncServer = [](const NetObjPtr<T>& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) {
a(*o);
return o.template cast<void>();
},
.readUpdateFuncServer = [](const NetObjPtr<T>& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) {
a(*o);

View file

@ -28,10 +28,12 @@ namespace NetworkingObjects {
NetTypeIDType typeID;
a(id, typeID);
auto& netTypeIDData = typeList->netTypeIDData[typeID];
NetObjPtr<T> newPtr = make_obj_with_id<T>(id);
if(isServer)
return netTypeIDData.readConstructorFuncServer(*this, a, clientReceivedFrom).cast<T>();
netTypeIDData.readConstructorFuncServer(newPtr.template cast<void>(), a, clientReceivedFrom);
else
return netTypeIDData.readConstructorFuncClient(*this, a, clientReceivedFrom).cast<T>();
netTypeIDData.readConstructorFuncClient(newPtr.template cast<void>(), a, clientReceivedFrom);
return newPtr;
}
template <typename T> NetObjPtr<T> read_get_obj_from_message(cereal::PortableBinaryInputArchive& a) {
NetObjID id;
@ -70,6 +72,13 @@ namespace NetworkingObjects {
return NetObjPtr<T>(this, id, std::static_pointer_cast<T>(it->second.p));
}
private:
template <typename T> NetObjPtr<T> make_obj_with_id(NetObjID id) {
auto sharedPtr = std::static_pointer_cast<T>(isServer ? typeList->typeIndexDataServer[std::type_index(typeid(T*))].allocatorFunc() : typeList->typeIndexDataClient[std::type_index(typeid(T*))].allocatorFunc());
if(!objectData.emplace(id, 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, id, sharedPtr);
}
template <typename T> friend class NetObjPtr;
struct SingleObjectData {

View file

@ -10,21 +10,27 @@ class NetObjManagerTypeList {
public:
template <typename ClientT, typename ServerT> struct ServerClientClassFunctions {
std::function<void(const NetObjPtr<ClientT>&, cereal::PortableBinaryOutputArchive&)> writeConstructorFuncClient;
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>&)> 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<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>&)> readConstructorFuncServer;
std::function<void(const NetObjPtr<ServerT>&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readUpdateFuncServer;
};
template <typename ClientT, typename ServerT, typename ClientAllocatedType, typename ServerAllocatedType> void register_class(const ServerClientClassFunctions<ClientT, ServerT>& funcs) {
netTypeIDData[nextNetTypeID] = NetTypeIDContainer {
.readConstructorFuncClient = funcs.readConstructorFuncClient,
.readConstructorFuncClient = [f = funcs.readConstructorFuncClient](const NetObjPtr<void>& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr<NetServer::ClientData>& c) {
if(f)
f(obj.cast<ClientT>(), message, c);
},
.readUpdateFuncClient = [f = funcs.readUpdateFuncClient](const NetObjPtr<void>& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr<NetServer::ClientData>& c) {
if(f)
f(obj.cast<ClientT>(), message, c);
},
.readConstructorFuncServer = funcs.readConstructorFuncServer,
.readConstructorFuncServer = [f = funcs.readConstructorFuncServer](const NetObjPtr<void>& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr<NetServer::ClientData>& c) {
if(f)
f(obj.cast<ServerT>(), message, c);
},
.readUpdateFuncServer = [f = funcs.readUpdateFuncServer](const NetObjPtr<void>& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr<NetServer::ClientData>& c) {
if(f)
f(obj.cast<ServerT>(), message, c);
@ -61,10 +67,10 @@ class NetObjManagerTypeList {
std::unordered_map<std::type_index, TypeIndexContainer> typeIndexDataServer;
struct NetTypeIDContainer {
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>&)> readConstructorFuncClient;
std::function<void(const NetObjPtr<void>&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readUpdateFuncClient;
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>&)> readConstructorFuncServer;
std::function<void(const NetObjPtr<void>&, cereal::PortableBinaryInputArchive&, const std::shared_ptr<NetServer::ClientData>&)> readUpdateFuncServer;
};
std::unordered_map<NetTypeIDType, NetTypeIDContainer> netTypeIDData;

View file

@ -75,13 +75,15 @@ 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_post_allocation(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;
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 NetObjPtr<void> read_constructor_func(NetObjManager& objMan, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c);
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 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);
}
@ -133,7 +135,7 @@ namespace NetworkingObjects {
for(size_t i = 0; i < data.size(); i++)
data[i]->obj.write_create_message(a);
}
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_constructor(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c) override {
uint32_t constructedSize;
a(constructedSize);
data.clear();
@ -215,7 +217,7 @@ namespace NetworkingObjects {
for(size_t i = 0; i < clientData.size(); i++)
clientData[i]->obj.write_create_message(a);
}
virtual void read_constructor_post_allocation(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) override {
virtual void read_constructor(const NetObjPtr<NetObjOrderedList<T>>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>&) override {
uint32_t constructedSize;
a(constructedSize);
clientData.clear();
@ -245,12 +247,6 @@ 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.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>, NetObjOrderedListClient<S>, NetObjOrderedListServer<S>>({
.writeConstructorFuncClient = NetObjOrderedList<S>::write_constructor_func,

View file

@ -69,7 +69,13 @@ MainServer::MainServer(World& initWorld, const std::string& serverLocalID):
if(isDirectConnect)
netServer->send_items_to_client(client, RELIABLE_COMMAND_CHANNEL, CLIENT_INITIAL_DATA, isDirectConnect, newClient.serverID, newClient.cursorColor);
else {
netServer->send_items_to_client(client, RELIABLE_COMMAND_CHANNEL, CLIENT_INITIAL_DATA, isDirectConnect, newClient.serverID, newClient.cursorColor, newClient.displayName, newClient.camCoords, newClient.windowSize, fileDisplayName, clients, data);
auto ss(std::make_shared<std::stringstream>());
{
cereal::PortableBinaryOutputArchive a(*ss);
a(CLIENT_INITIAL_DATA, isDirectConnect, newClient.serverID, newClient.cursorColor, newClient.displayName, newClient.camCoords, newClient.windowSize, fileDisplayName, clients, data);
world.stringListTest.write_create_message(a);
}
netServer->send_string_stream_to_client(client, RELIABLE_COMMAND_CHANNEL, ss);
for(auto& [id, rData] : data.resources) {
netServer->send_items_to_client(client, RESOURCE_COMMAND_CHANNEL, CLIENT_NEW_RESOURCE_ID, id);
netServer->send_items_to_client(client, RESOURCE_COMMAND_CHANNEL, CLIENT_NEW_RESOURCE_DATA, rData);

View file

@ -3,6 +3,7 @@
#include "Helpers/HsvRgb.hpp"
#include "Helpers/MathExtras.hpp"
#include "Helpers/Networking/ByteStream.hpp"
#include "Helpers/NetworkingObjects/NetObjManager.hpp"
#include "Helpers/VersionNumber.hpp"
#include "Server/CommandList.hpp"
#include "MainProgram.hpp"
@ -71,12 +72,14 @@ World::World(MainProgram& initMain, OpenWorldInfo& worldInfo):
con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_INITIAL_DATA, displayName, false);
using namespace NetworkingObjects;
stringListTest = netObjMan.make_obj<NetObjOrderedList<std::string>>();
stringListTest->emplace_back_direct(stringListTest, "Hello");
stringListTest->emplace_back_direct(stringListTest, "World");
stringListTest->emplace_back_direct(stringListTest, "Test");
for(const NetObjOrderedListObjectInfoPtr<std::string>& o : stringListTest->get_data())
std::cout << "At position: " << o->get_pos() << " we have string: \"" << *o->get_obj() << "\" with object id " << o->get_obj().get_net_id().to_string() << std::endl;
if(netObjMan.is_server()) {
stringListTest = netObjMan.make_obj<NetObjOrderedList<std::string>>();
stringListTest->emplace_back_direct(stringListTest, "Hello");
stringListTest->emplace_back_direct(stringListTest, "World");
stringListTest->emplace_back_direct(stringListTest, "Test");
for(const NetObjOrderedListObjectInfoPtr<std::string>& o : stringListTest->get_data())
std::cout << "At position: " << o->get_pos() << " we have string: \"" << *o->get_obj() << "\" with object id " << o->get_obj().get_net_id().to_string() << std::endl;
}
}
void World::init_client_callbacks() {
@ -96,6 +99,10 @@ void World::init_client_callbacks() {
message(canvasScale);
drawProg.initialize_draw_data(message);
message(bMan, gridMan);
stringListTest = netObjMan.read_create_message<NetworkingObjects::NetObjOrderedList<std::string>>(message, nullptr);
std::cout << "Client print: " << std::endl;
for(const NetworkingObjects::NetObjOrderedListObjectInfoPtr<std::string>& o : stringListTest->get_data())
std::cout << "At position: " << o->get_pos() << " we have string: \"" << *o->get_obj() << "\" with object id " << o->get_obj().get_net_id().to_string() << std::endl;
}
nextClientID = get_max_id(ownID);
clientStillConnecting = false;