2025-12-06 14:16:50 +03:00
# pragma once
# include <compare>
# include <memory>
# include <unordered_map>
# include <functional>
# include <cereal/archives/portable_binary.hpp>
# include <chrono>
# include <vector>
2025-12-08 14:28:01 +03:00
# include <Helpers/Random.hpp>
2025-12-06 14:16:50 +03:00
# include "../Networking/NetClient.hpp"
# include "../Networking/NetServer.hpp"
# include "../Networking/NetLibrary.hpp"
2025-12-08 14:28:01 +03:00
# include "Helpers/NetworkingObjects/NetObjID.hpp"
2025-12-06 14:16:50 +03:00
# include "NetObjManagerTypeList.hpp"
2025-12-11 16:05:41 +03:00
# include "NetObjOwnerPtr.decl.hpp"
# include "NetObjTemporaryPtr.decl.hpp"
2025-12-07 17:35:27 +03:00
# include "../Networking/NetServer.hpp"
2025-12-06 14:16:50 +03:00
namespace NetworkingObjects {
class NetObjManager {
public :
2025-12-13 13:03:27 +03:00
NetObjManager ( bool initIsServer ) ;
2025-12-07 17:35:27 +03:00
void read_update_message ( cereal : : PortableBinaryInputArchive & a , const std : : shared_ptr < NetServer : : ClientData > & clientReceivedFrom ) ;
2025-12-06 14:16:50 +03:00
void set_client ( std : : shared_ptr < NetClient > initClient , MessageCommandType initUpdateCommandID ) ;
void set_server ( std : : shared_ptr < NetServer > initServer , MessageCommandType initUpdateCommandID ) ;
2025-12-17 15:50:14 +03:00
void disconnect ( ) ;
2025-12-07 23:09:17 +03:00
bool is_server ( ) const ;
2025-12-11 16:05:41 +03:00
template < typename T > NetObjOwnerPtr < T > read_create_message ( cereal : : PortableBinaryInputArchive & a , const std : : shared_ptr < NetServer : : ClientData > & clientReceivedFrom ) {
2025-12-06 14:16:50 +03:00
NetObjID id ;
2025-12-09 13:00:38 +03:00
a ( id ) ;
2025-12-11 16:05:41 +03:00
auto it = objectData . find ( id ) ;
if ( it ! = objectData . end ( ) )
throw std : : runtime_error ( " [NetObjManager::read_create_message] Attempted to create an object with a used ID " ) ;
2025-12-13 13:03:27 +03:00
NetObjOwnerPtr < T > newPtr = emplace_raw_ptr ( id , static_cast < T * > ( typeList . get_type_index_data < T > ( isServer ) . allocatorFunc ( ) ) ) ;
typeList . get_type_index_data < T > ( isServer ) . readConstructorFunc ( NetObjTemporaryPtr ( newPtr ) . template cast < void > ( ) , a , clientReceivedFrom ) ;
2025-12-08 22:21:07 +03:00
return newPtr ;
2025-12-06 14:16:50 +03:00
}
2025-12-20 16:38:51 +03:00
template < typename T > NetObjTemporaryPtr < T > read_get_obj_temporary_ref_from_message ( cereal : : PortableBinaryInputArchive & a ) {
2025-12-06 14:16:50 +03:00
NetObjID id ;
a ( id ) ;
auto it = objectData . find ( id ) ;
if ( it = = objectData . end ( ) )
2025-12-11 22:41:53 +03:00
return NetObjTemporaryPtr < T > ( ) ;
return NetObjTemporaryPtr < T > ( this , id , std : : static_pointer_cast < T > ( it - > second . p ) ) ;
2025-12-06 14:16:50 +03:00
}
2025-12-16 12:02:08 +03:00
// NOTE: DO NOT USE THESE FUNCTIONS UNLESS SITUATION ISN'T NORMAL, EVERY OBJECT SHOULD HAVE A UNIQUE ID AND IDS SHOULDNT BE REUSED UNDER ANY CIRCUMSTANCES
template < typename T > NetObjOwnerPtr < T > make_obj_with_specific_id ( const NetObjID & id ) {
return emplace_raw_ptr < T > ( id , static_cast < T * > ( typeList . get_type_index_data < T > ( isServer ) . allocatorFunc ( ) ) ) ;
}
template < typename T , typename . . . Args > NetObjOwnerPtr < T > make_obj_direct_with_specific_id ( const NetObjID & id , Args & & . . . items ) {
return emplace_raw_ptr < T > ( id , new T ( items . . . ) ) ;
}
2025-12-11 16:05:41 +03:00
template < typename T > NetObjOwnerPtr < T > make_obj ( ) {
2025-12-13 13:03:27 +03:00
return emplace_raw_ptr < T > ( NetObjID : : random_gen ( ) , static_cast < T * > ( typeList . get_type_index_data < T > ( isServer ) . allocatorFunc ( ) ) ) ;
2025-12-08 20:51:11 +03:00
}
// Don't use this function unless you're sure that class T isn't a base class
2025-12-11 16:05:41 +03:00
template < typename T , typename . . . Args > NetObjOwnerPtr < T > make_obj_direct ( Args & & . . . items ) {
return emplace_raw_ptr < T > ( NetObjID : : random_gen ( ) , new T ( items . . . ) ) ;
2025-12-06 14:16:50 +03:00
}
2025-12-15 15:36:42 +03:00
template < typename T > NetObjOwnerPtr < T > make_obj_from_ptr ( T * p ) {
2025-12-11 16:05:41 +03:00
return emplace_raw_ptr < T > ( NetObjID : : random_gen ( ) , p ) ;
2025-12-06 14:16:50 +03:00
}
2025-12-16 12:02:08 +03:00
template < typename T > NetObjTemporaryPtr < T > get_obj_temporary_ref_from_id ( NetObjID id ) {
auto it = objectData . find ( id ) ;
if ( it = = objectData . end ( ) )
return NetObjTemporaryPtr < T > ( ) ;
return NetObjTemporaryPtr < T > ( this , id , static_cast < T * > ( it - > second . p ) ) ;
}
2025-12-13 13:03:27 +03:00
template < typename ClientT , typename ServerT , typename ClientAllocatedType , typename ServerAllocatedType > void register_class ( const NetObjManagerTypeList : : ServerClientClassFunctions < ClientT , ServerT > & funcs ) {
typeList . register_class < ClientT , ServerT , ClientAllocatedType , ServerAllocatedType > ( funcs ) ;
}
2025-12-06 14:16:50 +03:00
private :
2025-12-11 16:05:41 +03:00
template < typename T > NetObjOwnerPtr < T > emplace_raw_ptr ( NetObjID id , T * rawPtr ) {
2025-12-13 13:03:27 +03:00
if ( ! objectData . emplace ( id , SingleObjectData { . netTypeID = typeList . get_type_index_data < T > ( isServer ) . netTypeID , . p = rawPtr } ) . second )
2025-12-11 16:05:41 +03:00
throw std : : runtime_error ( " [NetObjManager::emplace_raw_ptr] ID Collision " ) ;
return NetObjOwnerPtr < T > ( this , id , rawPtr ) ;
}
template < typename T > static void send_update_to_all ( const NetObjTemporaryPtr < T > & ptr , const std : : string & channel , std : : function < void ( const NetObjTemporaryPtr < T > & , cereal : : PortableBinaryOutputArchive & ) > sendUpdateFunc ) {
if ( ptr . get_obj_man ( ) - > isServer )
NetObjManager : : send_server_update_to_all_clients ( ptr , channel , sendUpdateFunc ) ;
else
NetObjManager : : send_client_update ( ptr , channel , sendUpdateFunc ) ;
}
template < typename T > static void send_client_update ( const NetObjTemporaryPtr < T > & ptr , const std : : string & channel , std : : function < void ( const NetObjTemporaryPtr < T > & , cereal : : PortableBinaryOutputArchive & ) > sendUpdateFunc ) {
if ( ptr . get_obj_man ( ) - > client & & ! ptr . get_obj_man ( ) - > client - > is_disconnected ( ) ) {
auto ss ( std : : make_shared < std : : stringstream > ( ) ) ;
{
cereal : : PortableBinaryOutputArchive m ( * ss ) ;
m ( ptr . get_obj_man ( ) - > updateCommandID , ptr . get_net_id ( ) ) ;
sendUpdateFunc ( ptr , m ) ;
}
ptr . get_obj_man ( ) - > client - > send_string_stream_to_server ( channel , ss ) ;
}
}
template < typename T > static void send_server_update_to_client ( const NetObjTemporaryPtr < T > & ptr , const std : : shared_ptr < NetServer : : ClientData > & clientToSendTo , const std : : string & channel , std : : function < void ( const NetObjTemporaryPtr < T > & , cereal : : PortableBinaryOutputArchive & ) > sendUpdateFunc ) {
if ( ptr . get_obj_man ( ) - > server & & ! ptr . get_obj_man ( ) - > server - > is_disconnected ( ) ) {
auto ss ( std : : make_shared < std : : stringstream > ( ) ) ;
{
cereal : : PortableBinaryOutputArchive m ( * ss ) ;
m ( ptr . get_obj_man ( ) - > updateCommandID , ptr . get_net_id ( ) ) ;
sendUpdateFunc ( ptr , m ) ;
}
ptr . get_obj_man ( ) - > server - > send_string_stream_to_client ( clientToSendTo , channel , ss ) ;
}
}
template < typename T > static void send_server_update_to_all_clients_except ( const NetObjTemporaryPtr < T > & ptr , const std : : shared_ptr < NetServer : : ClientData > & clientToNotSendTo , const std : : string & channel , std : : function < void ( const NetObjTemporaryPtr < T > & , cereal : : PortableBinaryOutputArchive & ) > sendUpdateFunc ) {
if ( ptr . get_obj_man ( ) - > server & & ! ptr . get_obj_man ( ) - > server - > is_disconnected ( ) ) {
auto ss ( std : : make_shared < std : : stringstream > ( ) ) ;
{
cereal : : PortableBinaryOutputArchive m ( * ss ) ;
m ( ptr . get_obj_man ( ) - > updateCommandID , ptr . get_net_id ( ) ) ;
sendUpdateFunc ( ptr , m ) ;
}
ptr . get_obj_man ( ) - > server - > send_string_stream_to_all_clients_except ( clientToNotSendTo , channel , ss ) ;
}
}
template < typename T > static void send_server_update_to_all_clients ( const NetObjTemporaryPtr < T > & ptr , const std : : string & channel , std : : function < void ( const NetObjTemporaryPtr < T > & , cereal : : PortableBinaryOutputArchive & ) > sendUpdateFunc ) {
if ( ptr . get_obj_man ( ) - > server & & ! ptr . get_obj_man ( ) - > server - > is_disconnected ( ) ) {
auto ss ( std : : make_shared < std : : stringstream > ( ) ) ;
{
cereal : : PortableBinaryOutputArchive m ( * ss ) ;
m ( ptr . get_obj_man ( ) - > updateCommandID , ptr . get_net_id ( ) ) ;
sendUpdateFunc ( ptr , m ) ;
}
ptr . get_obj_man ( ) - > server - > send_string_stream_to_all_clients ( channel , ss ) ;
}
2025-12-09 13:00:38 +03:00
}
2025-12-11 16:05:41 +03:00
template < typename T > static void write_create_message ( const NetObjTemporaryPtr < T > & ptr , cereal : : PortableBinaryOutputArchive & a ) {
2025-12-11 22:41:53 +03:00
a ( ptr . get_net_id ( ) ) ;
2025-12-13 13:03:27 +03:00
ptr . get_obj_man ( ) - > typeList . template get_type_index_data < T > ( ptr . get_obj_man ( ) - > isServer ) . writeConstructorFunc ( ptr . template cast < void > ( ) , a ) ;
2025-12-08 22:21:07 +03:00
}
2025-12-11 16:05:41 +03:00
template < typename T > friend class NetObjOwnerPtr ;
template < typename T > friend class NetObjTemporaryPtr ;
2025-12-10 13:06:45 +03:00
template < typename T > friend class NetObjWeakPtr ;
2025-12-06 14:16:50 +03:00
struct SingleObjectData {
NetTypeIDType netTypeID ;
2025-12-11 16:05:41 +03:00
void * p ;
2025-12-06 14:16:50 +03:00
} ;
2025-12-09 13:00:38 +03:00
2025-12-07 17:35:27 +03:00
bool isServer ;
2025-12-06 14:16:50 +03:00
std : : shared_ptr < NetClient > client ;
std : : shared_ptr < NetServer > server ;
MessageCommandType updateCommandID ;
std : : unordered_map < NetObjID , SingleObjectData > objectData ;
2025-12-13 13:03:27 +03:00
NetObjManagerTypeList typeList ;
2025-12-06 14:16:50 +03:00
NetTypeIDType nextTypeID ;
} ;
}