00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifndef ArmageTron_NET_H
00029 #define ArmageTron_NET_H
00030
00031 #include "tError.h"
00032 #include "tString.h"
00033 #include "tHeap.h"
00034 #include "tLinkedList.h"
00035 #include "tCallback.h"
00036 #include "nObserver.h"
00037
00038 #include "tException.h"
00039 #include <memory>
00040
00041 class nSocket;
00042 class nAddress;
00043 class nBasicNetworkSystem;
00044 class nServerInfoBase;
00045
00046 extern nBasicNetworkSystem sn_BasicNetworkSystem;
00047
00048 class nMessage;
00049 class tCrypt;
00050 class tOutput;
00051
00052 typedef double nTimeAbsolute;
00053 typedef double nTimeRolling;
00054
00055 extern tString sn_bigBrotherString;
00056
00057
00058 extern tString sn_programVersion;
00059
00060 extern tString sn_serverName;
00061
00062 extern unsigned int sn_serverPort;
00063 extern const unsigned int sn_defaultPort;
00064
00065 extern int sn_defaultDelay;
00066
00067 extern tString sn_DenyReason;
00068
00069
00070 extern int sn_maxRateIn,sn_maxRateOut;
00071
00075 class nKillHim: public tException
00076 {
00077 public:
00078 nKillHim();
00079 ~nKillHim();
00080
00081 private:
00082 virtual tString DoGetName() const;
00083 virtual tString DoGetDescription() const;
00084 };
00085
00088 class nIgnore: public nKillHim
00089 {
00090 public:
00091 nIgnore();
00092 ~nIgnore();
00093
00094 private:
00095 virtual tString DoGetName() const;
00096 virtual tString DoGetDescription() const;
00097 };
00098
00099
00100 void nReadError( bool critical = true );
00101
00102 #ifndef MAXCLIENTS
00103 #define MAXCLIENTS 16
00104 #endif
00105
00106
00107 typedef enum {nSTANDALONE,nSERVER,nCLIENT} nNetState;
00108 typedef enum {nOK, nTIMEOUT, nDENIED, nABORT} nConnectError;
00109
00110
00111
00112 nConnectError sn_GetLastError();
00113 nNetState sn_GetNetState();
00114 void sn_SetNetState(nNetState x);
00115 void sn_DisconnectUser(int i, const tOutput& reason, nServerInfoBase * redirectTo = 0 );
00116 void sn_KickUser(int i, const tOutput& reason, REAL severity = 1, nServerInfoBase * redirectTo = 0 );
00117
00118 void sn_GetAdr(int user, tString& name);
00119 unsigned int sn_GetPort(int user);
00120 unsigned int sn_GetServerPort();
00121 int sn_NumUsers();
00122 int sn_MaxUsers();
00123 int sn_MessagesPending(int user);
00124
00125
00126 class nVersion
00127 {
00128 public:
00129 nVersion();
00130 nVersion( int min, int max );
00131 bool Supported( int version ) const;
00132 bool Merge( const nVersion& a,
00133 const nVersion& b);
00134
00135 int Min() const {
00136 return min_;
00137 }
00138 int Max() const {
00139 return max_;
00140 }
00141
00142 bool operator != ( const nVersion& other ){
00143 return !operator==(other);
00144 }
00145 bool operator == ( const nVersion& other );
00146 nVersion& operator = ( const nVersion& other );
00147 private:
00148 int min_, max_;
00149 };
00150
00151 nMessage& operator >> ( nMessage& m, nVersion& ver );
00152 nMessage& operator << ( nMessage& m, const nVersion& ver );
00153
00154 std::istream& operator >> ( std::istream& s, nVersion& ver );
00155 std::ostream& operator << ( std::ostream& s, const nVersion& ver );
00156
00157 const nVersion& sn_MyVersion();
00158 const nVersion& sn_CurrentVersion();
00159 void sn_UpdateCurrentVersion();
00160
00161
00162 class nVersionFeature
00163 {
00164 public:
00165 nVersionFeature( int min, int max = -1 );
00166 bool Supported();
00167 bool Supported( int client );
00168 private:
00169 int min_, max_;
00170 };
00171
00172 class nBandwidthControl;
00173
00174
00175 class nSendBuffer
00176 {
00177 public:
00178 int Len () const {
00179 return sendBuffer_.Len();
00180 }
00181
00182 void AddMessage ( nMessage& message
00183 , nBandwidthControl* control );
00184 void Send ( nSocket const & socket
00185 , const nAddress & peer
00186 , nBandwidthControl* control );
00187 void Broadcast ( nSocket const & socket
00188 , int port
00189 , nBandwidthControl* control );
00190
00191 void Clear();
00192
00193 private:
00194 tArray<unsigned short> sendBuffer_;
00195 };
00196
00197 class nBandwidthControl
00198 {
00199 public:
00200 enum Usage
00201 {
00202 Usage_Planning,
00203 Usage_Execution
00204 };
00205
00206 nBandwidthControl( nBandwidthControl* parent = NULL );
00207 ~nBandwidthControl();
00208 void Reset();
00209
00210 void SetRate( unsigned short rate ){
00211 rate_ = rate;
00212 }
00213 unsigned short Rate() {
00214 return rate_;
00215 }
00216
00217 REAL Control( Usage planned ){
00218 return Usage_Planning == planned ? rateControlPlanned_ : rateControl_;
00219 }
00220 void Use( Usage planned, REAL bandwidth );
00221
00222 bool CanSend(){
00223 return rateControlPlanned_ > 0;
00224 }
00225 REAL Score(){
00226 return rateControlPlanned_ / rate_;
00227 }
00228
00229 void Update( REAL ts);
00230 private:
00231 REAL rateControlPlanned_;
00232 REAL rateControl_;
00233 unsigned short rate_;
00234 nBandwidthControl* parent_;
00235 #ifdef DEBUG
00236 int numChildren_;
00237 #endif
00238 };
00239
00241 class nAverager
00242 {
00243 public:
00244 nAverager();
00245 ~nAverager();
00246 REAL GetAverage() const;
00247 REAL GetDataVariance() const;
00248 REAL GetAverageVariance() const;
00249 void Timestep( REAL decay );
00250 void Add( REAL value, REAL weight=1 );
00251 void Reset();
00252
00253 std::istream & operator << ( std::istream & stream );
00254 std::ostream & operator >> ( std::ostream & stream ) const;
00255 private:
00256 REAL weight_;
00257 REAL sum_;
00258 REAL sumSquared_;
00259 REAL weightSquared_;
00260 };
00261
00263 std::istream & operator >> ( std::istream & stream, nAverager & averager );
00264
00266 std::ostream & operator << ( std::ostream & stream, nAverager const & averager );
00267
00269 class nPingAverager
00270 {
00271 public:
00272 nPingAverager();
00273 ~nPingAverager();
00274
00275 operator REAL() const;
00276
00277 REAL GetPing() const;
00278 REAL GetPingSnail() const;
00279 REAL GetPingSlow() const;
00280 REAL GetPingFast() const;
00281 bool IsSpiking() const ;
00282 void Timestep( REAL decay );
00283 void Add( REAL value, REAL weight );
00284 void Add( REAL value );
00285 void Reset();
00286 private:
00287 nAverager snail_;
00288 nAverager slow_;
00289 nAverager fast_;
00290 static REAL weight_;
00291 public:
00292
00293 inline static void SetWeight( REAL const & weight );
00294 inline static REAL GetWeight( void );
00295 inline static void GetWeight( REAL & weight );
00296 inline nAverager const & GetSnailAverager( void ) const;
00297 inline nPingAverager const & GetSnailAverager( nAverager & snail ) const;
00298 inline nAverager const & GetSlowAverager( void ) const;
00299 inline nPingAverager const & GetSlowAverager( nAverager & slow ) const;
00300 inline nAverager const & GetFastAverager( void ) const;
00301 inline nPingAverager const & GetFastAverager( nAverager & fast ) const;
00302 protected:
00303 inline nPingAverager & SetSnailAverager( nAverager const & snail );
00304 inline nPingAverager & SetSlowAverager( nAverager const & slow );
00305 inline nPingAverager & SetFastAverager( nAverager const & fast );
00306 };
00307
00308 struct nConnectionInfo
00309 {
00310 nSocket const * socket;
00311 int ackPending;
00312
00313 nPingAverager ping;
00314
00315
00316
00317
00318 nBandwidthControl bandwidthControl_;
00319
00320
00321 nSendBuffer sendBuffer_;
00322
00323
00324 nVersion version;
00325
00326
00327 tJUST_CONTROLLED_PTR< nMessage > ackMess;
00328
00329
00330
00331
00332
00333 tString supportedAuthenticationMethods_;
00334
00335 nConnectionInfo();
00336 ~nConnectionInfo();
00337
00338 void Clear();
00339 void Timestep( REAL dt );
00340
00341 void ReliableMessageSent();
00342 void AckReceived();
00343 REAL PacketLoss() const;
00344 private:
00345
00346 nAverager packetLoss_;
00347
00348 };
00349
00350 extern nConnectionInfo sn_Connections[MAXCLIENTS+2];
00351
00352 extern int sn_maxNoAck;
00353
00354
00355
00356
00357
00358 enum nLoginType
00359 {
00360 Login_Pre0252,
00361 Login_Post0252,
00362 Login_All
00363 };
00364
00365
00366 nConnectError sn_Connect(nAddress const & server, nLoginType loginType = Login_All, nSocket const * socket = NULL );
00367
00368
00369 void sn_Bend( nAddress const & server );
00370 void sn_Bend( tString const & server, unsigned int port );
00371
00372 extern int sn_myNetID;
00373
00374
00375
00376
00377 class nMessage;
00378 typedef void nHandler(nMessage &m);
00379
00380
00381
00382 class nDescriptor:public tListItem<nDescriptor>{
00383 friend class nMessage;
00384
00385 static unsigned short s_nextID;
00386
00387 unsigned short id;
00388 nHandler *handler;
00389
00390 const char *name;
00391
00392 const bool acceptWithoutLogin;
00393 public:
00394 nDescriptor(unsigned short identification,nHandler *handle
00395 ,const char *name, bool acceptEvenIfNotLoggedIn = false);
00396
00397
00398 static void HandleMessage(nMessage &message);
00399
00400 unsigned short ID(){
00401 return id;
00402 }
00403 };
00404
00405
00406
00407 void RequestInfoHandler(nHandler *handle);
00408
00409
00410 #define NET_ID_FIRST 100
00411
00412
00413
00414 class nMessage: public tReferencable< nMessage >{
00415
00416 friend class tControlledPTR< nMessage >;
00417 friend class tReferencable< nMessage >;
00418
00419 friend class nDescriptor;
00420 friend class nNetObject;
00421 friend class nWaitForAck;
00422
00423
00424
00425
00426 protected:
00427 unsigned short descriptor;
00428
00429 unsigned long messageIDBig_;
00430 short senderID;
00431 tArray<unsigned short> data;
00432
00433 unsigned int readOut;
00434
00435 ~nMessage();
00436 public:
00437 unsigned short Descriptor() const{
00438 return descriptor;
00439 }
00440
00441 unsigned short SenderID() const{
00442 return senderID;
00443 }
00444
00445 unsigned short MessageID() const{
00446 return messageIDBig_ & 0xFFFF;
00447 }
00448
00449 unsigned long MessageIDBig() const{
00450 return messageIDBig_;
00451 }
00452
00453 unsigned short DataLen() const{
00454 return data.Len();
00455 }
00456
00457 unsigned short Data(unsigned short n){
00458 return data(n);
00459 }
00460
00461 void ClearMessageID(){
00462 messageIDBig_ = 0;
00463 }
00464
00465 nMessage(const nDescriptor &);
00466 nMessage(unsigned short*& buffer, short sn_myNetID, int lenLeft );
00467
00468
00469
00470 void SendImmediately(int peer,bool ack=true);
00471
00472
00473 static void SendCollected(int peer);
00474
00475
00476 static void BroadcastCollected(int peer, unsigned int port);
00477
00478
00479
00480 void BroadCast(bool ack=true);
00481
00482
00483 void Send(int peer,REAL priority=0,bool ack=true);
00484
00485 void Write(const unsigned short &x){
00486 data[data.Len()]=x;
00487 }
00488
00489 nMessage& operator<< (const REAL &x);
00490 nMessage& operator>> (REAL &x);
00491
00492 nMessage& operator<< (const unsigned short &x){
00493 Write(x);
00494 return *this;
00495 }
00496 nMessage& operator>> (unsigned short &x){
00497 Read(x);
00498 return *this;
00499 }
00500
00501 nMessage& operator<< (const double &x){
00502 return operator<<(REAL(x));
00503 }
00504
00505 nMessage& operator>> (double &x){
00506 REAL y;
00507 operator>>(y);
00508 x=y;
00509
00510 return *this;
00511 }
00512
00513
00514 nMessage& ReadRaw(tString &s);
00515
00516 nMessage& operator >> (tString &s);
00517 nMessage& operator >> (tColoredString &s);
00518 nMessage& operator << (const tString &s);
00519 nMessage& operator << (const tColoredString &s);
00520 nMessage& operator << (const tOutput &o);
00521
00522 template<class T> void BinWrite (const T &x){
00523 for (unsigned int i=0;i<sizeof(T)/2;i++)
00524 Write((reinterpret_cast<const unsigned short *>(&x))[i]);
00525 return *this;
00526 }
00527
00528 bool End(){
00529 return readOut>=static_cast<unsigned int>(data.Len());
00530 }
00531
00532 void Reset(){
00533 readOut=0;
00534 }
00535
00536 int ReadSoFar(){
00537 return readOut;
00538 }
00539
00540 void Read(unsigned short &x);
00541
00542 template<class T> void BinRead (const T &x){
00543 for (unsigned int i=0;i<sizeof(T)/2;i++)
00544 Read(reinterpret_cast<unsigned short *>(&x)[i]);
00545 return *this;
00546 }
00547
00548
00549 nMessage& operator<< (const short &x);
00550 nMessage& operator>> (short &x);
00551
00552 nMessage& operator<< (const int &x);
00553 nMessage& operator>> (int &x);
00554
00555 nMessage& operator<< (const unsigned int &x){
00556 operator<<(reinterpret_cast<const int&>(x));
00557 return *this;
00558 }
00559 nMessage& operator>> (unsigned int &x){
00560 operator>>(reinterpret_cast<int&>(x));
00561 return *this;
00562 }
00563
00564 nMessage& operator<< (const bool &x);
00565 nMessage& operator>> (bool &x);
00566
00567 template <class T> nMessage& operator<<(const tArray<T>& a)
00568 {
00569 unsigned short len = a.Len();
00570 Write(len);
00571 for (int i=a.Len()-1; i>=0; i--)
00572 operator<< (a(i));
00573
00574 return *this;
00575 }
00576
00577 template <class T> nMessage& operator>>(tArray<T>& a)
00578 {
00579 unsigned short len;
00580 Read(len);
00581 a.SetLen(len);
00582 for (int i=a.Len()-1; i>=0; i--)
00583 operator >> (a(i));
00584
00585 return *this;
00586 }
00587
00588 template<class T> nMessage& operator << (const T* p)
00589 {
00590 if (p)
00591 Write( p->ID() );
00592 else
00593 Write(0);
00594
00595 return *this;
00596 }
00597
00598
00599
00600 template<class T> nMessage& operator << (const tControlledPTR<T> p)
00601 {
00602 if (p)
00603 Write( p->ID() );
00604 else
00605 Write(0);
00606
00607 return *this;
00608 }
00609
00610
00611 };
00612
00613
00614
00615
00616
00617
00618 class nWaitForAck{
00619 protected:
00620 int id;
00621 tCONTROLLED_PTR(nMessage) message;
00622 int receiver;
00623 REAL timeout;
00624 nTimeRolling timeSendAgain;
00625 nTimeRolling timeFirstSent;
00626 nTimeRolling timeLastSent;
00627 int timeouts;
00628
00629 public:
00630 nWaitForAck(nMessage* m,int rec);
00631 virtual ~nWaitForAck();
00632
00633 virtual void AckExtraAction(){};
00634
00635 static void Ackt(unsigned short id,unsigned short peer);
00636
00637 static void AckAllPeer(unsigned short peer);
00638
00639 static void Resend();
00640 };
00641
00642
00644 void sn_Delay();
00645
00646
00647 void sn_Receive();
00648
00649
00650 extern void sn_ReceiveFromControlSocket();
00651
00652
00653 extern void sn_DiscardFromControlSocket();
00654
00655
00656
00657
00658
00659 void sn_Sync(REAL timeout,bool sync_sn_netObjects=false, bool otherEnd=true);
00660
00661
00662 void sn_ConsoleOut(const tOutput &message,int client=-1);
00663 nMessage* sn_ConsoleOutMessage(const tOutput &message);
00664
00665
00666 void sn_CenterMessage(const tOutput &message,int client=-1);
00667
00668
00669
00670
00671
00672 class nCallbackLoginLogout: public tCallback{
00673 static int user;
00674 static bool login;
00675 public:
00676 static int User(){
00677 return user;
00678 }
00679 static int Login(){
00680 return login;
00681 }
00682
00683 nCallbackLoginLogout(AA_VOIDFUNC *f);
00684 static void UserLoggedIn(int user);
00685 static void UserLoggedOut(int user);
00686 };
00687
00688 class nCallbackAcceptPackedWithoutConnection: public tCallbackOr{
00689 static unsigned short descriptor;
00690 public:
00691 static unsigned int Descriptor(){
00692 return descriptor;
00693 }
00694
00695 nCallbackAcceptPackedWithoutConnection(BOOLRETFUNC *f);
00696
00697 static bool Accept( const nMessage& m );
00698 };
00699
00700 class nCallbackReceivedComplete: public tCallback
00701 {
00702 public:
00703 nCallbackReceivedComplete(AA_VOIDFUNC *f);
00704 static void ReceivedComplete();
00705 };
00706
00707 void sn_SendPlanned();
00708 int sn_QueueLen(int user);
00709
00710 void sn_Statistics();
00711
00713 tString const & sn_GetMyAddress();
00714
00716 bool sn_IsLANAddress( tString const & address );
00717
00718
00719 class nCurrentSenderID
00720 {
00721 public:
00722 nCurrentSenderID():lastSenderID_( currentSenderID_ ){}
00723 nCurrentSenderID( int senderID ):lastSenderID_( currentSenderID_ ){
00724 SetID( senderID );
00725 }
00726 ~nCurrentSenderID(){
00727 currentSenderID_ = lastSenderID_;
00728 }
00729
00730 static int GetID(){
00731 return currentSenderID_;
00732 }
00733 void SetID( int senderID ){
00734 currentSenderID_ = senderID;
00735 }
00736 private:
00737 int lastSenderID_;
00738 static int currentSenderID_;
00739 };
00740
00741 class nMachine;
00742
00744 class nMachineDecorator: public tListItem< nMachineDecorator >
00745 {
00746 public:
00747 inline void Destroy();
00748 protected:
00749 virtual void OnDestroy();
00750
00751 nMachineDecorator( nMachine & machine );
00752 virtual ~nMachineDecorator();
00753 private:
00754 nMachineDecorator();
00755 };
00756
00758 class nMachine
00759 {
00760 friend class nMachineDecorator;
00761 friend class nMachinePersistor;
00762 public:
00763 nMachine();
00764 virtual ~nMachine();
00765
00766 bool operator == ( nMachine const & other ) const;
00767 bool operator != ( nMachine const & other ) const;
00768
00769 static nMachine & GetMachine( unsigned short userID );
00770 static void Expire();
00771 static void KickSpectators();
00772
00773
00774 void OnKick( REAL severity = 1 );
00775
00776
00777 void Ban( REAL time );
00778 void Ban( REAL time, tString const & reason );
00779 REAL IsBanned() const;
00780
00781
00782 void AddPlayer();
00783 void RemovePlayer();
00784 int GetPlayerCount();
00785 private:
00786 nMachine( nMachine const & other );
00787 nMachine & operator = ( nMachine const & other );
00788
00789
00790 mutable double lastUsed_;
00791 mutable double banned_;
00792 tString banReason_;
00793 nAverager kph_;
00794 int players_;
00795 REAL lastPlayerAction_;
00796
00797 tString IP_;
00798 nMachineDecorator * decorators_;
00799
00800
00801 public:
00802 REAL GetKicksPerHour( void ) const;
00803 nMachine const & GetKicksPerHour( REAL & kph ) const;
00804 nMachine & SetIP( tString const & IP );
00805 tString const & GetIP( void ) const;
00806 nMachine const & GetIP( tString & IP ) const;
00807 tString const & GetBanReason( void ) const;
00808 nMachine const & GetBanReason( tString & reason )const;
00809 inline nMachineDecorator * GetDecorators( void ) const;
00810 inline nMachine const & GetDecorators( nMachineDecorator * & decorators ) const;
00811
00813 template< class T > static T * GetNextDecorator( nMachineDecorator * run )
00814 {
00815 while ( run )
00816 {
00817 T * ret = dynamic_cast< T * >( run );
00818 if ( ret )
00819 {
00820 return ret;
00821 }
00822 run = run->Next();
00823 }
00824
00825 return 0;
00826 }
00827
00829 template< class T > T * GetDecorator()
00830 {
00831 return GetNextDecorator< T >( GetDecorators() );
00832 }
00833 protected:
00834 private:
00835 inline nMachine & SetDecorators( nMachineDecorator * decorators );
00836 };
00837
00839 class nSocketResetInhibitor
00840 {
00841 public:
00842 nSocketResetInhibitor();
00843 ~nSocketResetInhibitor();
00844 };
00845
00846
00847 std::auto_ptr< nServerInfoBase > sn_GetRedirectTo();
00848
00849
00850 nServerInfoBase * sn_PeekRedirectTo();
00851
00852
00853
00854
00855
00856
00857
00861
00862
00863 REAL nPingAverager::GetWeight( void )
00864 {
00865 return weight_;
00866 }
00867
00868
00869
00870
00871
00872
00876
00877
00878 void nPingAverager::GetWeight( REAL & weight )
00879 {
00880 weight = weight_;
00881 }
00882
00883
00884
00885
00886
00887
00891
00892
00893 void nPingAverager::SetWeight( REAL const & weight )
00894 {
00895 weight_ = weight;
00896 }
00897
00898
00899
00900
00901
00902
00906
00907
00908 nAverager const & nPingAverager::GetSnailAverager( void ) const
00909 {
00910 return this->snail_;
00911 }
00912
00913
00914
00915
00916
00917
00922
00923
00924 nPingAverager const & nPingAverager::GetSnailAverager( nAverager & snail ) const
00925 {
00926 snail = this->snail_;
00927 return *this;
00928 }
00929
00930
00931
00932
00933
00934
00939
00940
00941 nPingAverager & nPingAverager::SetSnailAverager( nAverager const & snail )
00942 {
00943 this->snail_ = snail;
00944 return *this;
00945 }
00946
00947
00948
00949
00950
00954
00955
00956 nAverager const & nPingAverager::GetSlowAverager( void ) const
00957 {
00958 return this->slow_;
00959 }
00960
00961
00962
00963
00964
00965
00970
00971
00972 nPingAverager const & nPingAverager::GetSlowAverager( nAverager & slow ) const
00973 {
00974 slow = this->slow_;
00975 return *this;
00976 }
00977
00978
00979
00980
00981
00982
00987
00988
00989 nPingAverager & nPingAverager::SetSlowAverager( nAverager const & slow )
00990 {
00991 this->slow_ = slow;
00992 return *this;
00993 }
00994
00995
00996
00997
00998
00999
01003
01004
01005 nAverager const & nPingAverager::GetFastAverager( void ) const
01006 {
01007 return this->fast_;
01008 }
01009
01010
01011
01012
01013
01014
01019
01020
01021 nPingAverager const & nPingAverager::GetFastAverager( nAverager & fast ) const
01022 {
01023 fast = this->fast_;
01024 return *this;
01025 }
01026
01027
01028
01029
01030
01031
01036
01037
01038 nPingAverager & nPingAverager::SetFastAverager( nAverager const & fast )
01039 {
01040 this->fast_ = fast;
01041 return *this;
01042 }
01043
01044
01045
01046
01047
01048
01051
01052
01053 void nMachineDecorator::Destroy( void )
01054 {
01055 this->OnDestroy();
01056 }
01057
01058
01059
01060
01061
01062
01066
01067
01068 nMachineDecorator * nMachine::GetDecorators( void ) const
01069 {
01070 return this->decorators_;
01071 }
01072
01073
01074
01075
01076
01077
01082
01083
01084 nMachine const & nMachine::GetDecorators( nMachineDecorator * & decorators ) const
01085 {
01086 decorators = this->decorators_;
01087 return *this;
01088 }
01089
01090
01091
01092
01093
01094
01099
01100
01101 nMachine & nMachine::SetDecorators( nMachineDecorator * decorators )
01102 {
01103 this->decorators_ = decorators;
01104 return *this;
01105 }
01106
01107 #endif
01108
01109
01110
01111