#pragma once #include "Helpers/Networking/NetLibrary.hpp" #include "Helpers/NetworkingObjects/NetObjOwnerPtr.decl.hpp" #include "NetObjOwnerPtr.hpp" #include "NetObjTemporaryPtr.hpp" #include "NetObjWeakPtr.hpp" #include "NetObjID.hpp" #include #include #include "NetObjManagerTypeList.hpp" #include namespace NetworkingObjects { enum class ObjPtrUnorderedSetCommand_StoC : uint8_t { INSERT_SINGLE_CONSTRUCT, ERASE_SINGLE }; enum class ObjPtrUnorderedSetCommand_CtoS : uint8_t { INSERT_SINGLE, ERASE_SINGLE }; template class NetObjUnorderedSet { public: // Don't use this function unless you're sure that class T isn't a base class template NetObjTemporaryPtr emplace_direct(const NetObjTemporaryPtr>& l, Args&&... items) { NetObjOwnerPtr newObj = l.get_obj_man()->template make_obj_direct(items...); return l->insert(l, nullptr, std::move(newObj)); } static NetObjTemporaryPtr insert_and_send_create(const NetObjTemporaryPtr>& l, T* newObj) { NetObjOwnerPtr newObjOwner = l.get_obj_man()->template make_obj_from_ptr(newObj); return l->insert(l, nullptr, std::move(newObjOwner)); } static bool erase(const NetObjTemporaryPtr>& l, const NetObjID& id) { return l->erase_by_id(l, id); } typedef std::function& objPtr)> InsertCallback; typedef std::function& objPtr)> EraseCallback; void set_insert_callback(const InsertCallback& func) { insertCallback = func; } void set_erase_callback(const EraseCallback& func) { eraseCallback = func; } bool contains(const NetObjID& p) const { return std::find_if(data.begin(), data.end(), [&p](const NetObjOwnerPtr& o){ return o.get_net_id() == p; }) != data.end(); } const std::vector>& get_data() const { return data; } uint32_t size() const { return data.size(); } bool empty() const { return data.empty(); } virtual ~NetObjUnorderedSet() {} protected: NetObjTemporaryPtr insert(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, NetObjOwnerPtr newObj) { auto& objAdded = this->data.emplace_back(std::move(newObj)); insert_network(l, clientInserting, objAdded); call_insert_callback(objAdded); return objAdded; } bool erase_by_id(const NetObjTemporaryPtr>& l, const NetObjID& id) { auto it = std::find_if(this->data.begin(), this->data.end(), [&id](const NetObjOwnerPtr& o){ return o.get_net_id() == id; }); if(it == this->data.end()) return false; call_erase_callback(*it); erase_network(l, id); data.erase(it); return true; } virtual void insert_network(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, const NetObjOwnerPtr& newObj) const = 0; virtual void erase_network(const NetObjTemporaryPtr>& l, const NetObjID& id) const = 0; virtual void read_update(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) = 0; void write_constructor(const NetObjTemporaryPtr>& l, cereal::PortableBinaryOutputArchive& a) { a(static_cast(data.size())); for(size_t i = 0; i < data.size(); i++) data[i].write_create_message(a); } void read_constructor(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { uint32_t newDataSize; a(newDataSize); for(size_t i = 0; i < newDataSize; i++) data.emplace_back(l.get_obj_man()->template read_create_message(a, c)); } // Call after inserting void call_insert_callback(const NetObjOwnerPtr& objPtr) { if(insertCallback) insertCallback(objPtr); } // Call before erasing void call_erase_callback(const NetObjOwnerPtr& objPtr) { if(eraseCallback) eraseCallback(objPtr); } std::vector> data; private: InsertCallback insertCallback; EraseCallback eraseCallback; template friend void register_unordered_set_class(NetObjManager& t); static void write_constructor_func(const NetObjTemporaryPtr>& l, cereal::PortableBinaryOutputArchive& a) { l->write_constructor(l, a); } static void read_constructor_func(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { l->read_constructor(l, a, c); } static void read_update_func(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { l->read_update(l, a, c); } }; template class NetObjUnorderedSetServer : public NetObjUnorderedSet { public: NetObjUnorderedSetServer() {} protected: virtual void insert_network(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, const NetObjOwnerPtr& newObj) const override { l.send_server_update_to_all_clients_except(clientInserting, RELIABLE_COMMAND_CHANNEL, [&newObj](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrUnorderedSetCommand_StoC::INSERT_SINGLE_CONSTRUCT); newObj.write_create_message(a); }); } virtual void erase_network(const NetObjTemporaryPtr>& l, const NetObjID& id) const override { l.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [id](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrUnorderedSetCommand_StoC::ERASE_SINGLE, id); }); } virtual void read_update(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) override { ObjPtrUnorderedSetCommand_CtoS command; a(command); switch(command) { case ObjPtrUnorderedSetCommand_CtoS::INSERT_SINGLE: { NetObjUnorderedSet::insert(l, c, l.get_obj_man()->template read_create_message(a, c)); break; } case ObjPtrUnorderedSetCommand_CtoS::ERASE_SINGLE: { NetObjID idToErase; a(idToErase); NetObjUnorderedSet::erase_by_id(l, idToErase); break; } } } }; template class NetObjUnorderedSetClient : public NetObjUnorderedSet { public: NetObjUnorderedSetClient() {} protected: virtual void insert_network(const NetObjTemporaryPtr>& l, const std::shared_ptr&, const NetObjOwnerPtr& newObj) const override { l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&newObj](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrUnorderedSetCommand_CtoS::INSERT_SINGLE); newObj.write_create_message(a); }); } virtual void erase_network(const NetObjTemporaryPtr>& l, const NetObjID& id) const override { l.send_client_update(RELIABLE_COMMAND_CHANNEL, [id](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrUnorderedSetCommand_CtoS::ERASE_SINGLE, id); }); } virtual void read_update(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) override { ObjPtrUnorderedSetCommand_StoC command; a(command); switch(command) { case ObjPtrUnorderedSetCommand_StoC::INSERT_SINGLE_CONSTRUCT: { this->data.emplace_back(l.get_obj_man()->template read_create_message(a, c)); break; } case ObjPtrUnorderedSetCommand_StoC::ERASE_SINGLE: { NetObjID id; a(id); auto it = std::find_if(this->data.begin(), this->data.end(), [&id](const NetObjOwnerPtr& o){ return o.get_net_id() == id; }); if(it != this->data.end()) this->data.erase(it); break; } } } }; template void register_unordered_set_class(NetObjManager& objMan) { objMan.register_class, NetObjUnorderedSet, NetObjUnorderedSetClient, NetObjUnorderedSetServer>({ .writeConstructorFuncClient = NetObjUnorderedSet::write_constructor_func, .readConstructorFuncClient = NetObjUnorderedSet::read_constructor_func, .readUpdateFuncClient = NetObjUnorderedSet::read_update_func, .writeConstructorFuncServer = NetObjUnorderedSet::write_constructor_func, .readConstructorFuncServer = NetObjUnorderedSet::read_constructor_func, .readUpdateFuncServer = NetObjUnorderedSet::read_update_func, }); } }