Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/network/src/lib/network/network_game_manager.cc @ 6273

Last change on this file since 6273 was 6273, checked in by rennerc, 18 years ago

converter: added functions for strings
network_protocol: length and id are now int
network_game_manager: fixed some more bugs :D
skybox: is loaded on client corectly now :)

File size: 18.1 KB
RevLine 
[6067]1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
12   main-programmer: Benjamin Wuest
13   co-programmer: ...
14*/
15
16
17/* this is for debug output. It just says, that all calls to PRINT() belong to the DEBUG_MODULE_NETWORK module
18   For more information refere to https://www.orxonox.net/cgi-bin/trac.cgi/wiki/DebugOutput
19*/
20#define DEBUG_MODULE_NETWORK
21
[6190]22#include "factory.h"
23#include "network_stream.h"
[6214]24#include "converter.h"
[6190]25
[6067]26/* include your own header */
[6116]27#include "network_game_manager.h"
[6067]28
29
30/* using namespace std is default, this needs to be here */
31using namespace std;
32
[6238]33NetworkGameManager* NetworkGameManager::singletonRef = NULL;
[6230]34
[6067]35/*!
36 * Standard constructor
37 */
[6116]38NetworkGameManager::NetworkGameManager()
[6067]39{
[6250]40  PRINTF(0)("START\n");
41
[6067]42  /* set the class id for the base object */
[6257]43  this->setClassID(CL_NETWORK_GAME_MANAGER, "EntityManager");
[6214]44
45  allOutBuffer.length = 0;
46
47  allOutBuffer.maxLength = 10*1024;
48
49  allOutBuffer.buffer = new byte[10*1024];
50
51  newUniqueID = MAX_CONNECTIONS + 2;
[6067]52}
53
54/*!
55 * Standard destructor
56 */
[6116]57NetworkGameManager::~NetworkGameManager()
[6067]58{
[6214]59  for ( int i = 0; i<outBuffer.size(); i++)
[6190]60  {
61    if ( outBuffer[i].buffer )
62      delete outBuffer[i].buffer;
63  }
[6214]64
65  if ( allOutBuffer.buffer )
66    delete allOutBuffer.buffer;
[6067]67}
68
69
[6190]70void NetworkGameManager::writeBytes(const byte* data, int length, int sender)
[6067]71{
[6214]72  int i = 0;
73  byte b;
74
[6256]75  while ( i<length-1 )
[6214]76  {
77    b = data[i++];
78
[6256]79    PRINTF(0)("WriteBytes: b = %d\n", b);
80
[6219]81    if ( isServer() )
[6214]82    {
[6219]83      if ( b == REQUEST_CREATE )
84      {
85        if ( !handleRequestCreate( i, data, length, sender ) )
86          return;
87        continue;
88      }
89      if ( b == REQUEST_REMOVE )
90      {
91        if ( !handleRequestRemove( i, data, length, sender ) )
92          return;
93        continue;
94      }
[6214]95    }
[6256]96    else
[6214]97    {
[6219]98      if ( b == CREATE_ENTITY )
99      {
100        if ( !handleCreateEntity( i, data, length, sender ) )
101          return;
102        continue;
103      }
104      if ( b == REMOVE_ENTITY )
105      {
106        if ( !handleRemoveEntity( i, data, length, sender ) )
107          return;
108        continue;
109      }
110      if ( b == CREATE_ENTITY_LIST )
111      {
112        if ( !handleCreateEntityList( i, data, length, sender ) )
113          return;
114        continue;
115      }
116      if ( b == REMOVE_ENTITY_LIST )
117      {
118        if ( !handleRemoveEntityList( i, data, length, sender ) )
119          return;
120        continue;
121      }
122      if ( b == YOU_ARE_ENTITY )
123      {
124        if ( !handleYouAreEntity( i, data, length, sender ) )
125          return;
126        continue;
127      }
[6214]128    }
[6219]129
[6214]130    if ( b == REQUEST_SYNC )
131    {
[6219]132      if ( !handleRequestSync( i, data, length, sender ) )
133        return;
134      continue;
[6214]135    }
[6219]136
137    //if we get her something with data is wrong
138    PRINTF(1)("Data is not in the right format! i=%d\n", i);
139    return;
[6214]140  }
[6067]141}
142
[6116]143int NetworkGameManager::readBytes(byte* data, int maxLength, int * reciever)
[6067]144{
[6214]145  for ( int i = 0; i<outBuffer.size(); i++ )
146  {
[6257]147    *reciever = i;
[6214]148    if ( outBuffer[i].length>0 )
149    {
150      int nbytes = outBuffer[i].length;
[6257]151      outBuffer[i].length = 0;
[6214]152
153      if ( nbytes > maxLength )
154      {
155        PRINTF(1)("OutBuffer.length (%d) > (%d) networkStreamBuffer.maxLength\n", nbytes, maxLength);
156        return 0;
157      }
158
159      memcpy(data, outBuffer[i].buffer, nbytes);
160      return nbytes;
161    }
162  }
163
[6257]164  *reciever = 0;
[6214]165  int nbytes = allOutBuffer.length;
[6257]166  allOutBuffer.length = 0;
[6214]167
168  if ( nbytes <=0 )
169    return 0;
170
171  if ( nbytes > maxLength )
172  {
173    PRINTF(1)("OutBuffer.length (%d) > (%d) networkStreamBuffer.length\n", nbytes, maxLength);
174    return 0;
175  }
176
177  memcpy( data, allOutBuffer.buffer, nbytes );
178  return nbytes;
[6067]179}
180
[6116]181void NetworkGameManager::writeDebug() const
[6067]182{
183}
184
[6116]185void NetworkGameManager::readDebug() const
[6067]186{
187}
188
189
190/*!
191 * Checks whether this is connected to a server or a client
[6214]192 * and afterwards creates the needed entity
[6067]193 * @param classID: The ID of the class of which an entity should be created
194 */
[6219]195void NetworkGameManager::createEntity( ClassID classID, int owner )
[6067]196{
[6214]197  if ( this->isServer() )
198  {
199    if ( newUniqueID < 0 )
200    {
201      PRINTF(1)("Cannot create entity! There are no more uniqueIDs left!\n");
202      return;
203    }
204
[6219]205    this->executeCreateEntity( classID, newUniqueID++, owner );
[6214]206  }
207  else
208  {
[6219]209    this->requestCreateEntity( classID );
[6214]210  }
[6067]211}
212
[6250]213
[6067]214/*!
215 * Checks whether this is connected to a server or a client
[6250]216 * and afterwards creates the needed entity
217 * @param classID: The ID of the class of which an entity should be created
218 */
219BaseObject* NetworkGameManager::createEntity( TiXmlElement* element)
220{
221  if ( this->isServer() )
222  {
223    if ( newUniqueID < 0 )
224    {
225      PRINTF(1)("Cannot create entity! There are no more uniqueIDs left!\n");
226      return NULL;
227    }
228    newUniqueID++;
229
230    BaseObject * b = Factory::fabricate( element );
231
232    if ( !b )
233    {
234      PRINTF(1)("Could not fabricate Object with classID %x\n", element->Value() );
235      return NULL;
236    }
237
238    if ( b->isA(CL_SYNCHRONIZEABLE) )
239    {
240      Synchronizeable * s = dynamic_cast<Synchronizeable*>(b);
241      s->setUniqueID( newUniqueID );
242      s->setOwner( 0 );
243      this->networkStream->connectSynchronizeable( *s );
244      return b;
245    }
246    else
247    {
248      PRINTF(1)("Class %s is not a synchronizeable!\n", b->getClassName() );
249      delete b;
250    }
251  }
252  else
253  {
254    PRINTF(1)("This node is not a server and cannot create id %x\n", element->Value());
255  }
256  return NULL;
257}
258
259
260/*!
261 * Checks whether this is connected to a server or a client
[6067]262 * and afterwards removes the specified entity
263 * @param uniqueID: The ID of the entity object which should be removed
264 */
[6116]265void NetworkGameManager::removeEntity(int uniqueID)
[6067]266{
[6214]267  if ( this->isServer() )
268  {
269    this->executeRemoveEntity( uniqueID );
270  }
271  else
272  {
273    this->requestRemoveEntity( uniqueID );
274  }
[6067]275}
276
277
278
279/*!
280 * Creates the needed entity on the server if possible
281 * @param classID: The ID of the class of which an entity should be created
282 */
[6214]283void NetworkGameManager::requestCreateEntity(ClassID classID)
[6067]284{
[6231]285  if ( !writeToClientBuffer( allOutBuffer, (byte)REQUEST_CREATE ) )
[6214]286    return;
[6231]287  if ( !writeToClientBuffer( allOutBuffer, (int)classID ) )
[6214]288    return;
[6067]289}
290
291/*!
292 * Removes the specified entity on the server
293 * @param uniqueID: The ID of the entity object which should be removed
294 */
[6116]295void NetworkGameManager::requestRemoveEntity(int uniqueID)
[6067]296{
[6231]297  if ( !writeToClientBuffer( allOutBuffer, (byte)REQUEST_REMOVE ) )
[6214]298    return;
[6231]299  if ( !writeToClientBuffer( allOutBuffer, uniqueID ) )
[6214]300    return;
[6067]301}
302
303/*!
304 * Creates the needed entity if possible
305 * This function is called if this is a server
306 * @param classID: The ID of the class of which an entity should be created
307 */
[6214]308void NetworkGameManager::executeCreateEntity(ClassID classID, int uniqueID, int owner)
[6067]309{
[6231]310  if ( !writeToClientBuffer( allOutBuffer, (byte)CREATE_ENTITY ) )
[6214]311    return;
[6231]312  if ( !writeToClientBuffer( allOutBuffer, (int)classID ) )
[6214]313    return;
[6231]314  if ( !writeToClientBuffer( allOutBuffer, uniqueID ) )
[6214]315    return;
[6231]316  if ( !writeToClientBuffer( allOutBuffer, owner ) )
[6214]317    return;
318
319  doCreateEntity( classID, uniqueID, owner );
[6067]320}
321
322/*!
323 * Removes the specified entity
324 * This function is called if this is a server
325 * @param uniqueID: The ID of the entity object which should be removed
326 */
[6116]327void NetworkGameManager::executeRemoveEntity(int uniqueID)
[6067]328{
[6231]329  if ( !writeToClientBuffer( allOutBuffer, (byte)REMOVE_ENTITY ) )
[6214]330    return;
[6231]331  if ( !writeToClientBuffer( allOutBuffer, uniqueID ) )
[6214]332    return;
333
334  doRemoveEntity(uniqueID);
[6067]335}
336
337/*!
338 * Checks whether it is possible to create an entity of a given class
339 * @return: true if the entity can be created, false otherwise
340 */
[6214]341bool NetworkGameManager::canCreateEntity(ClassID classID)
[6067]342{
[6190]343  return true;
[6067]344}
[6190]345
346/*!
347 * Sends the Entities to the new connected client
348 * @param userID: The ID of the user
349 */
350void NetworkGameManager::sendEntityList( int userID )
351{
[6214]352  if ( !isServer() )
353    return;
354
[6273]355  if ( userID >= outBuffer.size() )
[6214]356    resizeBufferVector( userID );
357
358  SynchronizeableList::const_iterator it, e;
359
360  it = this->networkStream->getSyncBegin();
361  e = this->networkStream->getSyncEnd();
362
[6231]363  if ( !writeToClientBuffer( outBuffer[userID], (byte)CREATE_ENTITY_LIST ) )
[6214]364    return;
365
[6257]366  // -2 because you must not send network_game_manager and handshake
367  if ( !writeToClientBuffer( outBuffer[userID], networkStream->getSyncCount()-2 ) )
[6214]368    return;
369
[6273]370  //PRINTF(0)("SendEntityList: n = %d\n", networkStream->getSyncCount()-2 );
[6256]371
[6214]372  while ( it != e )
373  {
[6257]374    if ( (*it)->getRealClassID() != CL_NETWORK_GAME_MANAGER && (*it)->getRealClassID() != CL_HANDSHAKE )
375    {
[6214]376
[6257]377      if ( !writeToClientBuffer( outBuffer[userID], (*it)->getRealClassID() ) )
378        return;
[6256]379
[6273]380      //PRINTF(0)("SendEntityList: ClassID = %x\n", (*it)->getRealClassID());
[6214]381
[6257]382      if ( !writeToClientBuffer( outBuffer[userID], (*it)->getUniqueID() ) )
383        return;
[6214]384
[6257]385      if ( !writeToClientBuffer( outBuffer[userID], (*it)->getOwner() ) )
386        return;
387    }
388
[6214]389    it++;
390  }
[6190]391}
392
393/**
394 * Creates a buffer for user n
395 * @param n The ID of the user
396 */
397void NetworkGameManager::resizeBufferVector( int n )
398{
[6214]399  for ( int i = outBuffer.size(); i<=n; i++)
[6190]400  {
401    clientBuffer outBuf;
402
403    outBuf.length = 0;
404
405    outBuf.maxLength = 5*1024;
406
407    outBuf.buffer = new byte[5*1014];
408
409    outBuffer.push_back(outBuf);
410  }
411}
412
413/**
414 * Creates the entity on this host
415 * @param classID: ClassID of the entity to create
416 * @param uniqueID: Unique ID to assign to the synchronizeable
417 * @param owner: owner of this synchronizealbe
418 */
419void NetworkGameManager::doCreateEntity( ClassID classID, int uniqueID, int owner )
420{
[6214]421  BaseObject * b = Factory::fabricate( classID );
[6190]422
[6214]423  if ( !b )
424  {
[6256]425    PRINTF(1)("Could not fabricate Object with classID %x\n", classID);
[6214]426    return;
427  }
[6256]428  else
429  {
[6273]430    //PRINTF(0)("Fabricated entity: %s\n", b->getClassName());
[6256]431  }
[6214]432
[6190]433  if ( b->isA(CL_SYNCHRONIZEABLE) )
434  {
435    Synchronizeable * s = dynamic_cast<Synchronizeable*>(b);
436    s->setUniqueID( uniqueID );
437    s->setOwner( owner );
438    this->networkStream->connectSynchronizeable( *s );
[6273]439    if ( !isServer() )
440      s->setIsOutOfSync( true );
[6190]441  }
442  else
443  {
[6256]444    PRINTF(1)("Class with ID %x is not a synchronizeable!", (int)classID);
[6190]445    delete b;
446  }
447}
448
449/**
450 * Removes a entity on this host
451 * @param uniqueID: unique ID assigned with the entity to remove
452 */
453void NetworkGameManager::doRemoveEntity( int uniqueID )
454{
455  SynchronizeableList::const_iterator it,e;
456  it = this->networkStream->getSyncBegin();
457  e = this->networkStream->getSyncEnd();
458
459  while ( it != e )
460  {
461    if ( (*it)->getUniqueID() == uniqueID )
462    {
463      delete *it;
464      break;
465    }
[6214]466    it++;
[6190]467  }
468}
469
470/**
471 * Tell the synchronizeable that a user's synchronizeable is out of sync
472 * @param uniqueID: unique ID assigned with the entity which is out of sync
473 * @param userID: user ID who's synchronizeable is out of sync
474 */
475void NetworkGameManager::doRequestSync( int uniqueID, int userID )
476{
477  SynchronizeableList::const_iterator it,e;
478  it = this->networkStream->getSyncBegin();
479  e = this->networkStream->getSyncEnd();
480
481  while ( it != e )
482  {
483    if ( (*it)->getUniqueID() == uniqueID )
484    {
485      (*it)->requestSync( userID );
486      break;
487    }
[6214]488    it++;
[6190]489  }
490}
[6214]491
492/**
493 * Copies length bytes to the clientBuffer with error checking
494 * @param clientBuffer: the clientBuffer to write to
495 * @param data: buffer to the data
496 * @param length: length of data
497 * @return false on error true else
498 */
499bool NetworkGameManager::writeToClientBuffer( clientBuffer &cb, byte * data, int length )
500{
501  if ( length > cb.maxLength-cb.length )
502  {
503    PRINTF(1)("No space left in clientBuffer\n");
504    return false;
505  }
506
507  memcpy( cb.buffer+cb.length, data, length );
508  return true;
509}
510
511/**
512 * Reads data from clientBuffer with error checking
513 * @param clientBuffer: the clientBuffer to read from
514 * @param data: pointer to the buffer
515 * @param length:
516 * @return
517 */
518bool NetworkGameManager::readFromClientBuffer( clientBuffer &cb, byte * data, int length )
519{
520  if ( cb.length < length )
521  {
522    PRINTF(0)("There is not enough data in clientBuffer\n");
523    return 0;
524  }
525
526  memcpy( data, cb.buffer+cb.length-length, length );
527  return true;
528}
529
530/**
531 * Tells this client that he has to control this entity
532 * @param uniqueID: the entity's uniqeID
533 */
534void NetworkGameManager::doYouAre( int uniqueID )
535{
536  //TODO: what has to be done
537}
538
539/**
540 * Tells a remote client that he has to control this entity
541 * @param uniqueID: the entity's uniqeID
542 * @param userID: the users ID
543 */
544void NetworkGameManager::sendYouAre( int uniqueID, int userID )
545{
546  if ( !isServer() )
547    return;
548
549  if ( userID != 0 )
550  {
[6231]551    if ( !writeToClientBuffer( outBuffer[userID], (byte)YOU_ARE_ENTITY ) )
[6214]552      return;
553
[6231]554    if ( !writeToClientBuffer( outBuffer[userID], uniqueID ) )
[6214]555      return;
556  }
557  else
558  {
559    doYouAre(uniqueID);
560  }
561}
562
[6219]563bool NetworkGameManager::handleRequestCreate( int & i, const byte * data, int length, int sender )
564{
565  if ( INTSIZE > length-i )
566  {
567    PRINTF(1)("Cannot read classID from buffer! Not enough data left!\n");
568    return false;
569  }
[6231]570  int classID;
[6256]571  i += Converter::byteArrayToInt( &data[i], &classID );
[6219]572
573  createEntity( (ClassID)classID );
574
575  return true;
576}
577
578bool NetworkGameManager::handleRequestRemove( int & i, const byte * data, int length, int sender )
579{
580  if ( INTSIZE > length-i )
581  {
582    PRINTF(1)("Cannot read uniqueID from buffer! Not enough data left!\n");
583    return false;
584  }
[6231]585  int uniqueID;
[6256]586  i += Converter::byteArrayToInt( &data[i], &uniqueID );
[6219]587
588  removeEntity( uniqueID );
589
590  return true;
591}
592
593bool NetworkGameManager::handleCreateEntity( int & i, const byte * data, int length, int sender )
594{
595  if ( INTSIZE > length-i )
596  {
597    PRINTF(1)("Cannot read classID from buffer! Not enough data left!\n");
598    return false;
599  }
[6231]600  int classID;
[6256]601  i += Converter::byteArrayToInt( &data[i], &classID );
[6219]602
603  if ( INTSIZE > length-i )
604  {
605    PRINTF(1)("Cannot read uniqueID from buffer! Not enough data left!\n");
606    return false;
607  }
[6231]608  int uniqueID;
[6256]609  i += Converter::byteArrayToInt( &data[i], &uniqueID );
[6219]610
611  if ( INTSIZE > length-i )
612  {
613    PRINTF(1)("Cannot read owner from buffer! Not enough data left!\n");
614    return false;
615  }
[6231]616  int owner;
[6256]617  i += Converter::byteArrayToInt( &data[i], &owner );
[6219]618
619  doCreateEntity( (ClassID)classID, uniqueID, owner );
620
621  return true;
622}
623
624bool NetworkGameManager::handleRemoveEntity( int & i, const byte * data, int length, int sender )
625{
626  if ( INTSIZE > length-i )
627  {
628    PRINTF(1)("Cannot read uniqueID from buffer! Not enough data left!\n");
629    return false;
630  }
[6231]631  int uniqueID;
[6256]632  i += Converter::byteArrayToInt( &data[i], &uniqueID );
[6219]633
634  doRemoveEntity( uniqueID );
635
636  return true;
637}
638
639bool NetworkGameManager::handleCreateEntityList( int & i, const byte * data, int length, int sender )
640{
641  if ( INTSIZE > length-i )
642  {
643    PRINTF(1)("Cannot read n from buffer! Not enough data left!\n");
644    return false;
645  }
[6256]646
647  PRINTF(0)("HandleCreateEntityList:  data[i..i+3] = %d %d %d %d\n", data[i], data[i+1], data[i+2], data[i+3]);
648
[6231]649  int n;
[6256]650  i += Converter::byteArrayToInt( &data[i], &n );
[6219]651
[6256]652
653  PRINTF(0)("HandleCreateEntityList: n = %d\n", n);
654
[6219]655  int classID, uniqueID, owner;
656
657  for ( int j = 0; j<n; j++ )
658  {
659
660    if ( INTSIZE > length-i )
661    {
662      PRINTF(1)("Cannot read classID from buffer! Not enough data left!\n");
663      return false;
664    }
[6256]665    i += Converter::byteArrayToInt( &data[i], &classID );
[6219]666
667    if ( INTSIZE > length-i )
668    {
669      PRINTF(1)("Cannot read uniqueID from buffer! Not enough data left!\n");
670      return false;
671    }
[6256]672    i += Converter::byteArrayToInt( &data[i], &uniqueID );
[6219]673
674    if ( INTSIZE > length-i )
675    {
676      PRINTF(1)("Cannot read owner from buffer! Not enough data left!\n");
677      return false;
678    }
[6256]679    i += Converter::byteArrayToInt( &data[i], &owner );
[6219]680
681    doCreateEntity( (ClassID)classID, uniqueID, owner );
682
683  }
684  return true;
685}
686
687bool NetworkGameManager::handleRemoveEntityList( int & i, const byte * data, int length, int sender )
688{
689  if ( INTSIZE > length-i )
690  {
691    PRINTF(1)("Cannot read n from buffer! Not enough data left!\n");
692    return false;
693  }
[6231]694  int n;
[6256]695  i += Converter::byteArrayToInt( &data[i], &n );
[6219]696
697  int uniqueID;
698
699  for ( int j = 0; j<n; j++ )
700  {
701
702    if ( INTSIZE > length-i )
703    {
704      PRINTF(1)("Cannot read uniqueID from buffer! Not enough data left!\n");
705      return false;
706    }
[6256]707    i += Converter::byteArrayToInt( &data[i], &uniqueID );
[6219]708
709    doRemoveEntity( uniqueID );
710  }
711
712  return true;
713}
714
715bool NetworkGameManager::handleYouAreEntity( int & i, const byte * data, int length, int sender )
716{
717  if ( INTSIZE > length-i )
718  {
719    PRINTF(1)("Cannot read uniqueID from buffer! Not enough data left!\n");
720    return false;
721  }
722
[6231]723  int uniqueID;
[6256]724  i += Converter::byteArrayToInt( &data[i], &uniqueID );
[6231]725
[6219]726  doYouAre( uniqueID );
727
728  return true;
729}
730
731bool NetworkGameManager::handleRequestSync( int & i, const byte * data, int length, int sender )
732{
733  if ( INTSIZE > length-i )
734  {
735    PRINTF(1)("Cannot read uniqueID from buffer! Not enough data left!\n");
736    return false;
737  }
[6231]738  int uniqueID;
[6256]739  i += Converter::byteArrayToInt( &data[i], &uniqueID );
[6219]740
741  doRequestSync( uniqueID, sender );
742
743  return true;
744}
745
[6231]746bool NetworkGameManager::writeToClientBuffer( clientBuffer & cb, byte b )
747{
748  if ( cb.maxLength-cb.length < 1 )
749  {
750    PRINTF(1)("Cannot write to clientBuffer! Not enough space for 1 byte\n");
751    return false;
752  }
753
754  cb.buffer[cb.length++] = b;
755
756  return true;
757}
758
759bool NetworkGameManager::writeToClientBuffer( clientBuffer & cb, int i )
760{
[6256]761  int n = Converter::intToByteArray( i, cb.buffer+cb.length, cb.maxLength-cb.length );
[6231]762  cb.length += n;
763
764  if ( n <= 0 )
765  {
766    PRINTF(1)("Cannot write to clientBuffer! Not enough space for 1 int\n");
767    return false;
768  }
769
770  return true;
771}
772
[6273]773void NetworkGameManager::sync( int uniqueID, int owner )
774{
775  if ( owner==this->getHostID() )
776    return;
777
778  if ( !isServer() )
779    executeRequestSync( uniqueID, 0 );
780  else
781    executeRequestSync( uniqueID, owner );
782}
783
784void NetworkGameManager::executeRequestSync( int uniqueID, int user )
785{
786  if ( user >= outBuffer.size() )
787    resizeBufferVector( user );
788
789  if ( !writeToClientBuffer( outBuffer[user], (byte)REQUEST_SYNC ) )
790    return;
791  if ( !writeToClientBuffer( outBuffer[user], uniqueID ) )
792    return;
793}
794
Note: See TracBrowser for help on using the repository browser.