2026-05-11 23:06:39 +03:00
/*
* InfiniPaint
* Copyright ( C ) 2025 - 2026 Yousef Khadadeh
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < https : //www.gnu.org/licenses/>.
*/
2025-12-07 17:35:27 +03:00
# pragma once
# include "Helpers/Networking/NetLibrary.hpp"
2025-12-11 16:05:41 +03:00
# include "NetObjOwnerPtr.hpp"
# include "NetObjTemporaryPtr.hpp"
2025-12-13 17:56:07 +03:00
# include "NetObjWeakPtr.hpp"
2025-12-08 14:28:01 +03:00
# include "NetObjID.hpp"
2025-12-13 17:56:07 +03:00
# include <cereal/archives/portable_binary.hpp>
# include <cereal/types/unordered_set.hpp>
# include <cereal/types/vector.hpp>
2025-12-07 17:35:27 +03:00
# include "NetObjManagerTypeList.hpp"
2025-12-13 17:56:07 +03:00
# include <limits>
2025-12-30 19:46:08 +03:00
# include <list>
2025-12-07 17:35:27 +03:00
2026-01-05 12:43:40 +03:00
//#define ENABLE_NETOBJ_ORDERED_LIST_VERBOSE_DEBUG
# ifdef ENABLE_NETOBJ_ORDERED_LIST_VERBOSE_DEBUG
# define NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(data, idMap) netobj_ordered_list_debug_check(data, idMap)
2026-01-05 22:01:54 +03:00
# define NETOBJ_CHECK_INSERT_ORDERED(data, newObjs) netobj_check_insert_is_ordered(data, newObjs)
2026-01-05 12:43:40 +03:00
# else
# define NETOBJ_ORDERED_LIST_VERBOSE_DEBUG(data, idMap)
2026-01-05 22:01:54 +03:00
# define NETOBJ_CHECK_INSERT_ORDERED(data, newObjs)
2026-01-05 12:43:40 +03:00
# endif
2025-12-07 17:35:27 +03:00
namespace NetworkingObjects {
enum class ObjPtrOrderedListCommand_StoC : uint8_t {
2025-12-30 19:46:08 +03:00
INSERT_LIST_CONSTRUCT ,
INSERT_LIST_REFERENCE ,
ERASE_ID_LIST
2025-12-07 17:35:27 +03:00
} ;
enum class ObjPtrOrderedListCommand_CtoS : uint8_t {
2025-12-30 19:46:08 +03:00
INSERT_LIST ,
ERASE_ID_LIST
2025-12-07 17:35:27 +03:00
} ;
2025-12-10 10:24:57 +03:00
template < typename T > struct NetObjOrderedListObjectInfo {
2025-12-11 16:05:41 +03:00
NetObjOrderedListObjectInfo ( NetObjOwnerPtr < T > iObj , uint32_t iPos ) :
obj ( std : : move ( iObj ) ) ,
pos ( iPos )
2025-12-10 10:24:57 +03:00
{ }
2025-12-30 19:46:08 +03:00
bool operator < ( NetObjOrderedListObjectInfo & other ) const {
return pos < other . pos ;
}
2025-12-10 10:24:57 +03:00
NetObjOrderedListObjectInfo ( ) = delete ;
2025-12-11 16:05:41 +03:00
NetObjOwnerPtr < T > obj ;
2025-12-10 10:24:57 +03:00
uint32_t pos ;
2025-12-07 17:35:27 +03:00
} ;
2025-12-30 19:46:08 +03:00
template < typename T > using NetObjOrderedListIterator = std : : list < NetObjOrderedListObjectInfo < T > > : : iterator ;
template < typename T > using NetObjOrderedListConstIterator = std : : list < NetObjOrderedListObjectInfo < T > > : : const_iterator ;
2025-12-07 17:35:27 +03:00
2025-12-30 19:46:08 +03:00
template < typename T > void set_position_obj_info_list ( NetObjOrderedListIterator < T > start , NetObjOrderedListIterator < T > end ) {
if ( start = = end )
return ;
uint32_t i = start - > pos ;
for ( ; start ! = end ; + + start ) {
start - > pos = i ;
+ + i ;
}
2025-12-07 17:35:27 +03:00
}
2026-01-05 12:43:40 +03:00
# ifdef ENABLE_NETOBJ_ORDERED_LIST_VERBOSE_DEBUG
template < typename T > void netobj_ordered_list_debug_check ( const std : : list < NetObjOrderedListObjectInfo < T > > & l , const std : : unordered_map < NetObjID , NetObjOrderedListIterator < T > > & idMap ) {
uint32_t i = 0 ;
std : : cout < < " [netobj_ordered_list_debug_check] Debug print start \n " ;
for ( auto & o : l ) {
std : : cout < < " Pos " < < o . pos < < " with id " < < o . obj . get_net_id ( ) . to_string ( ) < < ' \n ' ;
if ( o . pos ! = i )
throw std : : runtime_error ( " [netobj_ordered_list_debug_check] Position values are incorrect! " ) ;
+ + i ;
auto it = idMap . find ( o . obj . get_net_id ( ) ) ;
if ( it = = idMap . end ( ) )
throw std : : runtime_error ( " [netobj_ordered_list_debug_check] Could not find element in ID Map! " ) ;
if ( & ( * it - > second ) ! = & o )
throw std : : runtime_error ( " [netobj_ordered_list_debug_check] ID Map and list point to different objects! " ) ;
}
if ( l . size ( ) ! = idMap . size ( ) ) {
std : : cout < < " ID map size: " < < idMap . size ( ) < < " list size: " < < l . size ( ) < < ' \n ' ;
throw std : : runtime_error ( " [netobj_ordered_list_debug_check] ID map and list have different sizes! " ) ;
}
std : : cout < < " [netobj_ordered_list_debug_check] Debug print end " < < std : : endl ;
}
2026-01-05 22:01:54 +03:00
template < typename T > void netobj_check_insert_is_ordered ( const std : : list < NetObjOrderedListObjectInfo < T > > & l , std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > & newObjs ) {
std : : cout < < " [netobj_check_insert_is_ordered] Insert list order check " < < std : : endl ;
uint32_t lastPos = 0 ;
bool isEnd = false ;
for ( auto & [ it , obj ] : newObjs ) {
if ( it = = l . end ( ) ) {
std : : cout < < " [netobj_check_insert_is_ordered] Insert at: " < < l . size ( ) < < " (end) " < < std : : endl ;
isEnd = true ;
}
else {
std : : cout < < " [netobj_check_insert_is_ordered] Insert at: " < < it - > pos < < std : : endl ;
if ( isEnd )
throw std : : runtime_error ( " [netobj_check_insert_is_ordered] Insert list not ordered! (Failure at end) " ) ;
if ( lastPos > it - > pos )
throw std : : runtime_error ( " [netobj_check_insert_is_ordered] Insert list not ordered! " ) ;
lastPos = it - > pos ;
isEnd = false ;
}
}
std : : cout < < " [netobj_check_insert_is_ordered] Insert list is ordered " < < std : : endl ;
}
2026-01-05 12:43:40 +03:00
# endif
template < typename T > void refresh_positions_complete ( std : : list < NetObjOrderedListObjectInfo < T > > & l ) {
uint32_t i = 0 ;
for ( auto & c : l ) {
c . pos = i ;
+ + i ;
}
}
2026-02-10 13:12:53 +03:00
template < typename T > void sort_netobj_ordered_list_iterator_list ( const std : : list < NetObjOrderedListObjectInfo < T > > & l , std : : vector < NetObjOrderedListIterator < T > > & itListToSort ) {
std : : stable_sort ( itListToSort . begin ( ) , itListToSort . end ( ) , [ & l ] ( auto & a , auto & b ) {
return b = = l . end ( ) | | ( a ! = l . end ( ) & & a - > pos < b - > pos ) ;
} ) ;
}
template < typename T > void sort_netobj_ordered_list_iterator_insert_list ( const std : : list < NetObjOrderedListObjectInfo < T > > & l , std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > & itListToSort ) {
std : : stable_sort ( itListToSort . begin ( ) , itListToSort . end ( ) , [ & l ] ( auto & a , auto & b ) {
return b . first = = l . end ( ) | | ( a . first ! = l . end ( ) & & a . first - > pos < b . first - > pos ) ;
} ) ;
}
2025-12-07 17:35:27 +03:00
template < typename T > class NetObjOrderedList {
public :
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-30 19:46:08 +03:00
template < typename . . . Args > NetObjOrderedListIterator < T > emplace_back_direct ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , Args & & . . . items ) {
2026-01-02 10:29:50 +03:00
return l - > insert_single ( l , nullptr , l - > end ( ) , l . get_obj_man ( ) - > template make_obj_direct < T > ( items . . . ) ) ;
2025-12-30 19:46:08 +03:00
}
static NetObjOrderedListIterator < T > push_back_and_send_create ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , T * newObj ) {
2026-01-02 10:29:50 +03:00
return l - > insert_single ( l , nullptr , l - > end ( ) , l . get_obj_man ( ) - > template make_obj_from_ptr < T > ( newObj ) ) ;
2025-12-30 19:46:08 +03:00
}
2026-01-02 21:06:13 +03:00
template < typename . . . Args > NetObjOrderedListIterator < T > emplace_direct ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const NetObjOrderedListIterator < T > & it , Args & & . . . items ) {
return l - > insert_single ( l , nullptr , it , l . get_obj_man ( ) - > template make_obj_direct < T > ( items . . . ) ) ;
}
2025-12-30 19:46:08 +03:00
static NetObjOrderedListIterator < T > insert_and_send_create ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const NetObjOrderedListIterator < T > & it , T * newObj ) {
2026-01-02 10:29:50 +03:00
return l - > insert_single ( l , nullptr , it , l . get_obj_man ( ) - > template make_obj_from_ptr < T > ( newObj ) ) ;
2025-12-30 19:46:08 +03:00
}
2026-02-10 13:12:53 +03:00
static std : : vector < NetObjOrderedListIterator < T > > insert_sorted_list_and_send_create ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const std : : vector < std : : pair < NetObjOrderedListIterator < T > , T * > > & newObjs ) {
if ( newObjs . empty ( ) )
return { } ;
std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > ownerPtrOrderedList ;
for ( uint32_t i = 0 ; i < static_cast < uint32_t > ( newObjs . size ( ) ) ; i + + )
ownerPtrOrderedList . emplace_back ( newObjs [ i ] . first , std : : move ( l . get_obj_man ( ) - > template make_obj_from_ptr < T > ( newObjs [ i ] . second ) ) ) ;
return l - > insert_ordered_list ( l , nullptr , ownerPtrOrderedList ) ;
}
static std : : vector < NetObjOrderedListIterator < T > > insert_sorted_list_and_send_create ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > & newObjPtrs ) {
if ( newObjPtrs . empty ( ) )
return { } ;
return l - > insert_ordered_list ( l , nullptr , newObjPtrs ) ;
}
static std : : vector < NetObjOrderedListIterator < T > > insert_unsorted_list_and_send_create ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const std : : vector < std : : pair < NetObjOrderedListIterator < T > , T * > > & newObjs ) {
2025-12-13 17:56:07 +03:00
if ( newObjs . empty ( ) )
return { } ;
2025-12-30 19:46:08 +03:00
std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > ownerPtrOrderedList ;
2025-12-13 17:56:07 +03:00
for ( uint32_t i = 0 ; i < static_cast < uint32_t > ( newObjs . size ( ) ) ; i + + )
2025-12-15 15:36:42 +03:00
ownerPtrOrderedList . emplace_back ( newObjs [ i ] . first , std : : move ( l . get_obj_man ( ) - > template make_obj_from_ptr < T > ( newObjs [ i ] . second ) ) ) ;
2026-02-10 13:12:53 +03:00
sort_netobj_ordered_list_iterator_insert_list ( l , ownerPtrOrderedList ) ;
2025-12-13 17:56:07 +03:00
return l - > insert_ordered_list ( l , nullptr , ownerPtrOrderedList ) ;
}
2026-02-10 13:12:53 +03:00
static std : : vector < NetObjOrderedListIterator < T > > insert_unsorted_list_and_send_create ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > & newObjPtrs ) {
2025-12-22 11:13:50 +03:00
if ( newObjPtrs . empty ( ) )
return { } ;
2026-02-10 13:12:53 +03:00
sort_netobj_ordered_list_iterator_insert_list ( l , newObjPtrs ) ;
2025-12-22 11:13:50 +03:00
return l - > insert_ordered_list ( l , nullptr , newObjPtrs ) ;
}
2025-12-30 19:46:08 +03:00
static void erase_list ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const std : : vector < NetObjOrderedListIterator < T > > & iterators , std : : vector < NetObjOwnerPtr < T > > * erasedObjects = nullptr ) {
l - > erase_it_list ( l , iterators , erasedObjects ) ;
2025-12-07 17:35:27 +03:00
}
2025-12-30 19:46:08 +03:00
static void erase ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const NetObjOrderedListIterator < T > & it ) {
l - > erase_it_list ( l , { it } , nullptr ) ;
2025-12-07 17:35:27 +03:00
}
2025-12-22 11:13:50 +03:00
virtual void reassign_netobj_ids_call ( ) = 0 ;
2025-12-13 21:41:32 +03:00
2025-12-30 19:46:08 +03:00
typedef std : : function < void ( const NetObjOrderedListIterator < T > & objInfo ) > InsertCallback ;
typedef std : : function < void ( const NetObjOrderedListIterator < T > & objInfo ) > EraseCallback ;
typedef std : : function < void ( const NetObjOrderedListIterator < T > & objInfo , uint32_t oldPos ) > MoveCallback ;
typedef NetObjOrderedListObjectInfo < T > value_type ;
2025-12-13 21:41:32 +03:00
void set_insert_callback ( const InsertCallback & func ) {
insertCallback = func ;
}
void set_erase_callback ( const EraseCallback & func ) {
eraseCallback = func ;
}
void set_move_callback ( const MoveCallback & func ) {
moveCallback = func ;
}
2026-01-03 13:35:24 +03:00
bool contains ( const NetObjID & id ) const {
return data_map ( ) . contains ( id ) ;
}
uint32_t size ( ) const {
return data_list ( ) . size ( ) ;
}
NetObjOrderedListIterator < T > begin ( ) {
return data_list ( ) . begin ( ) ;
}
NetObjOrderedListIterator < T > end ( ) {
return data_list ( ) . end ( ) ;
}
NetObjOrderedListIterator < T > at ( uint32_t index ) {
auto & data = data_list ( ) ;
if ( index > = data . size ( ) )
return data . end ( ) ;
return std : : prev ( data . end ( ) , data . size ( ) - index ) ;
}
std : : vector < NetObjOrderedListIterator < T > > at_ordered_indices ( const std : : vector < uint32_t > & orderedIndices ) {
auto & data = data_list ( ) ;
std : : vector < NetObjOrderedListIterator < T > > toRet ( orderedIndices . size ( ) ) ;
auto lastIt = data . end ( ) ;
uint32_t lastDataIndex = data . size ( ) ;
2026-01-03 19:05:00 +03:00
for ( std : : pair < const uint32_t & , NetObjOrderedListIterator < T > & > p : std : : views : : zip ( orderedIndices , toRet ) | std : : views : : reverse ) {
uint32_t orderedIndex = std : : min < uint32_t > ( p . first , data . size ( ) ) ;
2026-01-03 13:35:24 +03:00
NetObjOrderedListIterator < T > & it = p . second ;
for ( ; ; ) {
2026-01-03 19:05:00 +03:00
if ( orderedIndex = = lastDataIndex ) {
2026-01-03 13:35:24 +03:00
it = lastIt ;
break ;
}
- - lastDataIndex ;
- - lastIt ;
}
}
return toRet ;
}
NetObjOrderedListIterator < T > get ( const NetObjID & id ) {
auto it = data_map ( ) . find ( id ) ;
if ( it = = data_map ( ) . end ( ) )
return data_list ( ) . end ( ) ;
return it - > second ;
}
2026-01-03 19:05:00 +03:00
std : : vector < NetObjOrderedListIterator < T > > get_list ( const std : : vector < NetObjID > & ids ) {
std : : vector < NetObjOrderedListIterator < T > > toRet ;
for ( auto & id : ids )
toRet . emplace_back ( get ( id ) ) ;
return toRet ;
}
2026-01-03 13:35:24 +03:00
NetObjOrderedListConstIterator < T > begin ( ) const {
return data_list ( ) . begin ( ) ;
}
NetObjOrderedListConstIterator < T > end ( ) const {
return data_list ( ) . end ( ) ;
}
NetObjOrderedListConstIterator < T > at ( uint32_t index ) const {
auto & data = data_list ( ) ;
if ( index > = data . size ( ) )
return data . end ( ) ;
return std : : prev ( data . begin ( ) , data . size ( ) - index ) ;
}
std : : vector < NetObjOrderedListConstIterator < T > > at_ordered_indices ( const std : : vector < uint32_t > & orderedIndices ) const {
auto & data = data_list ( ) ;
std : : vector < NetObjOrderedListConstIterator < T > > toRet ( orderedIndices . size ( ) ) ;
auto lastIt = data . end ( ) ;
uint32_t lastDataIndex = data . size ( ) ;
2026-01-03 19:05:00 +03:00
for ( std : : pair < const uint32_t & , NetObjOrderedListConstIterator < T > & > p : std : : views : : zip ( orderedIndices , toRet ) ) {
uint32_t orderedIndex = std : : min < uint32_t > ( p . first , data . size ( ) ) ;
2026-01-03 13:35:24 +03:00
NetObjOrderedListConstIterator < T > & it = p . second ;
for ( ; ; ) {
if ( lastDataIndex > = orderedIndex ) {
it = lastIt ;
break ;
}
- - lastDataIndex ;
- - lastIt ;
}
}
return toRet ;
}
NetObjOrderedListConstIterator < T > get ( const NetObjID & id ) const {
auto it = data_map ( ) . find ( id ) ;
if ( it = = data_map ( ) . end ( ) )
return data_list ( ) . end ( ) ;
return it - > second ;
}
2026-01-03 19:05:00 +03:00
std : : vector < NetObjOrderedListConstIterator < T > > get_list ( const std : : vector < NetObjID > & ids ) const {
std : : vector < NetObjOrderedListConstIterator < T > > toRet ;
for ( auto & id : ids )
toRet . emplace_back ( get ( id ) ) ;
return toRet ;
}
2026-02-10 13:12:53 +03:00
void sort_it_list ( std : : vector < NetObjOrderedListIterator < T > > & itList ) const {
sort_netobj_ordered_list_iterator_list ( data_list ( ) , itList ) ;
}
2026-01-03 13:35:24 +03:00
bool empty ( ) const {
return data_list ( ) . empty ( ) ;
}
2025-12-08 20:51:11 +03:00
virtual ~ NetObjOrderedList ( ) { }
2025-12-07 17:35:27 +03:00
protected :
2026-01-02 20:11:33 +03:00
NetObjOrderedListIterator < T > insert_single ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const std : : shared_ptr < NetServer : : ClientData > & clientInserting , const NetObjOrderedListIterator < T > it , NetObjOwnerPtr < T > newObj ) {
std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > toInsert ;
toInsert . emplace_back ( it , std : : move ( newObj ) ) ;
return insert_ordered_list ( l , clientInserting , toInsert ) . back ( ) ;
}
2026-01-03 13:35:24 +03:00
virtual std : : list < NetObjOrderedListObjectInfo < T > > & data_list ( ) = 0 ;
virtual const std : : list < NetObjOrderedListObjectInfo < T > > & data_list ( ) const = 0 ;
virtual std : : unordered_map < NetworkingObjects : : NetObjID , NetObjOrderedListIterator < T > > & data_map ( ) = 0 ;
virtual const std : : unordered_map < NetworkingObjects : : NetObjID , NetObjOrderedListIterator < T > > & data_map ( ) const = 0 ;
2025-12-30 19:46:08 +03:00
virtual std : : vector < NetObjOrderedListIterator < T > > insert_ordered_list ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const std : : shared_ptr < NetServer : : ClientData > & clientInserting , std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > & newObj ) = 0 ;
virtual void erase_it_list ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const std : : vector < NetObjOrderedListIterator < T > > & itList , std : : vector < NetObjOwnerPtr < T > > * erasedObjects ) = 0 ;
2025-12-11 16:05:41 +03:00
virtual void write_constructor ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryOutputArchive & a ) = 0 ;
virtual void read_update ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryInputArchive & a , const std : : shared_ptr < NetServer : : ClientData > & ) = 0 ;
2025-12-11 22:41:53 +03:00
virtual void read_constructor ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryInputArchive & a , const std : : shared_ptr < NetServer : : ClientData > & ) = 0 ;
2025-12-13 21:41:32 +03:00
// Call after inserting
2025-12-30 19:46:08 +03:00
void call_insert_callback ( const NetObjOrderedListIterator < T > & objInfo ) {
2025-12-13 21:41:32 +03:00
if ( insertCallback )
insertCallback ( objInfo ) ;
}
2025-12-30 19:46:08 +03:00
void call_insert_callback_list ( const std : : vector < NetObjOrderedListIterator < T > > & objInfos ) {
2025-12-13 21:41:32 +03:00
if ( insertCallback ) {
for ( auto objInfo : objInfos )
insertCallback ( objInfo ) ;
}
}
// Call before erasing
2025-12-30 19:46:08 +03:00
void call_erase_callback ( const NetObjOrderedListIterator < T > & objInfo ) {
2025-12-13 21:41:32 +03:00
if ( eraseCallback )
eraseCallback ( objInfo ) ;
}
2025-12-30 19:46:08 +03:00
void call_move_callback ( const NetObjOrderedListIterator < T > & objInfo , uint32_t oldPos ) {
2025-12-13 21:41:32 +03:00
if ( moveCallback )
moveCallback ( objInfo , oldPos ) ;
}
2025-12-07 17:35:27 +03:00
private :
2025-12-13 21:41:32 +03:00
InsertCallback insertCallback ;
EraseCallback eraseCallback ;
MoveCallback moveCallback ;
2025-12-13 13:03:27 +03:00
template < typename S > friend void register_ordered_list_class ( NetObjManager & t ) ;
2025-12-11 16:05:41 +03:00
static void write_constructor_func ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryOutputArchive & a ) {
2025-12-07 17:35:27 +03:00
l - > write_constructor ( l , a ) ;
}
2025-12-11 16:05:41 +03:00
static void read_constructor_func ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryInputArchive & a , const std : : shared_ptr < NetServer : : ClientData > & c ) {
2025-12-08 22:21:07 +03:00
l - > read_constructor ( l , a , c ) ;
}
2025-12-11 16:05:41 +03:00
static void read_update_func ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryInputArchive & a , const std : : shared_ptr < NetServer : : ClientData > & c ) {
2025-12-07 17:35:27 +03:00
l - > read_update ( l , a , c ) ;
}
} ;
template < typename T > class NetObjOrderedListServer : public NetObjOrderedList < T > {
public :
2025-12-08 20:51:11 +03:00
NetObjOrderedListServer ( ) { }
2025-12-22 11:13:50 +03:00
virtual void reassign_netobj_ids_call ( ) override {
idToDataMap . clear ( ) ;
2025-12-30 19:46:08 +03:00
for ( auto it = data . begin ( ) ; it ! = data . end ( ) ; + + it ) {
it - > obj . reassign_ids ( ) ;
idToDataMap [ it - > obj . get_net_id ( ) ] = it ;
2025-12-22 11:13:50 +03:00
}
}
2025-12-07 17:35:27 +03:00
protected :
2026-01-03 13:35:24 +03:00
virtual std : : list < NetObjOrderedListObjectInfo < T > > & data_list ( ) override { return data ; }
virtual const std : : list < NetObjOrderedListObjectInfo < T > > & data_list ( ) const override { return data ; }
2026-01-05 15:19:21 +03:00
virtual std : : unordered_map < NetworkingObjects : : NetObjID , NetObjOrderedListIterator < T > > & data_map ( ) override { return idToDataMap ; }
virtual const std : : unordered_map < NetworkingObjects : : NetObjID , NetObjOrderedListIterator < T > > & data_map ( ) const override { return idToDataMap ; }
2025-12-30 19:46:08 +03:00
virtual std : : vector < NetObjOrderedListIterator < T > > insert_ordered_list ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const std : : shared_ptr < NetServer : : ClientData > & clientInserting , std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > & newObjs ) override {
if ( newObjs . empty ( ) )
return { } ;
2026-01-05 22:01:54 +03:00
NETOBJ_CHECK_INSERT_ORDERED ( data , newObjs ) ;
2025-12-30 19:46:08 +03:00
std : : vector < NetworkingObjects : : NetObjID > idPositionList ;
for ( auto & [ itToInsertAt , newObj ] : newObjs ) {
if ( itToInsertAt = = data . begin ( ) )
idPositionList . emplace_back ( NetworkingObjects : : NetObjID { 0 , 0 } ) ;
else
idPositionList . emplace_back ( std : : prev ( itToInsertAt ) - > obj . get_net_id ( ) ) ;
}
std : : vector < NetObjOrderedListIterator < T > > toRet ;
for ( auto & [ itToInsertAt , newObj ] : newObjs ) {
auto newObjIt = data . emplace ( itToInsertAt , std : : move ( newObj ) , itToInsertAt = = data . end ( ) ? data . size ( ) : itToInsertAt - > pos ) ; // All position values will be wrong except the first one, which is all that matters
idToDataMap . emplace ( newObjIt - > obj . get_net_id ( ) , newObjIt ) ;
toRet . emplace_back ( newObjIt ) ;
2025-12-13 17:56:07 +03:00
}
2025-12-30 19:46:08 +03:00
set_position_obj_info_list < T > ( toRet [ 0 ] , data . end ( ) ) ;
l . send_server_update_to_all_clients_except ( clientInserting , RELIABLE_COMMAND_CHANNEL , [ & toRet , & idPositionList ] ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & , cereal : : PortableBinaryOutputArchive & a ) {
a ( ObjPtrOrderedListCommand_StoC : : INSERT_LIST_CONSTRUCT , static_cast < uint32_t > ( toRet . size ( ) ) ) ;
for ( auto [ newObjIt , idPosition ] : std : : views : : zip ( toRet , idPositionList ) ) {
a ( idPosition ) ;
newObjIt - > obj . write_create_message ( a ) ;
2025-12-13 17:56:07 +03:00
}
} ) ;
2025-12-30 19:46:08 +03:00
l . send_server_update_to_client ( clientInserting , RELIABLE_COMMAND_CHANNEL , [ & toRet , & idPositionList ] ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & , cereal : : PortableBinaryOutputArchive & a ) {
a ( ObjPtrOrderedListCommand_StoC : : INSERT_LIST_REFERENCE , static_cast < uint32_t > ( toRet . size ( ) ) ) ;
for ( auto [ newObjIt , idPosition ] : std : : views : : zip ( toRet , idPositionList ) )
a ( idPosition , newObjIt - > obj . get_net_id ( ) ) ;
2025-12-13 17:56:07 +03:00
} ) ;
2025-12-13 21:41:32 +03:00
this - > call_insert_callback_list ( toRet ) ;
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( data , idToDataMap ) ;
2025-12-13 17:56:07 +03:00
return toRet ;
}
2026-01-05 15:19:21 +03:00
virtual void erase_it_list ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const std : : vector < NetObjOrderedListIterator < T > > & itList , std : : vector < NetObjOwnerPtr < T > > * erasedObjects ) override {
2025-12-30 19:46:08 +03:00
if ( itList . empty ( ) )
2025-12-11 16:05:41 +03:00
return ;
2025-12-30 19:46:08 +03:00
std : : vector < std : : pair < uint32_t , NetObjOwnerPtr < T > > > erasedObjectsWithPos ;
2026-02-10 11:33:19 +03:00
if ( erasedObjects ) {
for ( auto & it : itList )
erasedObjectsWithPos . emplace_back ( it - > pos , NetObjOwnerPtr < T > ( ) ) ;
}
2025-12-30 19:46:08 +03:00
NetObjOrderedListIterator < T > smallestPosIt = data . end ( ) ;
std : : vector < NetObjID > idListToSend ;
2026-02-10 11:33:19 +03:00
for ( size_t i = 0 ; i < itList . size ( ) ; i + + ) {
auto & it = itList [ i ] ;
2025-12-30 19:46:08 +03:00
if ( smallestPosIt = = data . end ( ) | | smallestPosIt - > pos > = it - > pos ) {
smallestPosIt = std : : next ( it ) ;
if ( smallestPosIt ! = data . end ( ) )
smallestPosIt - > pos = it - > pos ;
}
idListToSend . emplace_back ( it - > obj . get_net_id ( ) ) ;
this - > call_erase_callback ( it ) ;
idToDataMap . erase ( it - > obj . get_net_id ( ) ) ;
2025-12-22 11:13:50 +03:00
if ( erasedObjects )
2026-02-10 11:33:19 +03:00
erasedObjectsWithPos [ i ] . second = std : : move ( it - > obj ) ;
2025-12-30 19:46:08 +03:00
data . erase ( it ) ;
}
if ( erasedObjects ) {
std : : sort ( erasedObjectsWithPos . begin ( ) , erasedObjectsWithPos . end ( ) , [ ] ( auto & a , auto & b ) {
return a . first < b . first ;
} ) ;
for ( auto & e : erasedObjectsWithPos )
erasedObjects - > emplace_back ( std : : move ( e . second ) ) ;
2025-12-13 21:41:32 +03:00
}
2025-12-30 19:46:08 +03:00
l . send_server_update_to_all_clients ( RELIABLE_COMMAND_CHANNEL , [ & idListToSend ] ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & , cereal : : PortableBinaryOutputArchive & a ) {
a ( ObjPtrOrderedListCommand_StoC : : ERASE_ID_LIST , idListToSend ) ;
2025-12-13 17:56:07 +03:00
} ) ;
2025-12-30 19:46:08 +03:00
set_position_obj_info_list < T > ( smallestPosIt , data . end ( ) ) ;
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( data , idToDataMap ) ;
2025-12-13 17:56:07 +03:00
}
2025-12-11 16:05:41 +03:00
virtual void write_constructor ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryOutputArchive & a ) override {
2025-12-08 14:28:01 +03:00
a ( static_cast < uint32_t > ( data . size ( ) ) ) ;
2025-12-30 19:46:08 +03:00
for ( auto & c : data )
c . obj . write_create_message ( a ) ;
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( data , idToDataMap ) ;
2025-12-07 17:35:27 +03:00
}
2025-12-11 22:41:53 +03:00
virtual void read_constructor ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryInputArchive & a , const std : : shared_ptr < NetServer : : ClientData > & c ) override {
2025-12-08 14:28:01 +03:00
uint32_t constructedSize ;
a ( constructedSize ) ;
data . clear ( ) ;
2025-12-10 13:06:45 +03:00
idToDataMap . clear ( ) ;
for ( uint32_t i = 0 ; i < constructedSize ; i + + ) {
2025-12-30 19:46:08 +03:00
auto it = data . emplace ( data . end ( ) , l . get_obj_man ( ) - > template read_create_message < T > ( a , c ) , i ) ;
idToDataMap . emplace ( data . back ( ) . obj . get_net_id ( ) , it ) ;
2025-12-10 13:06:45 +03:00
}
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( data , idToDataMap ) ;
2025-12-08 14:28:01 +03:00
// Dont send the object data to all clients in the constructor, as the function that called read_create_message is also the one that will decide where to send the data of the constructed object
2025-12-07 17:35:27 +03:00
}
2025-12-11 16:05:41 +03:00
virtual void read_update ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryInputArchive & a , const std : : shared_ptr < NetServer : : ClientData > & c ) override {
2025-12-07 17:35:27 +03:00
ObjPtrOrderedListCommand_CtoS command ;
a ( command ) ;
switch ( command ) {
2025-12-30 19:46:08 +03:00
case ObjPtrOrderedListCommand_CtoS : : INSERT_LIST : {
std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > newObjs ;
2025-12-31 19:48:12 +03:00
std : : vector < uint32_t > insertIndices ;
2025-12-30 19:46:08 +03:00
2025-12-13 17:56:07 +03:00
uint32_t newObjsSize ;
a ( newObjsSize ) ;
for ( uint32_t i = 0 ; i < newObjsSize ; i + + ) {
2025-12-31 19:48:12 +03:00
uint32_t & insertIndex = insertIndices . emplace_back ( ) ;
a ( insertIndex ) ;
insertIndex - = i ;
insertIndex = std : : min < uint32_t > ( insertIndex , data . size ( ) ) ;
newObjs . emplace_back ( NetObjOrderedListIterator < T > ( ) , l . get_obj_man ( ) - > template read_create_message < T > ( a , c ) ) ;
}
2025-12-30 19:46:08 +03:00
2026-01-05 12:43:40 +03:00
std : : vector < NetObjOrderedListIterator < T > > itList = this - > at_ordered_indices ( insertIndices ) ;
for ( size_t i = 0 ; i < itList . size ( ) ; i + + )
newObjs [ i ] . first = itList [ i ] ;
2025-12-31 19:48:12 +03:00
2025-12-13 17:56:07 +03:00
insert_ordered_list ( l , c , newObjs ) ;
break ;
}
2025-12-30 19:46:08 +03:00
case ObjPtrOrderedListCommand_CtoS : : ERASE_ID_LIST : {
std : : vector < NetObjID > idsToErase ;
2025-12-13 17:56:07 +03:00
a ( idsToErase ) ;
2025-12-30 19:46:08 +03:00
std : : vector < NetObjOrderedListIterator < T > > iteratorsToErase ;
for ( auto & id : idsToErase ) {
auto it = idToDataMap . find ( id ) ;
if ( it ! = idToDataMap . end ( ) )
iteratorsToErase . emplace_back ( it - > second ) ;
}
erase_it_list ( l , iteratorsToErase , nullptr ) ;
2025-12-13 17:56:07 +03:00
break ;
}
2025-12-07 17:35:27 +03:00
}
}
private :
2025-12-30 19:46:08 +03:00
std : : list < NetObjOrderedListObjectInfo < T > > data ;
std : : unordered_map < NetObjID , NetObjOrderedListIterator < T > > idToDataMap ;
2025-12-07 17:35:27 +03:00
} ;
template < typename T > class NetObjOrderedListClient : public NetObjOrderedList < T > {
public :
2025-12-08 20:51:11 +03:00
NetObjOrderedListClient ( ) { }
2025-12-22 11:13:50 +03:00
virtual void reassign_netobj_ids_call ( ) override {
serverData . clear ( ) ;
2025-12-30 19:46:08 +03:00
serverIdToDataMap . clear ( ) ;
clientIdToDataMap . clear ( ) ;
for ( auto it = clientData . begin ( ) ; it ! = clientData . end ( ) ; + + it ) {
it - > obj . reassign_ids ( ) ;
clientIdToDataMap [ it - > obj . get_net_id ( ) ] = it ;
auto serverIt = serverData . emplace ( serverData . end ( ) , it - > obj . get_net_id ( ) ) ;
serverIdToDataMap [ it - > obj . get_net_id ( ) ] = serverIt ;
2025-12-22 11:13:50 +03:00
}
}
2025-12-07 17:35:27 +03:00
protected :
2026-01-03 13:35:24 +03:00
virtual std : : list < NetObjOrderedListObjectInfo < T > > & data_list ( ) override { return clientData ; }
virtual const std : : list < NetObjOrderedListObjectInfo < T > > & data_list ( ) const override { return clientData ; }
2026-01-05 15:19:21 +03:00
virtual std : : unordered_map < NetworkingObjects : : NetObjID , NetObjOrderedListIterator < T > > & data_map ( ) override { return clientIdToDataMap ; }
virtual const std : : unordered_map < NetworkingObjects : : NetObjID , NetObjOrderedListIterator < T > > & data_map ( ) const override { return clientIdToDataMap ; }
2025-12-30 19:46:08 +03:00
virtual std : : vector < NetObjOrderedListIterator < T > > insert_ordered_list ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const std : : shared_ptr < NetServer : : ClientData > & clientInserting , std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > & newObjs ) override {
if ( newObjs . empty ( ) )
return { } ;
2026-01-05 22:01:54 +03:00
NETOBJ_CHECK_INSERT_ORDERED ( clientData , newObjs ) ;
2025-12-30 19:46:08 +03:00
std : : vector < NetObjOrderedListIterator < T > > toRet ;
for ( auto & [ itToInsertAt , newObj ] : newObjs ) {
auto newObjIt = clientData . emplace ( itToInsertAt , std : : move ( newObj ) , itToInsertAt = = clientData . end ( ) ? clientData . size ( ) : itToInsertAt - > pos ) ; // All position values will be wrong except the first one, which is all that matters
clientIdToDataMap . emplace ( newObjIt - > obj . get_net_id ( ) , newObjIt ) ;
toRet . emplace_back ( newObjIt ) ;
}
set_position_obj_info_list < T > ( toRet [ 0 ] , clientData . end ( ) ) ;
2025-12-31 19:48:12 +03:00
l . send_client_update ( RELIABLE_COMMAND_CHANNEL , [ & toRet ] ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & , cereal : : PortableBinaryOutputArchive & a ) {
2025-12-30 19:46:08 +03:00
a ( ObjPtrOrderedListCommand_CtoS : : INSERT_LIST , static_cast < uint32_t > ( toRet . size ( ) ) ) ;
2025-12-31 19:48:12 +03:00
for ( auto newObjIt : toRet ) {
a ( newObjIt - > pos ) ;
2025-12-30 19:46:08 +03:00
newObjIt - > obj . write_create_message ( a ) ;
2025-12-13 17:56:07 +03:00
}
} ) ;
2025-12-13 21:41:32 +03:00
this - > call_insert_callback_list ( toRet ) ;
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( clientData , clientIdToDataMap ) ;
2025-12-13 17:56:07 +03:00
return toRet ;
}
2026-01-05 15:19:21 +03:00
virtual void erase_it_list ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , const std : : vector < NetObjOrderedListIterator < T > > & itList , std : : vector < NetObjOwnerPtr < T > > * erasedObjects ) override {
2025-12-30 19:46:08 +03:00
if ( itList . empty ( ) )
2025-12-13 17:56:07 +03:00
return ;
2025-12-30 19:46:08 +03:00
std : : vector < std : : pair < uint32_t , NetObjOwnerPtr < T > > > erasedObjectsWithPos ;
2026-02-10 11:33:19 +03:00
if ( erasedObjects ) {
for ( auto & it : itList )
erasedObjectsWithPos . emplace_back ( it - > pos , NetObjOwnerPtr < T > ( ) ) ;
}
2025-12-30 19:46:08 +03:00
NetObjOrderedListIterator < T > smallestPosIt = clientData . end ( ) ;
std : : vector < NetObjID > idListToSend ;
2026-02-10 11:33:19 +03:00
for ( size_t i = 0 ; i < itList . size ( ) ; i + + ) {
auto & it = itList [ i ] ;
2025-12-30 19:46:08 +03:00
if ( smallestPosIt = = clientData . end ( ) | | smallestPosIt - > pos > = it - > pos ) {
smallestPosIt = std : : next ( it ) ;
if ( smallestPosIt ! = clientData . end ( ) )
smallestPosIt - > pos = it - > pos ;
}
idListToSend . emplace_back ( it - > obj . get_net_id ( ) ) ;
this - > call_erase_callback ( it ) ;
clientIdToDataMap . erase ( it - > obj . get_net_id ( ) ) ;
2025-12-22 11:13:50 +03:00
if ( erasedObjects )
2026-02-10 11:33:19 +03:00
erasedObjectsWithPos [ i ] . second = std : : move ( it - > obj ) ;
2025-12-30 19:46:08 +03:00
clientData . erase ( it ) ;
}
if ( erasedObjects ) {
std : : sort ( erasedObjectsWithPos . begin ( ) , erasedObjectsWithPos . end ( ) , [ ] ( auto & a , auto & b ) {
return a . first < b . first ;
} ) ;
for ( auto & e : erasedObjectsWithPos )
erasedObjects - > emplace_back ( std : : move ( e . second ) ) ;
2025-12-13 21:41:32 +03:00
}
2025-12-30 19:46:08 +03:00
l . send_client_update ( RELIABLE_COMMAND_CHANNEL , [ & idListToSend ] ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & , cereal : : PortableBinaryOutputArchive & a ) {
a ( ObjPtrOrderedListCommand_CtoS : : ERASE_ID_LIST , idListToSend ) ;
2025-12-13 17:56:07 +03:00
} ) ;
2025-12-30 19:46:08 +03:00
set_position_obj_info_list < T > ( smallestPosIt , clientData . end ( ) ) ;
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( clientData , clientIdToDataMap ) ;
2025-12-13 17:56:07 +03:00
}
2025-12-11 16:05:41 +03:00
virtual void write_constructor ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryOutputArchive & a ) override {
2025-12-08 14:28:01 +03:00
a ( static_cast < uint32_t > ( clientData . size ( ) ) ) ;
2025-12-22 11:13:50 +03:00
serverData . clear ( ) ;
2025-12-30 19:46:08 +03:00
serverIdToDataMap . clear ( ) ;
for ( auto & c : clientData ) {
c . obj . write_create_message ( a ) ;
auto serverIt = serverData . emplace ( serverData . end ( ) , c . obj . get_net_id ( ) ) ; // We are the ones who made this list, so fill up
serverIdToDataMap . emplace ( c . obj . get_net_id ( ) , serverIt ) ;
2025-12-22 11:13:50 +03:00
}
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( clientData , clientIdToDataMap ) ;
2025-12-07 17:35:27 +03:00
}
2025-12-11 22:41:53 +03:00
virtual void read_constructor ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryInputArchive & a , const std : : shared_ptr < NetServer : : ClientData > & ) override {
2025-12-08 14:28:01 +03:00
uint32_t constructedSize ;
a ( constructedSize ) ;
clientData . clear ( ) ;
serverData . clear ( ) ;
2025-12-10 13:06:45 +03:00
clientIdToDataMap . clear ( ) ;
2025-12-30 19:46:08 +03:00
serverIdToDataMap . clear ( ) ;
2025-12-10 13:06:45 +03:00
for ( uint32_t i = 0 ; i < constructedSize ; i + + ) {
2025-12-30 19:46:08 +03:00
auto clientIt = clientData . emplace ( clientData . end ( ) , l . get_obj_man ( ) - > template read_create_message < T > ( a , nullptr ) , i ) ;
clientIdToDataMap . emplace ( clientIt - > obj . get_net_id ( ) , clientIt ) ;
auto serverIt = serverData . emplace ( serverData . end ( ) , clientIt - > obj . get_net_id ( ) ) ;
serverIdToDataMap . emplace ( clientIt - > obj . get_net_id ( ) , serverIt ) ;
2025-12-10 13:06:45 +03:00
}
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( clientData , clientIdToDataMap ) ;
2025-12-07 17:35:27 +03:00
}
2025-12-11 16:05:41 +03:00
virtual void read_update ( const NetObjTemporaryPtr < NetObjOrderedList < T > > & l , cereal : : PortableBinaryInputArchive & a , const std : : shared_ptr < NetServer : : ClientData > & ) override {
2025-12-07 17:35:27 +03:00
ObjPtrOrderedListCommand_StoC c ;
a ( c ) ;
switch ( c ) {
2025-12-30 19:46:08 +03:00
case ObjPtrOrderedListCommand_StoC : : INSERT_LIST_CONSTRUCT : {
2025-12-13 17:56:07 +03:00
uint32_t newObjsSize ;
a ( newObjsSize ) ;
2025-12-30 19:46:08 +03:00
std : : vector < NetworkingObjects : : NetObjID > idsBeforeElements ;
2026-01-05 12:43:40 +03:00
std : : vector < std : : list < NetObjID > : : iterator > serverInsertIts ;
2025-12-30 19:46:08 +03:00
std : : vector < std : : pair < NetObjOrderedListIterator < T > , NetObjOwnerPtr < T > > > newObjs ;
2025-12-13 17:56:07 +03:00
for ( uint32_t i = 0 ; i < newObjsSize ; i + + ) {
2025-12-30 19:46:08 +03:00
auto & idBeforeElement = idsBeforeElements . emplace_back ( ) ;
a ( idBeforeElement ) ;
newObjs . emplace_back ( get_client_iterator_from_server_previous_net_obj_id ( idBeforeElement ) , l . get_obj_man ( ) - > template read_create_message < T > ( a , nullptr ) ) ;
2026-01-05 12:43:40 +03:00
serverInsertIts . emplace_back ( get_server_iterator_from_server_previous_net_obj_id ( idBeforeElement ) ) ;
2025-12-13 17:56:07 +03:00
}
2025-12-30 19:46:08 +03:00
for ( uint32_t i = 0 ; i < newObjsSize ; i + + ) {
2026-01-05 12:43:40 +03:00
auto serverIt = serverData . emplace ( serverInsertIts [ i ] , newObjs [ i ] . second . get_net_id ( ) ) ;
2025-12-30 19:46:08 +03:00
serverIdToDataMap . emplace ( newObjs [ i ] . second . get_net_id ( ) , serverIt ) ;
}
2025-12-30 21:18:59 +03:00
std : : vector < NetObjOrderedListIterator < T > > insertedIterators ;
2025-12-30 19:46:08 +03:00
auto firstInsertedIt = clientData . end ( ) ;
for ( uint32_t i = 0 ; i < newObjs . size ( ) ; i + + ) {
auto & [ itToInsertAt , newObj ] = newObjs [ i ] ;
auto newObjIt = clientData . emplace ( itToInsertAt , std : : move ( newObj ) , itToInsertAt = = clientData . end ( ) ? clientData . size ( ) : itToInsertAt - > pos ) ; // All position values will be wrong except the first one, which is all that matters
clientIdToDataMap . emplace ( newObjIt - > obj . get_net_id ( ) , newObjIt ) ;
2025-12-30 21:18:59 +03:00
insertedIterators . emplace_back ( newObjIt ) ;
2025-12-30 19:46:08 +03:00
if ( i = = 0 )
firstInsertedIt = newObjIt ;
}
2026-01-05 12:43:40 +03:00
2025-12-30 19:46:08 +03:00
set_position_obj_info_list < T > ( firstInsertedIt , clientData . end ( ) ) ;
2025-12-30 21:18:59 +03:00
this - > call_insert_callback_list ( insertedIterators ) ;
2025-12-30 19:46:08 +03:00
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( clientData , clientIdToDataMap ) ;
2025-12-07 17:35:27 +03:00
break ;
2025-12-09 13:00:38 +03:00
}
2025-12-30 19:46:08 +03:00
case ObjPtrOrderedListCommand_StoC : : INSERT_LIST_REFERENCE : {
2025-12-13 17:56:07 +03:00
uint32_t newObjsSize ;
a ( newObjsSize ) ;
2025-12-30 19:46:08 +03:00
struct PerElementData {
NetworkingObjects : : NetObjID idBeforeElement ;
NetworkingObjects : : NetObjID refID ;
2026-01-05 12:43:40 +03:00
std : : list < NetObjID > : : iterator serverInsertIt ;
2025-12-30 19:46:08 +03:00
bool foundInClient ;
NetObjOrderedListIterator < T > clientObjectIt ;
NetObjOrderedListIterator < T > clientInsertPosIt ;
} ;
std : : vector < PerElementData > receivedElements ;
2025-12-13 17:56:07 +03:00
for ( uint32_t i = 0 ; i < newObjsSize ; i + + ) {
2025-12-30 19:46:08 +03:00
auto & elemData = receivedElements . emplace_back ( ) ;
a ( elemData . idBeforeElement , elemData . refID ) ;
2026-01-05 12:43:40 +03:00
elemData . serverInsertIt = get_server_iterator_from_server_previous_net_obj_id ( elemData . idBeforeElement ) ;
2025-12-13 17:56:07 +03:00
}
2025-12-30 19:46:08 +03:00
std : : list < NetObjOrderedListObjectInfo < T > > referredToObjectData ;
std : : unordered_map < NetworkingObjects : : NetObjID , uint32_t > referredToObjectOldPos ;
auto startRefreshFrom = clientData . end ( ) ;
for ( auto & elemData : receivedElements ) {
auto clientIdToDataMapIt = clientIdToDataMap . find ( elemData . refID ) ;
if ( clientIdToDataMapIt ! = clientIdToDataMap . end ( ) ) {
elemData . clientObjectIt = clientIdToDataMapIt - > second ;
referredToObjectOldPos . emplace ( elemData . clientObjectIt - > obj . get_net_id ( ) , elemData . clientObjectIt - > pos ) ;
if ( startRefreshFrom = = clientData . end ( ) | | startRefreshFrom = = elemData . clientObjectIt ) {
startRefreshFrom = std : : next ( elemData . clientObjectIt ) ;
if ( startRefreshFrom ! = clientData . end ( ) )
startRefreshFrom - > pos = elemData . clientObjectIt - > pos ;
}
2026-01-05 12:43:40 +03:00
referredToObjectData . splice ( referredToObjectData . end ( ) , clientData , elemData . clientObjectIt ) ;
2025-12-30 19:46:08 +03:00
clientIdToDataMap . erase ( clientIdToDataMapIt ) ;
elemData . foundInClient = true ;
}
else
elemData . foundInClient = false ;
}
set_position_obj_info_list < T > ( startRefreshFrom , clientData . end ( ) ) ;
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( clientData , clientIdToDataMap ) ;
2025-12-30 19:46:08 +03:00
for ( auto & elemData : receivedElements ) {
if ( elemData . foundInClient )
elemData . clientInsertPosIt = get_client_iterator_from_server_previous_net_obj_id ( elemData . idBeforeElement ) ;
}
for ( auto & elemData : receivedElements ) {
2026-01-05 12:43:40 +03:00
auto serverIt = serverData . emplace ( elemData . serverInsertIt , elemData . refID ) ;
2025-12-30 19:46:08 +03:00
serverIdToDataMap . emplace ( elemData . refID , serverIt ) ;
}
auto firstInsertedIt = clientData . end ( ) ;
uint32_t firstInsertedActualPos = 0 ;
for ( auto & elemData : receivedElements ) {
if ( ! elemData . foundInClient )
continue ;
if ( firstInsertedIt = = clientData . end ( ) ) {
firstInsertedIt = elemData . clientObjectIt ;
2026-01-05 22:01:54 +03:00
if ( elemData . clientInsertPosIt ! = clientData . end ( ) )
firstInsertedActualPos = elemData . clientInsertPosIt - > pos ;
else
firstInsertedActualPos = clientData . size ( ) ;
2025-12-30 19:46:08 +03:00
}
2026-01-05 12:43:40 +03:00
clientData . splice ( elemData . clientInsertPosIt , referredToObjectData , elemData . clientObjectIt ) ;
2025-12-30 19:46:08 +03:00
clientIdToDataMap . emplace ( elemData . clientObjectIt - > obj . get_net_id ( ) , elemData . clientObjectIt ) ;
}
// Instead of set_position_obj_info_list<T>
if ( firstInsertedIt ! = clientData . end ( ) ) {
auto & it = firstInsertedIt ;
auto & actualPos = firstInsertedActualPos ;
for ( ; it ! = clientData . end ( ) ; + + it ) {
it - > pos = actualPos ;
auto referredToObjectOldPosIt = referredToObjectOldPos . find ( it - > obj . get_net_id ( ) ) ;
if ( referredToObjectOldPosIt ! = referredToObjectOldPos . end ( ) ) {
uint32_t oldPos = referredToObjectOldPosIt - > second ;
if ( oldPos ! = it - > pos )
this - > call_move_callback ( it , oldPos ) ;
}
actualPos + + ;
}
2025-12-11 16:05:41 +03:00
}
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( clientData , clientIdToDataMap ) ;
2025-12-07 17:35:27 +03:00
break ;
2025-12-09 13:00:38 +03:00
}
2025-12-30 19:46:08 +03:00
case ObjPtrOrderedListCommand_StoC : : ERASE_ID_LIST : {
std : : vector < NetworkingObjects : : NetObjID > idsToErase ;
a ( idsToErase ) ;
for ( auto & id : idsToErase ) {
auto serverIDToDataMapIt = serverIdToDataMap . find ( id ) ;
serverData . erase ( serverIDToDataMapIt - > second ) ;
serverIdToDataMap . erase ( serverIDToDataMapIt ) ;
2025-12-13 17:56:07 +03:00
}
2025-12-30 19:46:08 +03:00
NetObjOrderedListIterator < T > smallestPosIt = clientData . end ( ) ;
for ( auto & id : idsToErase ) {
auto clientIt = clientIdToDataMap . find ( id ) ;
if ( clientIt = = clientIdToDataMap . end ( ) )
continue ;
auto it = clientIt - > second ;
if ( smallestPosIt = = clientData . end ( ) | | smallestPosIt - > pos > = it - > pos ) {
smallestPosIt = std : : next ( it ) ;
if ( smallestPosIt ! = clientData . end ( ) )
smallestPosIt - > pos = it - > pos ;
}
this - > call_erase_callback ( it ) ;
clientIdToDataMap . erase ( clientIt ) ;
clientData . erase ( it ) ;
2025-12-13 21:41:32 +03:00
}
2025-12-30 19:46:08 +03:00
set_position_obj_info_list < T > ( smallestPosIt , clientData . end ( ) ) ;
2026-01-05 12:43:40 +03:00
NETOBJ_ORDERED_LIST_VERBOSE_DEBUG ( clientData , clientIdToDataMap ) ;
2025-12-13 17:56:07 +03:00
break ;
}
2025-12-07 17:35:27 +03:00
}
}
private :
2025-12-30 19:46:08 +03:00
NetworkingObjects : : NetObjOrderedListIterator < T > get_client_iterator_from_server_previous_net_obj_id ( NetworkingObjects : : NetObjID previousObjId ) {
if ( previousObjId = = NetworkingObjects : : NetObjID { 0 , 0 } )
return clientData . begin ( ) ;
else {
auto serverIt = serverIdToDataMap [ previousObjId ] ;
for ( ; ; ) {
NetworkingObjects : : NetObjID netObjID = * serverIt ;
auto clientIt = clientIdToDataMap . find ( netObjID ) ;
if ( clientIt ! = clientIdToDataMap . end ( ) )
return std : : next ( clientIt - > second ) ;
if ( serverIt = = serverData . begin ( ) )
return clientData . begin ( ) ;
- - serverIt ;
2025-12-09 13:00:38 +03:00
}
2025-12-11 16:05:41 +03:00
}
2025-12-30 19:46:08 +03:00
return clientData . begin ( ) ;
}
2025-12-11 16:05:41 +03:00
2025-12-30 19:46:08 +03:00
std : : list < NetObjID > : : iterator get_server_iterator_from_server_previous_net_obj_id ( NetworkingObjects : : NetObjID previousObjId ) {
if ( previousObjId = = NetworkingObjects : : NetObjID { 0 , 0 } )
return serverData . begin ( ) ;
return std : : next ( serverIdToDataMap [ previousObjId ] ) ;
2025-12-09 13:00:38 +03:00
}
2025-12-30 19:46:08 +03:00
std : : list < NetObjID > serverData ;
std : : unordered_map < NetObjID , std : : list < NetObjID > : : iterator > serverIdToDataMap ;
std : : list < NetObjOrderedListObjectInfo < T > > clientData ;
std : : unordered_map < NetObjID , NetObjOrderedListIterator < T > > clientIdToDataMap ;
2025-12-07 17:35:27 +03:00
} ;
2025-12-13 13:03:27 +03:00
template < typename S > void register_ordered_list_class ( NetObjManager & objMan ) {
objMan . register_class < NetObjOrderedList < S > , NetObjOrderedList < S > , NetObjOrderedListClient < S > , NetObjOrderedListServer < S > > ( {
2025-12-07 17:35:27 +03:00
. writeConstructorFuncClient = NetObjOrderedList < S > : : write_constructor_func ,
. readConstructorFuncClient = NetObjOrderedList < S > : : read_constructor_func ,
. readUpdateFuncClient = NetObjOrderedList < S > : : read_update_func ,
. writeConstructorFuncServer = NetObjOrderedList < S > : : write_constructor_func ,
. readConstructorFuncServer = NetObjOrderedList < S > : : read_constructor_func ,
. readUpdateFuncServer = NetObjOrderedList < S > : : read_update_func ,
} ) ;
}
}