Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

space_ship: tried to implement control synchronization
entities will not be spawned at (0,0,0) anymore

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